为MySQL服务器配置复制非常简单。但由于场景不同,基本的步骤还是有所差异。最基本的场景是新安装的主库和备库,总的来说分为以下几步∶
1. 配置复制
为MySQL服务器配置复制非常简单。但由于场景不同,基本的步骤还是有所差异。最基本的场景是新安装的主库和备库,总的来说分为以下几步:
-
- 在每台服务器上创建复制账号。
-
- 配置主库和备库。
-
- 通知备库连接到主库并从主库复制数据。
这里我们假定大部分配置采用默认值即可,在主库和备库都是全新安装并且拥有同样的数据(默认MySQL数据库)时这样的假设是合理的。接下来我们将展示如何一步步配置复制:假设有服务器 serverl(IP地址192.168.0.1)和服务器server2(IP地址192.168.0.2),我们将解释如何给一个已经运行的服务器配置备库,并探讨推荐的复制配置。
1.1 创建复制账号
MySQL会赋予一些特殊的权限给复制线程。在备库运行的I/O线程会建立一个到主库的TCP/IP连接,这意味着必须在主库创建一个用户,并赋予其合适的权限。备库I/O线程以该用户名连接到主库并读取其二进制日志。通过如下语句创建用户账号:
mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO repl@'192.168.0.%' IDENTIFIED BY 'p4ssword',;
我们在主库和备库都创建该账号。注意我们把这个账户限制在本地网络,因为这是一个特权账号(尽管该账号无法执行 select或修改数据,但仍然能从二进制日志中获得一些数据)。
复制账户事实上只需要有主库上的REPLICATION SLAVE权限,并不一定需要每一端服务器都有REPLICATION CLIENT权限,那为什么我们要把这两种权限给主/备库都赋予呢这有两个原因
- 用来监控和管理复制的账号需要REPLICATION CLIENT权限,并且针对这两种目的使用同一个账号更加容易(而不是为某个目的单独创建一个账号)。
- 如果在主库上建立了账号,然后从主库将数据克隆到备库上时,备库也就设置好了————变成主库所需要的配置。这样后续有需要可以方便地交换主备库的角色。
1.2 配置主库和备库
下一步需要在主库上开启一些设置,假设主库是服务器serverl,需要打开二进制日志并指定一个独一无二的服务器ID(server ID),在主库的my.cnf文件中增加或修改如下内容
log_bin = mysql-bin
server_id = 10
实际取值由你决定,这里只是为了简单起见,当然也可以设置更多需要的配置。
必须明确地指定一个唯一的服务器ID,默认服务器ID通常为1(这和版本相关,一些MySQL版本根本不允许使用这个值)。使用默认值可能会导致和其他服务器的ID冲突,因此这里我们选择10来作为服务器ID。一种通用的做法是使用服务器IP地址的末8位,但要保证它是不变且唯一的(例如,服务器都在一个子网里)。最好选择一些有意义的约定并遵循。
如果之前没有在MySQL的配置文件中指定log-bin选项,就需要重新启动MySQL。为了确认二进制日志文件是否已经在主库上创建,使用 SHOW MASTER STATUS命令,检查输出是否与如下的一致。MySQL会为文件名增加一些数字,所以这里看到的文件名和你定义的会有点不一样。
备库上也需要在my.cnf中增加类似的配置,并且同样需要重启服务器。
log_bin=mysql-bin
server id=2
relay_log=/var/lib/mysql/mysql-relay-bin
log_slave_updates=1
read_only=1
从技术上来说,这些选项并不总是必要的。其中一些选项我们只是显式地列出了默认值。事实上只有server_id是必需的。这里我们同样也使用了log_bin,并赋予了一个明确的名字。默认情况下,它是根据机器名来命名的,但如果机器名变化了可能会导致问题。为了简便起见,我们将主库和备库上的Log-bin设置为相同的值。当然如果你愿意的话,也可以设置成别的值。
另外我们还增加了两个配置选项:relay_log(指定中继日志的位置和命名)和log_slave_updates(允许备库将其重放的事件也记录到自身的二进制日志中),后一个选项会给备库增加额外的工作,但正如后面将会看到的,我们有理由为每个备库设置该选项。
有时候只开启了二进制日志,但却没有开启log_slave_updates,可能会碰到一些奇怪的现象,例如,当配置错误时可能会导致备库数据被修改。如果可能的话,最好使用read_only配置选项,该选项会阻止任何没有特权权限的线程修改数据(所以最好不要给予用户超出需要的权限)。但read_only选项常常不是很实用,特别是对于那些需要在备库建表的应用。
注意:不要在配置文件my.cnf中设置master_port或master_host 这些选项,这是老的配置方式,已经被废弃,它只会导致问题,不会有任何好处。
1.3 启动复制
下一步是告诉备库如何连接到主库并重放其二进制日志。这一步不要通过修改my.cnf来配置,而是使用CHANGE MASTER TO语句,该语句完全替代了my.cnf中相应的设置,并且允许以后指向别的主库时无须重启备库。下面是开始复制的基本命令:
mysql> CHANGE MASTER TO MASTER_HOST='server1',
-> MASTER_USER='repl',
-> MASTER_PASSWORD='p4ssword',
-> MASTER_LOG_FILE='mysql-bin.000001',
-> MASTER_LOG_POS=0;
MASTER_LOG_POS参数被设置为0,因为要从日志的开头读起。当执行完这条语句后,可以通过SHOW SLAVE STATUS 语句来检查复制是否正确执行。
Slave_IO_State、Slave_IO_Running和Slave_SQL_Running这三列显示当前备库复制尚未运行。细心的同学可能已经注意到日志的开头是4而不是0,这是因为0其实不是日志真正开始的位置,它仅仅意味着 “在日志文件头”,MySQL知道第一个事件从文件的第4位开始读。
运行下面的命令开始复制:
mysql>START SLAVE;
执行该命令没有显示错误,现在我们再用SHOW SLAVE STATUS命令检查∶
从输出可以看出I/O线程和SQL线程都已经开始运行,Seconds_Behind_Master的值也不再为NULL(稍后再解释Seconds_Behind_Master的含义)。I/O线程正在等待从主库传递过来的事件,这意味着I/O线程已经读取了主库所有的事件。日志位置发生了变化,表明已经从主库获取和执行了一些事件(你的结果可能会有所不同)。如果在主库上做一些数据更新,就会看到备库的文件或者日志位置都可能会增加。备库中的数据同样会随之更新。
我们还可以从线程列表中看到复制线程。在主库上可以看到由备库I/O线程向主库发起的连接。
同样,在备库也可以看到两个线程,一个是I/O线程,一个是SQL线程∶
这些简单的输出来自一台已经运行了一段时间的服务器,所以I/O线程在主库和备库上的Time列的值较大。SQL线程在备库已经空闲了33秒。这意味着33秒内没有重放任何事件。
这些线程总是运行在“system user”账号下,其他列的值则不相同。例如,当SQL线程回放事件时,Info列可能显示正在执行的查询。
1.4 从另一个服务器开始复制
前面的设置都是假定主备库均为刚刚安装好且都是默认的数据,也就是说两台服务器上数据相同,并且知道当前主库的二进制日志。这不是典型的案例。大多数情况下有一个已经运行了一段时间的主库,然后用一台新安装的备库与之同步,此时这台备库还没有数据。
有几种办法来初始化备库或者从其他服务器克隆数据到备库。包括从主库复制数据、从另外一台备库克隆数据,以及使用最近的一次备份来启动备库,需要有三个条件来让主库和备库保持同步:
- 在某个时间点的主库的数据快照。
- 主库当前的二进制日志文件,和获得数据快照时在该二进制日志文件中的偏移量,我们把这两个值称为日志文件坐标(logfile coordinates)。通过这两个值可以确定二进制日志的位置。可以通过 SHOW MASTER STATUS命令来获取这些值。
- 从快照时间到现在的二进制日志。
下面是一些从别的服务器克隆备库的方法:
- 使用冷备份。
重启主库后,会使用一个新的二进制日志文件,我们在备库通过执行CHANGE MASTER TO指向这个文件的起始处。这个方法的缺点很明显:在复制数据时需要关闭主库。
- 使用热备份
如果仅使用了MyISAM表,可以在主库运行时使用mysqlhotcopy或rsync来复制数据,更多细节参阅第15章。使用mysqldump
如果只包含InnoDB表,那么可以使用以下命令来转储主库数据并将其加载到备库,然后设置相应的二进制日志坐标:
选项–single-transaction使得转储的数据为事务开始前的数据。如果使用的是非事务型表,可以使用–lock-all-tables选项来获得所有表的一致性转储。
- 使用快照或备份
只要知道对应的二进制日志坐标,就可以使用主库的快照或者备份来初始化备库(如果使用备份,需要确保从备份的时间点开始的主库二进制日志都要存在)。只需要把备份或快照恢复到备库,然后使用CHANGE MASTER TO指定二进制日志的坐标。也可以使用LVM快照、SAN快照、EBS快照——任何快照都可以。
- 使用Percona Xtrabackup
Percona的Xtrabackup是一款开源的热备份工具,多年前我们就介绍过。它能够在备份时不阻塞服务器的操作,因此可以在不影响主库的情况下设置备库。可以通过克隆主库或另一个已存在的备库的方式来建立备库。
在后面会介绍更多使用Percona Xtrabackup的细节。这里会介绍一些相关的功能。创建一个备份(不管是从主库还是从别的备库),并将其转储到目标机器,然后根据备份获得正确的开始复制的位置。
如果是从主库获得备份,可以从xtrabackup_binlog_pos_innodb文件中获得复制开始的位置。如果是从另外的备库获得备份,可以从 xtrabackup_slave_info文件中获得复制开始的位置。另外,InnoDB热备份和MySQL企业版的备份,也是比较好的初始化备库方式。
- 使用另外的备库
可以使用任何一种提及的克隆或者拷贝技术来从任意一台备库上将数据克隆到另外一台服务器。但是如果使用的是mysqldump,-master-data选项就会不起作用。此外,不能使用SHOWMASTER STATUS来获得主库的二进制日志坐标,而是在获取快照时使用 SHOW SLAVE STATUS来获取备库在主库上的执行位置。
使用另外的备库进行数据克隆最大的缺点是,如果这台备库的数据已经和主库不同步,克隆得到的就是脏数据。
注意:不要使用LOAD DATA FROM MASTER或者LOAD TABLE FROM MASTER!这些命令过时、缓慢,并且非常危险,并且只适用于MyISAM存储引擎。
不管选择哪种技术,都要能熟练运用,要记录详细的文档或编写脚本。因为可能不止一次需要做这样的事情。甚至当错误发生时,也需要能够处理。
1.5 推荐的复制配置
有许多参数来控制复制,其中一些会对数据安全和性能产生影响。稍后我们会解释何种规则在何时会失效。本小节推荐的一种“安全”的配置,可以最小化问题发生的概率。
在主库上二进制日志最重要的选项是 sync_binlog:
sync_binlog=1
如果开启该选项,MySQL每次在提交事务前会将二进制日志同步到磁盘上,保证在服务器崩溃时不会丢失事件。如果禁止该选项,服务器会少做一些工作,但二进制日志文件可能在服务器崩溃时损坏或丢失信息。在一个不需要作为主库的备库上,该选项带来了不必要的开销。它只适用于二进制日志,而非中继日志。
如果无法容忍服务器崩溃导致表损坏,推荐使用InnoDB。在表损坏无关紧要时,MyISAM是可以接受的,但在一次备库服务器崩溃重启后,MyISAM表可能已经处于不一致状态。一种可能是语句没有完全应用到一个或多个表上,那么即使修复了表,数据也可能是不一致的。
如果使用InnoDB,我们强烈推荐设置如下选项∶
这些是MySQL5.0及最新版本中的默认配置,我们推荐明确指定二进制日志的名字,以保证二进制日志名在所有服务器上是一致的,避免因为服务器名的变化导致的日志文件名变化。你可能认为以服务器名来命名二进制日志无关紧要,但经验表明,当在服务器间转移文件、克隆新的备库、转储备份或者其他一些你想象不到的场景下,可能会导致很多问题。为了避免这些问题,需要给log_bin选项指定一个参数。可以随意地给一个绝对路径,但必须明确地指定基本的命名(正如我们之前讨论的)。
在备库上,我们同样推荐开启如下配置选项,为中继日志指定绝对路径:
通过设置relay_log可以避免中继日志文件基于机器名来命名,防止之前提到的可能在主库发生的问题。指定绝对路径可以避免多个MySQL版本中存在的Bug,这些Bug可能会导致中继日志在一个意料外的位置创建。skip_slave_start选项能够阻止备库在崩溃后自动启动复制。这可以给你一些机会来修复可能发生的问题。如果备库在崩溃后自动启动并且处于不一致的状态,就可能会导致更多的损坏,最后将不得不把所有数据丢弃,并重新开始配置备库。
read_only选项可以阻止大部分用户更改非临时表,除了复制SQL线程和其他拥有超级权限的用户之外,这也是要尽量避免给正常账号授予超级权限的原因之一。
即使开启了所有我们建议的选项,备库仍然可能在崩溃后被中断,因为master.info和中继日志文件都不是崩溃安全的。默认情况下甚至不会刷新到磁盘,直到MySQL5.5版本才有选项来控制这种行为。如果正在使用MySQL 5.5并且不介意额外的 fsync()导致的性能开销,最好设置以下选项∶
如果备库与主库的延迟很大,备库的I/O线程可能会写很多中继日志文件,SQL线程在重放完一个中继日志中的事件后会尽快将其删除(通过relay_log_purge选项来控制)。
但如果延迟非常严重,I/O线程可能会把整个磁盘撑满。解决办法是配置relay_log_space_limit变量。如果所有中继日志的大小之和超过这个值,I/O线程会停止,等待SQL线程释放磁盘空间。
尽管听起来很美好,但有一个隐藏的问题。如果备库没有从主库上获取所有的中继日志,这些日志可能在主库崩溃时丢失。早先这个选项存在一些Bug,使用率也不高,所以用到这个选项遇到Bug的风险会更高。除非磁盘空间真的非常紧张,否则最好让中继日志使用其需要的磁盘空间,这也是为什么我们没有将relay_log_space_limit列入推荐的配置选项的原因。