MySQL 同步常见问题
By admin
- 12 minutes read - 2429 words6 MySQL 同步
同步功能在MySQL 3.23.15就开始引进了,它可以把一个MySQL服务器上的数据复制到另一个服务器上去。本章描述了MySQL的各种复制特性。介绍了同步的概念,如何设置同步服务器,以及可用服务器的参照。还提供了一系列的常见问题及其答案,疑难解答。
“14.6 Replication Statements“中介绍了同步相关的SQL语句语法。
我们建议经常访问”http://www.mysql.com“经常阅读本章的最新内容。同步功能一直在改进,我们经常把这部分的手册更新到当前的最新内容。
6.1 同步介绍
MySQL 3.23.15及更高的版本支持单向同步。一个服务器作为master(主服务器),一个或者多个服务器作为slave(从服务器)。master服务器 把更新的内容写到二进制日志(binary log或binlog)中,并且维护了一个索引文件来记录日志循环的情况。这些日志中的更新部分会被发送到slave服务器。一个slave连接到 master之后,它通知master最后一次成功增量更新的日志位置。slave会找出所有从那个时刻开始的更新操作,然后阻塞并等待master发送 新的更新操作。
如果想要做一个同步服务器链的话,slave同时也可以作为master。
注意,启用同步后,所有要同步的更新操作都必须在master上执行。否则,必须注意不要造成用户在master上的更新和在slave上的更新引起冲突。
单向同步的好处是稳健,高速,系统易管理:
- 有了master/slave机制后,就更稳健了。当master上发生问题时,可以把slave作为备用切换过去。
- 可以在slave和master之间分担一些查询,这就能加速响应时间。
SELECT
查询就可以在slave上执行以减少master的负载。更新数据的语句则要放在mater上执行以保持master和slave的同步。当非更新操作占多数时,负载均衡就很有效了,不过这只是普通情况而言。 - 另一个好处是可以在slave上备份数据,无需干扰master。备份数据时master照样继续运作。详情请看”5.7.1 Database Backups“。
6.2 同步机制实现概述
MySQL同步机制基于master把所有对数据库的更新、删除 等)都记录在二进制日志里。因此,想要启用同步机制,在master就必须启用二进制日志。详情请看”5.9.4 The Binary Log“。
每个slave接受来自master上在二进制日志中记录的更新操作,因此在slave上执行了这个操作的一个拷贝。
应该非常重要地意识到,二进制日志只是从启用二进制日志开始的时刻才记录更新操作的。所有的slave必须在启用二进制日志时把master上已经存在的数据拷贝过来。如果运行同步时slave上的数据和master上启用二进制日志时的数据不一致的话,那么slave同步就会失败。
把master上的数据拷贝过来的方法之一实在slave上执行 LOAD DATA FROM MASTER
语句。不过要注意,LOAD DATA FROM MASTER
是从MySQL 4.0.0之后才开始可以用的,而且只支持master上的 MyISAM
类型表。同样地,这个操作需要一个全局的读锁,这样的话传送日志到slave的时候在master上就不会有更新操作了。当实现了自由锁表热备份时(在MySQL 5.0中),全局读锁就没必要了。
由于有这些限制,因此我们建议只在master上相关数据比较小的时候才执行 LOAD DATA FROM MASTER
语句,或者在master上允许一个长时间的读锁。由于每个系统之间 LOAD DATA FROM MASTER
的速度各不一样,一个比较好的衡量规则是每秒能拷贝1MB数据。这只是的粗略的估计,不过master和slave都是奔腾700MHz的机器且用100MBit/s网络连接时就能达到这个速度了。
slave上已经完整拷贝master数据后,就可以连接到master上然后等待处理更新了。如果master当机或者slave连接断开,slave会定期尝试连接到master上直到能重连并且等待更新。重试的时间间隔由 --master-connect-retry
选项来控制,它的默认值是60秒。
每个slave都记录了它关闭时的日志位置。msater是不知道有多少个slave连接上来或者哪个slave从什么时候开始更新。
6.3 同步实现细节
MySQL同步功能由3个线程(master上1个,slave上2个)来实现。执行 START SLAVE
语句后,slave就创建一个I/O线程。I/O线程连接到master上,并请求master发送二进制日志中的语句。master创建一个线程来把日志的内容发送到slave上。这个线程在master上执行 SHOW PROCESSLIST
语句后的结果中的 Binlog Dump
线程便是。slave上的I/O线程读取master的 Binlog Dump
线程发送的语句,并且把它们拷贝到其数据目录下的中继日志(relay logs)中。第三个是SQL线程,salve用它来读取中继日志,然后执行它们来更新数据。
如上所述,每个mster/slave上都有3个线程。每个master上有多个线程,它为每个slave连接都创建一个线程,每个slave只有I/O和SQL线程。
在MySQL 4.0.2以前,同步只需2个线程(master和slave各一个)。slave上的I/O和SQL线程合并成一个了,它不使用中继日志。
slave上使用2个线程的优点是,把读日志和执行分开成2个独立的任务。执行任务如果慢的话,读日志任务不会跟着慢下来。例如,如果slave停 止了一段时间,那么I/O线程可以在slave启动后很快地从master上读取全部日志,尽管SQL线程可能落后I/O线程好几的小时。如果slave 在SQL线程没全部执行完就停止了,但I/O线程却已经把所有的更新日志都读取并且保存在本地的中继日志中了,因此在slave再次启动后就会继续执行它 们了。这就允许在master上清除二进制日志,因为slave已经无需去master读取更新日志了。
执行 SHOW PROCESSLIST
语句就会告诉我们所关心的master和slave上发生的情况。
下例说明了 SHOW PROCESSLIST
结果中的3个线程是什么样的。这是在MySQL 4.0.15及更新上执行 SHOW PROCESSLIST
的结果,State
字段的内容已经比旧版本显示的更有意义了。
在master上,SHOW PROCESSLIST
的结果如下:
mysql> SHOW PROCESSLISTG
*************************** 1. row ***************************
Id: 2
User: root
Host: localhost:32931
db: NULL
Command: Binlog Dump
Time: 94
State: Has sent all binlog to slave; waiting for binlog to
be updated
Info: NULL
在这里,线程2是为一个slave连接创建的。结果表明所有未完成的更新日志已经都发送到slave了,master正等待新的更新日志发生。
在slave上,SHOW PROCESSLIST
的结果如下:
mysql> SHOW PROCESSLISTG
*************************** 1. row ***************************
Id: 10
User: system user
Host:
db: NULL
Command: Connect
Time: 11
State: Waiting for master to send event
Info: NULL
*************************** 2. row ***************************
Id: 11
User: system user
Host:
db: NULL
Command: Connect
Time: 11
State: Has read all relay log; waiting for the slave I/O
thread to update it
Info: NULL
这表明线程10是I/O线程,它正连接到master上;线程11是SQL线程,它执行中继日志中的更新操作。现在,这2个线程都处于空闲状态,正等待新的更新日志。
注意,Time
字段的值告诉我们slave上的日志比master晚了多久。详情请看”6.9 Replication FAQ“。
6.3.1 Master 同步线程状态
以下列出了master的 Binlog Dump
线程 State
字段中最常见的几种状态。如果在master上没有 Binlog Dump
线程,那么同步就没有在运行。也就是说,没有slave连接上来。
Sending binlog event to slave
- 事件是由二进制日志构成,一个事件通常由更新语句加上其他信息。线程读取到一个事件并正发送到slave上。
Finished reading one binlog; switching to next binlog
- 读取完了一个二进制日志,正切换到下一个。
Has sent all binlog to slave; waiting for binlog to be updated
- 已经读取完全部未完成更新日志,并且全部都发送到slave了。它处于空闲状态,正等待在master上执行新的更新操作以在二进制日志中产生新的事件,然后读取它们。
Waiting to finalize termination
- 当前线程停止了,这个时间很短。
6.3.2 Slave的I/O线程状态
以下列出了slave的I/O线程 State
字段中最常见的几种状态。从MySQL 4.1.1开始,这个状态在执行 SHOW SLAVE STATUS
语句结果的 Slave_IO_State
字段也会出现。这意味着可以只执行 SHOW SLAVE STATUS
语句就能了解到更多的信息。
Connecting to master
- 该线程证尝试连接到master上。
Checking master version
- 确定连接到master后出现的一个短暂的状态。
Registering slave on master
- 确定连接到master后出现的一个短暂的状态。
Requesting binlog dump
- 确定连接到master后出现的一个短暂的状态。该线程向master发送一个请求,告诉它要请求的二进制文件以及开始位置。
Waiting to reconnect after a failed binlog dump request
- 如果二进制日志转储(binary log dump)请求失败了(由于连接断开),该线程在休眠时进入这个状态,并定期重连。重连的时间间隔由
--master-connect-retry
选项来指定。 Reconnecting after a failed binlog dump request
- 该线程正尝试重连到master。
Waiting for master to send event
- 已经连接到master,正等待它发送二进制日志。如果master闲置时,这个状态可能会持续较长时间,如果它等待超过
slave_read_timeout
秒,就会发生超时。这时,它就会考虑断开连接,然后尝试重连。 Queueing master event to the relay log
- 已经读取到一个事件,正把它拷贝到中继日志中以备SQL线程处理。
Waiting to reconnect after a failed master event read
- 读日志时发生错误(由于连接断开)。该线程在重连之前休眠
master-connect-retry
秒。 Reconnecting after a failed master event read
- 正尝试重连到master。当连接确定后,状态就变成
Waiting for master to send event
。 Waiting for the slave SQL thread to free enough relay log space
relay_log_space_limit
的值非零,中继日志的大小总和超过这个值了。I/O线程等待SQL线程先处理中继日志然后删除它们以释放足够的空间。Waiting for slave mutex on exit
- 当前线程停止了,这个时间很短。
6.3.3 Slave的SQL线程状态
以下列出了slave的SQL线程 State
字段中最常见的几种状态:
Reading event from the relay log
- 从中继日志里读到一个事件以备执行。
Has read all relay log; waiting for the slave I/O thread to update it
- 已经处理完中继日志中的全部事件了,正等待I/O线程写入更新的日志。
Waiting for slave mutex on exit
- 当前线程停止了,这个时间很短。
SQL线程的 State
字段有时候也可能是一个SQL语句。这意味着它从中继日志中读取到一个事件了,从中提取出SQL语句,并执行它。
6.3.4 中继日志及状态文件
默认地,中继日志的名字格式为 `host_name-relay-bin.nnn`
,host_name 是服务器的主机名,nnn 是序号。中继日志是根据顺序的序号来创建的,从 000001
(MySQL 4.0 及更旧是 001
)开始。slave上用一个索引文件来跟踪当前正在使用的中继日志。默认的中继日志索引文件名是 `host_name-relay-bin.index`
。默认地,这个文件位于slave的数据文件目录下。默认文件名可以根据的系统选项 --relay-log
和 --relay-log-index
来替换。详情请看”6.8 Replication Startup Options“。
中继日志和二进制日志的格式一样,因此也可以用 mysqlbinlog
来读取。当SQL线程读取完中继日志中的全部事件后就不再需要它了,会自动删除它。中继日志没有显式的删除机制,因为SQL线程会自动关注这个。不过,从MySQL 4.0.14开始,执行 FLUSH LOGS
的话就会轮转(rotate)中继日志,会让SQL线程删除它们。
在下列条件中会创建一个新的中继日志:
- slave启动后,I/O线程第一次启动(在MySQL 5.0中,每次I/O线程启动后都会新建一个中继日志,而不只是第一次启动时)。
- 刷新日志时;例如,执行
FLUSH LOGS
语句或运行mysqladmin flush-logs
命令(从 MySQL 4.0.14开始才会创建新中继日志)。 - 当前的中继日志大小太大了;”太大了”是这么判断的:
max_relay_log_size
, 如果max_relay_log_size
> 0 的话max_binlog_size
, 如果max_relay_log_size
= 0 或 MySQL 低于 4.0.14
slave会在数据文件目录下创建两个额外的文件。它们是状态文件,名字默认为 `master.info`
and `relay-log.info`
。它们的内容跟执行 SHOW SLAVE STATUS
语句的结果类似。详情请看”14.6.2 SQL Statements for Controlling Slave Servers“。由于是磁盘上的文件,它们在slave关闭后还会留着。下一次slave启动时,就会读取这两个文件来判断从master读取到二进制日志的什么位置了,处理中继日志到什么位置了。
`master.info`
文件由来I/O线程更新。在MySQL 4.1以前,文件的内容和执行 SHOW SLAVE STATUS
语句结果中相对应的字段值一样,如下:
Line****Description
1
Master_Log_File
2
Read_Master_Log_Pos
3
Master_Host
4
Master_User
5
Password (not shown by SHOW SLAVE STATUS
)
6
Master_Port
7
Connect_Retry
从MySQL 4.1开始,文件内容还包括了SSL选项:
Line****Description 1
Number of lines in the file
2
Master_Log_File
3
Read_Master_Log_Pos
4
Master_Host
5
Master_User
6
Password (not shown by SHOW SLAVE STATUS
)
7
Master_Port
8
Connect_Retry
9
Master_SSL_Allowed
10
Master_SSL_CA_File
11
Master_SSL_CA_Path
12
Master_SSL_Cert
13
Master_SSL_Cipher
14
Master_SSL_Key```
relay-log.info`` 文件由SQL线程来更新。文件的内容和执行
SHOW SLAVE STATUS` 语句结果中相对应的字段值一样:
Line****Description
1
Relay_Log_File
2
Relay_Log_Pos
3
Relay_Master_Log_File
4
Exec_Master_Log_Pos
备份slave数据时,要把这两个文件也备份起来,和中继日志一道。想要恢复slave时就用得到它们了。如果丢失了中继日志,但是 `relay-log.info`
文件还存在,那么就可以判断出SQL线程执行了多少master二进制日志。然后执行 CHANGE MASTER TO
语句,带上 MASTER_LOG_FILE
和 MASTER_LOG_POS
选项告诉slave要从master的二进制日志哪个位置重新读取。当然了,这要求master上相关的二进制日志都还留着。
如果slav打算同步 LOAD DATA INFILE
语句,那么也要备份对应目录下的任何 `SQL_LOAD-*`
文件。这可以在 LOAD DATA INFILE
被中断后继续保持同步。这个目录由 --slave-load-tmpdir
选项来指定。默认地,如果没有指定的话,它的值就是变量 tmpdir
的值。
6.4 设置同步
以下描述了如何快速设置MySQL同步服务器。假设你打算同步全部的数据库,并且之前没有设置过。需要关闭master服务器以完成全部的步骤。
本章描述的过程可以用于一个slave的情况,也可以用于多个slave的情况。
这只是一个最直接设置slave的办法,并不是只有一个。例如,已经有了master的数据快照(snapshot),master已经设置了服务 器编号ID(server_id)并且启用了二进制日志,这就无需关闭master或者阻止在master上更新数据了。详情请看”6.9 Replication FAQ“。
想要完全掌握MySQL同步设置,最好把本章全部读完,并且测试在”14.6.1 SQL Statements for Controlling Master Servers“和”14.6.2 SQL Statements for Controlling Slave Servers“中提到的全部语句。而且要熟悉各种同步设置选项,详情请看”6.8 Replication Startup Options“。
注意,这个过程以及后面一些同步SQL语句需要有 SUPER
权限。MySQL 4.0.2以前,则是 PROCESS
权限。
- 请确认master和slave上都安装了较近的MySQL版本,且这些版本之间要能兼容,在”6.5 Replication Compatibility Between MySQL Versions“中列出来了。请确认在最新版本中还有存在问题,否则不要报告该bug。
- 在master上新加一个帐户,slave才能用它来连接。这个帐户必须授予
REPLICATION SLAVE
权限。如果这个帐户只用于同步(推荐这么做),那就没必要授予其他权限了。设定你的域是mydomain.com
,想要授权一个帐户repl
使用密码slavepass
,允许它可以在域里的任何主机连接到master上。用GRANT
语句来创建帐户:
mysql> GRANT REPLICATION SLAVE ON *.*
-> TO 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
在MySQL 4.0.2以前,用 FILE
权限来代替 REPLICATION SLAVE
:
mysql> GRANT FILE ON *.*
-> TO 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
如果打算在slave上执行 LOAD TABLE FROM MASTER
或 LOAD DATA FROM MASTER
语句,那么必须给该帐户授予附加权限:
- 授予全局
SUPER
和RELOAD
权限。 - 授予对想要加载的所有表上的
SELECT
权限。在master上任何没有SELECT
权限的表都会被LOAD DATA FROM MASTER
略过。
- 如果只用到
MyISAM
表,执行FLUSH TABLES WITH READ LOCK
语句刷新所有表并且阻止其他写入:
mysql> FLUSH TABLES WITH READ LOCK;
不要退出执行 FLUSH TABLES
语句的客户端,以保持读锁有效(如果退出了,读锁就释放了)。然后从master上取得数据快照。比较简单的办法就是把数据目录打包压缩。例如,Unix上的 tar
, PowerArchiver
, WinRAR
, WinZip
,或Windows上的类似程序。想要用 tar
来创建一个压缩包,包括所有的数据库,只需执行以下命令(把目录改成你的真实路径):
shell> tar -cvf /tmp/mysql-snapshot.tar .
如果只想打包一个数据库 this_db
,只需执行命令:
shell> tar -cvf /tmp/mysql-snapshot.tar ./this_db
然后把这个文件拷贝到slave的 `/tmp`
目录下。在slave上,执行以下命令解开压缩包(把目录改成你的真实路径):
shell> tar -xvf /tmp/mysql-snapshot.tar
可能不需要同步 mysql
数据库,因为在slave上的权限表和master不一样。这时,解开压缩包的时候要排除它。同时在压缩包中也不要包含任何日志文件,或者 `master.info~
或 `relay-log.info`
文件。当在master上的 FLUSH TABLES WITH READ LOCK
语句还生效时,在master上读取当前二进制文件的文件名及偏移位置:
mysql > SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| mysql-bin.003 | 73 | test | manual,mysql |
+---------------+----------+--------------+------------------+
File
字段显示了二进制日志文件名,Position
字段显示了日志偏移位置。在这个例子中,日志文件是 mysql-bin.003
,偏移位置是 73
。记下这些值,在后面设置slave的时候就需要用到它们了。它们表示了slave要从master的哪个偏移位置开始处理更新操作。取得快照和记录下日志名及偏移位置后,就可以让master释放读锁了:
mysql> UNLOCK TABLES;
如果用到 InnoDB
表,那么最好使用 InnoDB Hot Backup
工具。它无需在master上请求任何锁就能做到快照的一致性,并且在后面中在slave上要用到的快照中已经记录了日志文件名以及偏移位置。InnoDB Hot Backup
是费免费(商业的)的附加工具,它没有包含在MySQL发布包中。访问 InnoDB Hot Backup
的主页 http://www.innodb.com/manual.php 查看更多详细信息。除去 InnoDB Hot Backup
的另一个最快的办法就是关闭master服务器,拷贝 InnoDB
数据文件,日志文件,以及表结构定义文件( `.frm`
文件)。想要记录当前日志文件及偏移位置,需要在master关闭前执行如下可语句:
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
尽快记下 SHOW MASTER STATUS
显示结果中的日志文件及偏移位置。然后,在不解锁的情况下关闭master,确保master上的快照和记录的结果一致:
shell> mysqladmin -u root shutdown
还有一个方法可以同时用于 MyISAM
和 InnoDB
表,这就是在master上作SQL转储而无需如上所述备份二进制日志。在master上运行 mysqldump --master-data
命令,然后把结果文件转储到slave上。不过,这比拷贝二进制日志慢点。如果master在以前没有启用 --log-bin
选项,那么执行 SHOW MASTER STATUS
语句的结果中的文件名及偏移位置值为空了,那么后面在slave上指定的参数值就是空字符串(''
) 和 4
了。
- 确认master上的
`my.cnf`
文件[mysqld]
区间有log-bin
选项。这个区间还必须有server-id=master_id
选项,的值必须是 1 到 2^32-1 之间的正整数。例如:
[mysqld]
log-bin
server-id=1
如果这些配置选项不存在,那么就加上并且重启master。
- 关闭要做slave的服务器,在
`my.cnf`
文件中增加如下选项:
[mysqld]
server-id=slave_id
slave_id
的值和 master_id
类似,是 1 到 2^32-1 之间的正整数。另外,这个ID必须不能和master的ID一样。例如:
[mysqld]
server-id=2
如果有多个slave,那么每个slave都必须要有一个唯一的 server-id
,它的值不能和master以及其其他slave的值一样。可以把 server-id
想象成为IP地址:这些ID标识了整个同步组合中的每个服务器。如果没有指定 server-id
的值,如果也没定义 master-host
,那么它的值就为1,否则为2。注意,如果没有设定 server-id
,那么master就会拒绝所有的slave连接,同时slave也会拒绝连接到master上。因此,省略配置 server-id
只对备份二进制日志有利。
- 如果已经备份了master上的数据(直接打包压缩的方式),那么在slave启动之前把它们拷贝过去。要确保文件的权限属主等设置没问题。MySQL运行的用户必须对这些文件有读写权限,就跟在master上一样。如果是用
mysqldump
备份的,那么可以直接启动salve(直接跳到下一步)。 - 启动slave,如果它之前已经运行同步了,那么在启动slave的时候使用
--skip-slave-start
选项使之不会立刻去连接master。最好也使用--log-warnings
选项(从 MySQL 4.0.19 和 4.1.2 开始就是默认启用了)来启动slave,以知道发生问题时的更详细的信息(例如,网络或者连接问题)。从开始MySQL 4.0.21 和 4.1.3,异常中止的连接不再记录到错误日志中,除非--log-warnings
选项的值大于1。 - 如果在master上用
mysqldump
备份数据的话,把文件导入slave中:
shell> mysql -u root -p < dump_file.sql
- 在slave上执行如下语句,把各个选项的值替换成真实值:
mysql> CHANGE MASTER TO
-> MASTER_HOST='master_host_name',
-> MASTER_USER='replication_user_name',
-> MASTER_PASSWORD='replication_password',
-> MASTER_LOG_FILE='recorded_log_file_name',
-> MASTER_LOG_POS=recorded_log_position;
下表列出了各个选项字符串的最大长度:
MASTER_HOST
60
MASTER_USER
16
MASTER_PASSWORD
32
MASTER_LOG_FILE
255
- 启动slave线程:
mysql> START SLAVE;
做完上述过程后,slave应该会连接到master上并且捕获所有从取得快照后的更新操作。
如果忘了设置master的 server-id
值,那么slave就不能连接到master上。
如果忘了设置master的 server-id
值,那么在错误日志中就会记录如下内容:
Warning: You should set server-id to a non-0 value if master_host is set;
we force server id to 2, but this MySQL server will not act as a slave.
如果因为其他原因不能同步的话,错误信息也会记录在slave的日志上。
一旦slave开始同步了,就能在数据文件目录下找到2个文件 `master.info`
和 `relay-log.info`
。slave利用这2个文件来跟踪处理了多少master的二进制日志。
不要删除或者修改这2个文件,除非知道怎么改。尽管如此,我们更推荐用 CHANGE MASTER TO
语句来做。
注意: `master.info`
中的内容覆盖了部分命令行中指定的或 `my.cnf`
的选项。详情请看”6.8 Replication Startup Options“。
只要有了master的数据快照,就可以按照上述几个步骤配置其它slave了。无需再次取得master的数据快照,每个slave都可以用这一份快照来做。
6.5 不同MySQL版本之间的同步兼容性
最早的二进制格式是在MySQL 3.23中开发出来的。在MySQL 4.0中改进了,MySQL 5.0又改进了。在配置同步时需要升级服务器的话,它们之间的因果关系在”6.6 Upgrading a Replication Setup“中描述了。
如果只关心同步,任何MySQL 4.1.x版本和MySQL 4.0.x是一样的,因为它们都使用相同格式的二进制日志。所以,这些版本是互相兼容的,它们之间可以无缝地运行同步。一个例外的情况是,MySQL 4.0.0到4.0.2由于开发的较早,无法和后来的版本互相兼容,所以不要使用它们(它们是4.0版本的alpha系列。它们之间的兼容性在发布包的手 册中均有相关文档)。 下表展示了不同版本的MySQL之间的master/slave同步兼容性。
MasterMasterMaster3.23.33 and up4.0.3 and up or any 4.1.x5.0.0Slave****3.23.33 and up yes
no
no Slave****4.0.3 and up yes
yes
no Slave****5.0.0 yes
yes
yes
一个通常的规则是,我们建议使用最近的MySQL版本,因为同步兼容性一直在改善。我们也建议master和slave都使用同一个版本。
6.6 升级同步
如果升级服务器时涉及到配置同步,升级设置的步骤跟当前版本以及升级后的版本不同而异。
6.6.1 升级同步到 4.0 或 4.1
本节适用于从MySQL 3.23升级到4.0或者4.1的情况。4.0的服务器必须是4.0.3或者更高,”6.5 Replication Compatibility Between MySQL Versions“中提到了。
把master从MySQL 3.23升级到4.0或4.1时,首先要确认这个master的所有slave都已经是4.0或4.1了,否则的话,要先升级slave:挨个关闭,升级,重启,重启同步等。 通过以下步骤可以实现安全地升级,假定master要升级到3.23,而slave已经是4.0或4.1了。注意,master升级后,不要重启使用任何旧的二进制日志的同步,因为它会干扰到4.0或4.1 slave的同步。
- 在master上执行
FLUSH TABLES WITH READ LOCK
语句,阻止所有的更新。 - 等到所有的slave都跟上了master的数据更新。在master上执行
SHOW MASTER STATUS
语句取得二进制日志以及偏移位置。然后,再slave用这些值执行SELECT MASTER_POS_WAIT()
语句,它会阻止slave上的同步且返回它已经同步的偏移位置。然后在slave上执行STOP SLAVE
语句。 - 关闭master,将它升级到MySQL 4.0或4.1。
- 重启master,记下它的新的二进制文件名。可以在master上执行
SHOW MASTER STATUS
语句来取得这些信息。然后在每个slave上都执行如下语句:
mysql> CHANGE MASTER TO MASTER_LOG_FILE='binary_log_name',
-> MASTER_LOG_POS=4;
mysql> START SLAVE;
6.6.2升级同步到 5.0
本节适用于从MySQL 3.23,4.0或4.1升级到5.0的情况。4.0的服务器必须是4.0.3或者更高,”6.5 Replication Compatibility Between MySQL Versions“中提到了。
首先,注意到MySQL 5.0还是alpha发布系列。它在各方面都比旧版本好(更容易升级一些同步中重要的会话变量,例如 sql_mode
;详情请看”C.1.3 Changes in release 5.0.0 (22 Dec 2003: Alpha“)。不过,它还没经过广泛测试。由于是alpha版本,我们不建议用于任何生产环境(现在已经可以用于生产了,译者注)。
把master从MySQL 3.23,4.0或4.1升级到5.0.0时,首先要确认这个master的所有slave都已经是5.0.0了,否则的话,要先升级slave:挨个关 闭,升级,重启,重启同步等。5.0.0的slave可以读取升级前写入的执行语句的中继日志。升级完后的slave创建的中继日志就是5.0格式了。
当所有的slave都升级完了,关闭master,升级到5.0.0,然后重启。5.0.0的master也可以读取旧格式的二进制日志。slave能识别旧的格式并且合理处理它们。master上新建的二进制日志都是5.0.0格式的。slave也能识别这格式。
换言之,在升级到5.0.0时无需特殊的规定,除非在升级master到5.0.0之前slave必须使用旧版本的。注意,把5.0.0降级到旧版本中不能自动地做了:必须确保所有的5.0.0格式二进制日志和中继日志都已经处理完了,然后才能把它们删除完成降级。
6.7 同步特性及已知问题
以下列出了同步支持什么,不支持什么。附加的 InnoDB
特殊相关的信息以及同步请看”16.7.5 InnoDB
and MySQL Replication“。
AUTO_INCREMENT
,LAST_INSERT_ID()
, 和TIMESTAMP
的值都能被正常同步。USER()
,UUID()
, 和LOAD_FILE()
函数都完完全全地同步到slave,因此可能不大可靠。MySQL 4.1.1以前的版本中的CONNECTION_ID()
函数也是如此。从MySQL 4.1.1及更高以后,新的PASSWORD()
函数可以正常同步,当然了,slave必须是4.1.1或更高或者不同步它。如果有旧版本的slave必须要同步PASSWORD()
函数,那么master启动时必须增加--old-password
选项,这样在master上就用旧的方法来实现PASSWORD()
了(注意,MySQL 4.1.0的PASSWORD()
函数实现跟其他的版本都不同,最好不要同步4.1.0)。- 从MySQL 4.0.14开始同步
FOREIGN_KEY_CHECKS
变量。从5.0.0开始同步sql_mode
,UNIQUE_CHECKS
,和SQL_AUTO_IS_NULL
变量。SQL_SELECT_LIMIT
和table_type
变量目前还不能被同步。 - 现在讨论使用不同字符集的MySQL服务器间同步的问题。
- 首先,在master和slave上必须总是使用同样的全局字符集以及校验字符集(
--default-character-set
,--default-collation
都是相关的全局变量)。否则,slave上可能会出现键重复(duplicate-key)的错误,因为用master的字符集认为该键可能是唯一的,但是用slave的字符集则未必然。 - 第二,如果master必须低于MySQL 4.1.3,则会话(session)的字符集必须和全局值一样(也就是说,不能执行
SET NAMES
,SET CHARACTER SET
等语句),因为这些对字符集的修改在slave不能识别。如果master是4.1.3或者更高,slave也是这样的话,那么会话字符集就可以随便修改了(执行NAMES
,CHARACTER SET
,COLLATION_CLIENT
,COLLATION_SERVER
等),并且这些修改都会被记录到二进制日志中,然后同步到slave上,它就知道怎么做了。该会话还会阻止试图修改这些全局变量的操作;就如前面所说,master和slave必须使用同样的全局字符集。 - 如果在master上有和全局变量
collation_server
不一样字符集的数据库,那么就要设计CREATE TABLE
语句使得数据表不隐式地使用该数据库的默认字符集,因为这目前还是一个bug(Bug #2326);一个变通的办法是在CREATE TABLE
语句中显式地声明数据表的字符集以及校验字符集。
- 有时可能会把master上的事务表同步到slave后变成非事务表。例如,可以在slave上把master的
InnoDB
表当成MyISAM
表。不过,slave在一个BEGIN/COMMIT
区块中停止的话就有问题了,因为slave会从BEGIN
重新开始。这个问题已经放到TODO中,很快会被修复。 - 更新语句中如果用到了用户自定义变量(例如变量
@var_name
)的情况下,在MySQL 3.23和4.0不能被正确同步。在 4.1 这已经修复了。注意,从MySQL 5.0开始,用户变量就不区分大小写了。在做MySQL 5.0和旧版本间的同步需要考虑到这个问题。 - 从4.1.1以及更高版本中,slave可以用SSL方式连接到master。
- 在master上执行的
CREATE TABLE
语句如果包括了DATA DIRECTORY
或INDEX DIRECTORY
子句,那么它也会应用于slave上。如果slave上不存在对应的目录或者没有权限时便出现问题。从MySQL 4.0.15开始,有个sql_mode
选项叫NO_DIR_IN_CREATE
。如果slave的SQL模式包含这个选项,那么它在同步CREATE TABLE
语句前会忽略前面提到的2个子句。结果就是MyISAM
的数据和索引文件都只能放在该表的数据库目录下。 - 尽管没听说过发生过类似的情况,不过理论上确实存在这种可能性:如果一个查询被设计为非确定方式的修改数据,那么可能导致master和slave的数据不一致。那么,就把决定的权力交给查询优化器吧。(通常这不是一个好的做法,甚至超出了同步的范围,详情请看”1.8.7.3 Open Bugs and Design Deficiencies in MySQL“)
- 在MySQL 4.1.1之前,
FLUSH
,ANALYZE TABLE
,OPTIMIZE TABLE
,和REPAIR TABLE
语句没有写入到二进制日志中,因此也不会同步到slave上。这通常不会引发问题,因为它们并没有修改数据。不过在特定情况下可能导致问题。如果同步mysql
数据库下的权限表,在更新时不是用GRANT
语句,那么必须在slave上执行那么必须在slave上执行FLUSH PRIVILEGES
语句才能使之生效。同样地,如果还有一个MyISAM
表是MERGE
表的一部分,那么必须在slave上手工执行FLUSH TABLES
语句。从MySQL 4.1.1开始,这些语句都写入二进制日志了(除非指定选项NO_WRITE_TO_BINLOG
或它的同名选项LOCAL
)。一些例外的情况是FLUSH LOGS
,FLUSH SLAVE
, 和FLUSH TABLES WITH READ LOCK
(它们中的任何一个同步到slave的话都可能导致问题)。例子可见”14.5.4.2FLUSH
Syntax“。 - MySQL只支持一个master多个slave的机制。以后我们会增加一个表决算法,如果当前master出现问题时能自动切换。同时也会引进一个”代理”进程来帮助将
SELECT
查询发送到不同的slave上达到负载均衡。 - 当服务器关闭,重启后,所有的
MEMORY
(HEAP
) 表都清空了。从MySQL 4.0.18开始,master用以下方式同步它们:一旦master开始使用一个MEMORY
表,它会在用完这些表之后在二进制日志中写入一个DELETE FROM
语句告诉slave把它们删除。详情请看”15.3 TheMEMORY
(HEAP
) Storage Engine“。 - 除非关闭slave(只是关闭slave线程),临时表也会同步;并且在slave上已经记录了一些还未被执行的需要用到临时表的更新语句。关闭slave再重启后更新所需的临时表就不复存在了。为了避免这个问题,在有临时表时就不要关闭slave。或者,使用以下步骤:
- 提交一个
STOP SLAVE
语句。 - 使用
SHOW STATUS
语句检查变量Slave_open_temp_tables
的值。 - 如果它的值是0,运行
mysqladmin shutdown
命令关闭slave。 - 如果它的值不是0,用
START SLAVE
语句重启slave线程。 - 如果还有这样的好运气就再次执行同样的步骤吧。^_^
我们会尽快解决这个问题。
- 如果在一个循环master/slave同步关系中指定
--log-slave-updates
选项,那么就可以安全地连接到各个服务器上。注意,很多语句可能在这种设置环境下不能正常工作,除非程序中已经特别注意避免这种更新时潜在的问题了,因为可能在不同服务器上不同的顺序上发生更新问题。这意味着可以设定像下面的循环:
A -> B -> C -> A
服务器ID都已经编码到二进制日志中了,因此服务器A知道那些自己创建的日志,从而不会去执行它们(除非在服务器A上启动时增加 --replicate-same-server-id
选项,这个选项只在极少数情况下设置有意义)。因此,这就不会存在无限循环了。不过这个循环只有在更新表时没有发生冲突才不会发生问题。换言之,如果在A 和C中同时插入一条记录,那么可能在A中不可能插入数据,因为它的键可能跟C的键冲突了。同样地,也不能在两个服务器上更新同一条记录,除非2次更新操作 间有足够的时间间隔。
- 如果在slave上执行一个SQL语句后产生错误,那么slave的SQL线程就终止,然后它在错误日志中写入一条信息。可以连接到slave上,解决问题(例如,不存在表)后,运行
START SLAVE
语句重启它。 - 可以放心地关闭master(干净地)之后再重启它。如果slave到master的连接断开了,它会立刻重连。如果失败了,slave会定期重试(默认是每60秒重试一次,可通过
--master-connect-retry
选项来修改)。slave也会处理网络断开的情况。不过,slave会在slave_net_timeout
秒之后如果还没收到来自master的数据才会当作网络断开的情况来处理。如果断开时间不长,可以减少slave_net_timeout
的值。详情请看”5.2.3 Server System Variables“。 - 也可以放心地关闭slave(干净地),它会记录停止的地方。不干净地关闭slave可能产生问题,特别是系统关闭了但缓存还没刷新到磁盘时。可以提供不间断电源来提高系统容错性。master的不干净关闭可能导致表和二进制内容的不一致;如果是
InnoDB
表,使用--innodb-safe-binlog
选项在master上就能避免这个问题。详情请看”5.9.4 The Binary Log“。 - 由于
MyISAM
表的非事务本质,就可能发生一个语句只更新了部分表就返回错误代码的情况。例如,一个多重插入语句中,有一条记录违反了约束键规则,一个更新语句在更新了 一些记录后辈杀掉了。如果在master上发生这种情况了,那么slave线程会推出,等待数据库管理员决定要怎么做,除非这个错误代码是合法的并且这个 语句的执行结果也是一样的错误代码。并没有关于错误代码是否合法的详细描述,一些错误代码可以用--slave-skip-errors
选项屏蔽掉。这个选项从MySQL 3.23.47开始就可以用了。 - 如果把非事务表同步到事务表时在一个
BEGIN/COMMIT
段内更新数据表了,如果在非事务表提交之前有其他线程更新它了,那么这个更新操作就不会正确地同步到二进制日志中。这是因为只有整个事务成功提交了才会写到二进制日志中。 - 在4.0.15之前,任何在非事务表的更新操作会在它执行的时候立刻写入到二进制日志中,然而事务表的更新只有在
COMMIT
后才写入,ROLLBACK
的话就不写入了。因此在一些事务中更新事务表或非事务表时就需要考虑这个情况了(不只是同步时会碰到这个问题,想要把二进制日志作为备份时也一样)。在 MySQL 4.0.15中,我们已经修改了更新事务和非事务表混合的情况下的日志记录行为,它解决了这个问题(对于二进制日志来说顺序地记录语句是比较不错的做法, 所有必须的语句都会写进去,ROLLBACK
也一样)。当第二个连接更新非事务表而第一个连接的事务还没结束时,就会有同样的问题了;仍会发记录语句顺序发生错误的问题,因为第二个连接会在更新完成后立刻写入到日志中。 - 当4.x的slave从3.23的master上同步
LOAD DATA INFILE
时,SHOW SLAVE STATUS
中的Exec_Master_Log_Pos
和Relay_Log_Space
字段的值就不正确了。Exec_Master_Log_Pos
值不正确的话在重启slave之后会导致问题;因此最好在重启前修改一下这个值,只需在master上运行FLUSH LOGS
。这个bug在MySQL 5.0.0的slave中已经解决了。
下表列出了MySQL 3.23同步时会发生的问题,它们在MySQL 4.0已经解决了:
LOAD DATA INFILE
能正确处理,只要那个数据文件在更新开始时仍然存在于master上。LOAD DATA LOCAL INFILE
不再像以前3.23那样被略过了。- 在3.23中,
RAND()
更新同步不正常。因此在使用RAND()
更新时采用RAND(some_non_rand_expr)
格式。例如,可以用UNIX_TIMESTAMP()
作为RAND()
的参数。
6.8 同步启动选项
不管是master还是slave,都要设定 server-id
选项来确定使它们都有各自唯一的同步ID。必须选择 1 到 2^32-1 之间的正整数。例如: server-id=3
。
关于master服务器上可用于控制二进制日志记录的选项详细描述请看”5.9.4 The Binary Log“。
下表描述了slave同步可用的选项,可以在命令行或者配置文件中设定它们。
一些slave同步选项以特定的方式来处理,在slave启动时,如果存在 `master.info`
文件并且包含这些选项,那么slave将略过它们。这些选项如下:
--master-host
--master-user
--master-password
--master-port
--master-connect-retry
从MySQL 4.1.1开始,一下选项也按照上述方式特殊处理:
--master-ssl
--master-ssl-ca
--master-ssl-capath
--master-ssl-cert
--master-ssl-cipher
--master-ssl-key
在MySQL 4.1.1中, `master.info`
文件的格式改变了以包含相应的SSL选项。另外,MySQL 4.1.1文件格式还包括了在第一行中的文件总行数。如果从旧版本升级到4.1.1,那么服务器启动时会自动升级 `master.info`
为新的格式。不过,如果是从4.1.1降级到旧版本,就需要在系统第一次启动时手工删除文件的第一行。注意,这种情况下,被降级的服务器就不能再使用SSL选项连接到master了。
slave启动时如果不存在 `master.info`
文件,它就使用在命令行或者配置文件中指定的参数值来启动。这在每次第一次启动slave服务器时都是这样,或者执行 RESET SLAVE
语句关闭且重启slave之后。
slave启动时如果存在 `master.info`
文件,那么它就略过这些选项,而是直接读取 `master.info`
文件中的值。
如果重启salve时使用的选项值和 `master.info`
中的不一样,那么这个新的值不会生效,因为slave服务器还是照样只读取 `master.info`
文件。想要使用不同的选项值,可以在删除 `master.info`
后重启slave或者使用 CHANGE MASTER TO
语句(推荐)重置选项值。
假定在 `my.cnf`
设定了以下选项值:
[mysqld]
master-host=some_host
第一次启动slave的时候,它从 `my.cnf`
中读取选项值,然后再把它们保存在 `master.info`
中。下次重启slave时,它就只读取 `master.info`
的内容而略过 `my.cnf`
中的选项值了。企图修改 `my.cnf`
来改变同步选项是不可行的,不过可以通过执行 CHANGE MASTER TO
语句来实现:
由于服务器认为 `master.info`
的优先级比配置文件高,因此建议根本不要在启动时附加同步选项,而只用 CHANGE MASTER TO
语句。详情请看”14.6.2.1 CHANGE MASTER TO
Syntax“。
下例显示了一些配置slave的扩展选项:
[mysqld]
server-id=2
master-host=db-master.mycompany.com
master-port=3306
master-user=pertinax
master-password=freitag
master-connect-retry=60
report-host=db-slave.mycompany.com
下列所述启动选项都是用来控制同步的:它们中的大部分都可以在运行时用 CHANGE MASTER TO
语句来改变。其他的,例如 --replicate-*
,只能在salve启动时指定。我们打算在将来解决这个问题。
--log-slave-updates
: 通常,slave从master接收更新操作后并没有再把它们记录在二进制日志中。这个选项告诉slave的SQL线程要把这些更新操作记录在二进制日志中。想要这个选项起作用,需要同时启用 --log-bin
选项才能启用二进制日志。在使用同步链机制时,就需要使用 --log-slave-updates
选项。例如,可能需要设置如下同步关系:
A -> B -> C
在这里,A当作B的master,B当作C的master。B同时是slave又是master,在A和B上都需要启用 --log-bin
选项,并且在B上还需要启用 --log-slave-updates
选项。
--log-warnings
: 让slave在执行同步时记录更多的错误日志。例如,它会通知你在网络/连接失败后重连成功,并且通知了每个slave线程如何启动的。这个选项在MySQL 4.0.19和4.1.12之后默认启用了;用 --skip-log-warnings
就可以禁用它。从MySQL 4.0.21和MySQL 4.1.3开始,除非这个选项的值大于1,否则放弃的连接不再记录在错误日志中。这个选项不只是用于限制同步,它产生的警告跨越了大部分操作。
--master-connect-retry=seconds
: 在master当机或者网络连接中断后,slave在重新连接到master之前休眠的秒数。如果在 `master.info`
文件中存在,就优先使用它。如果没有设置,默认是60。
--master-host=host
: master服务器的主机名或者ip地址。如果没有设置它,slave线程无法启动。如果存在的话, `master.info`
文件中选项值优先被读取。
--master-info-file=file_name
: slave记录master信息的文件名。默认名字是 `master.info`
,放在数据文件目录下。
--master-password=password
: 用于被授权连接到master上运行同步的帐户密码。如果存在的话, `master.info`
文件中选项值优先被读取。如果没有设置,就当作是空密码。
--master-port=port_number
: master上监听的TCP/IP端口号。如果存在的话, `master.info`
文件中选项值优先被读取。如果没有设置,就当作预编译的设置。如果没有修改 configure
选项参数,那么就是3306。
`–master-ssl,--master-ssl-ca=file_name
,``–master-ssl-capath=directory_name,
–master-ssl-cert=file_name,
--master-ssl-cipher=cipher_list,
–master-ssl-key=file_name: 用于设定用SSL安全连接到master的选项。它们的意义对应于”[5.6.7.5 SSL Command-Line Options][7]“中提到的
–ssl,
–ssl-ca,
–ssl-capath,
–ssl-cert,
–ssl-cipher,
–ssl-key选项。如果存在的话, ``
master.info` `` 文件中选项值优先被读取。这些选项是从MySQL 4.1.1之后开始可以用的。
--master-user=username
: 用于被授权连接到master上运行同步的帐户。这个帐户必须有 REPLICATION SLAVE
权限(在MySQL 4.0.2以前,则是 FILE
权限)。如果存在的话, `master.info`
文件中选项值优先被读取。如果没有设置,就当作是 test
。
--max-relay-log-size=#
: 中继日志自动轮转(rotate)的大小。详情请看”5.2.3 Server System Variables“。这个选项是从MySQL 4.0.14之后才可以用的。
--read-only
: 这个选项令slave除了slave线程或者拥有 SUPER
权限用户之外的都不能更新数据。这能确保slave不会接受来自其他客户端的更新。这个选项是从MySQL 4.0.14开始有的。
--relay-log=file_name
: 中继日志的名字。默认名字是 host_name-relay-bin.nnn
,host_name 是slave服务器的主机名,nnn 是指中继日志的顺序号。可以用这个选项创建不依赖主机名的中继日志,或者在中继日志越来越大(不想降低 max_relay_log_size
的值)且需要将它们放在非数据文件目录下,或者想使用磁盘间的负载均衡来提高速度等情况。
--relay-log-index=file_name
: 中继日志索引文件的位置及文件名。它的默认值是 host_name-relay-bin.index
,host_name 是slave服务器主机名。
--relay-log-info-file=file_name
: slave上记录中继日志信息的文件名。默认是数据文件目录下的 `relay-log.info`
。
--relay-log-purge={0|1}
: 在不需要中继日志时禁用或启用自动清除。默认值是1(启用)。这是一个全局变量,可以用 SET GLOBAL relay_log_purge
来动态更改。这个选项从MySQL 4.1.1开始可以用。
--relay-log-space-limit=#
: 用 于加大slave上中继日志的总大小(如果值为0表示”无限”)。这在slave主机只有有限的空间时很有用。当达到这个限制后,I/O线程直到SQL线 程删除一些无用的中继日志后才会继续从master读取二进制日志事件。注意,这个限制不是绝对的:在删除中继日志之前,SQL线程可能还需要更多的二进 制日志事件。这种情况下,I/O线程会超越这个限制,直到SQL线程删除一些中继日志,因为如果不这么做的话就会导致死锁(在MySQL 4.0.13之前就是这样)。不要设置 --relay-log-space-limit
的值小于2倍 --max-relay-log-size
(如果 --max-relay-log-size
的值为0,则是 --max-binlog-size
) 的值。在这种情况下,由于已经超过 --relay-log-space-limit
了,I/O线程需要等待更多的剩余空间,但是SQL线程没有可以删除的中继日志来满足I/O线程的需求。这就会强制I/O线程暂时忽略 --relay-log-space-limit
限制。
--replicate-do-db=db_name
: 告诉slave只同步那些缺省数据库是 db_name (也就是用 USE
选中的)的语句。想要指定更多的数据库,只需多次使用该选项,每次指定一个数据库。注意,类似 UPDATE some_db.some_table SET foo='bar'
这样的跨库操作语句以及没有选中数据库的操作都不会被同步。如果必须使用跨库操作,要确保使用MySQL 3.23.28或更高,并且使用 --replicate-wild-do-table=db_name.%
选项。请仔细阅读最后面的注意事项。
: 下面是一个不能按照预期工作的例子:如果启动slave时使用 --replicate-do-db=sales
选项,并且在master上执行下列语句,那么这个 UPDATE
语句_不会_被同步:
:
USE prices;
UPDATE sales.january SET amount=amount+1000;
如果需要同步跨库操作,只需使用 --replicate-wild-do-table=db_name.%
选项。这个”只检查缺省数据库”特性的主要原因是因为想要单从一个语句中判断是否要被同步比较困难(例如,使用多表 DELETE
或者 UPDATE
,这就跨库了)。不过想要检查是否是缺省数据库却很快。
--replicate-do-table=db_name.tbl_name
: 告诉slave只同步那些指定的数据表。想要指定更多的数据表,只需多次使用该选项,每次指定一个数据表。这个选项支持跨库更新,和 --replicate-do-db
选项相反。请仔细阅读最后面的注意事项。
--replicate-ignore-db=db_name
: 告诉slave不要同步那些缺省数据库是 db_name (也就是用 USE
选中的)的语句。想要指定更多的数据库,只需多次使用该选项,每次指定一个数据库。如果有跨库操作且希望这些操作要被同步就不要使用该选项。请仔细阅读最后面的注意事项。
: 下面是一个不能按照预期工作的例子:如果启动slave时使用 --replicate-ignore-db=sales
选项,并且在master上执行下列语句,那么这个 UPDATE
语句_不会_被同步:
:
USE prices;
UPDATE sales.january SET amount=amount+1000;
想要让跨库操作能正常同步,只需使用 --replicate-wild-ignore-table=db_name.%
选项。
--replicate-ignore-table=db_name.tbl_name
: 告诉slave不要同步指定数据表的任何更新语句(甚至用同一个语句更新的其他表)。想要指定更多的数据表,只需多次使用该选项,每次指定一个数据表。这个选项支持跨库更新,和 --replicate-ignore-db
选项相反。请仔细阅读最后面的注意事项。
--replicate-wild-do-table=db_name.tbl_name
: 限制slave只同步那些匹配指定模式的数据表。模式中可以包含通配符 `%` 和 ``,它们的含义和 LIKE
模式一样。想要指定更多的数据表,只需多次使用该选项,每次指定一个数据表。请仔细阅读最后面的注意事项。
: 例如: --replicate-wild-do-table=foo%.bar%
会同步所有以 foo
开头的数据库下的以 bar
开头的数据表上的更新操作。
: 如果匹配模式是 %
,则匹配所有的表名,且应用到数据库级语句(CREATE DATABASE
, DROP DATABASE
,和 ALTER DATABASE
)。例如,使用 --replicate-wild-do-table=foo%.%
选项的话,所有匹配 foo%
模式的数据库级操作都会被同步。
: 如果想要在数据库/表模式中包含原义通配符,需要用反斜杠来转义它们。例如,想要同步 my_own%db
数据库下的所有表,但是不想同步 my1ownAABCdb
数据库下的表,就需要转义字符 ``: --replicate-wild-do-table=my_own%db
。如果是在命令行中使用这个选项,就可能需要两个反斜杠来转义,这依赖于命令行解释器。例如,在 bash
shell下,就需要输入: --replicate-wild-do-table=my\_own\%db
。
--replicate-wild-ignore-table=db_name.tbl_name
: 限制slave不同步那些匹配指定模式的数据表。想要指定更多的数据表,只需多次使用该选项,每次指定一个数据表。请仔细阅读最后面的注意事项。
: 例如,--replicate-wild-ignore-table=foo%.bar%
就不会同步所有以 foo
开头的数据库下的以 bar
开头的数据表上的更新操作。
: 想要了解匹配模式如何工作的,请查看 --replicate-wild-ignore-table
选项的具体描述。模式中包含原义通配符的规则和 --replicate-wild-ignore-table
选项一样。
--replicate-rewrite-db=from_name->to_name
: 告诉slave把在master上的缺省数据库 from_name (只有用 USE
选中的)转换成 to_name 。只有涉及到数据表的语句(不包括类似 CREATE DATABASE
, DROP DATABASE
,和 ALTER DATABASE
)才会被同步,并且只针对master上缺省数据库为 from_name 的情况。这个选项不支持跨库操作。注意,数据库名字转换先于 --replicate-*
规则之前测试。如果是在命令行中使用这个选项,需要把 `>’
字符用引号引用起来。例如:
shell> mysqld --replicate-rewrite-db="olddb->newdb"
--replicate-same-server-id
: 该选项用于slave之上。通常使用它的默认值0,用于避免无限同步循环。如果设置为1,那么slave就不会忽略那些跟它有同样服务器编号的更新日志了;通常它只用于比较罕见的配置中。如果启用 --log-slave-updates
选项,则不能设置为1。注意,从MySQL 4.1开始,slave的I/O线程默认不把包含slave的服务器编号的二进制日志写到中继日志中(相对4.0这能节省磁盘使用)。因此想要在4.1中使用 --replicate-same-server-id
选项,在slave读取自己的更新事件让SQL线程来执行之前要确保启动slave时使用该选项。
--report-host=host
: 在salve注册时要报告的master主机名或IP地址。在master上执行 SHOW SLAVE HOSTS
语句时就会显示出来了。如果不想slave注册到master就无需设置这个选项。注意,这在slave连接到master之后,只根据这个配置master还不能直接从TCP/IP套接字中读取slave的IP地址。因为存在 NAT
或者其他路由机制,这个IP信息还不足以在master或者其他主机上连接到slave上。这个选项是从MySQL 4.0.0开始可以用的。
--report-port=port_number
: 连 接到slave的TCP/IP端口,在slave注册到master时用的到。除非slave在非默认端口上监听或者从master或其他客户端上到连接 到slave使用的是特定的隧道,否则无需设置这个值。如果不确定,就不要设置它。这个选项是从MySQL 4.0.0开始可以用的。
--skip-slave-start
: 告诉slave服务器在启动时不要运行slave线程。只需使用 START SLAVE
语句来启动slave线程。
--slave_compressed_protocol={0|1}
: 如果它设置为1,并且maste/slave都支持的话,就采用压缩协议传输数据。
--slave-load-tmpdir=file_name
: slave创建临时文件的目录。这个选项值默认地和系统变量 tmpdir
的值一样。slave的SQL线程同步 LOAD DATA INFILE
语句时,它从中继日志中提取出要被加载的文件放到临时文件中,然后把它们加载到slave中。如果在master上加载的文件很大,那么slave上的临时文件也会很大。因此建议在slave上指定这个选项时把它放在剩余空间比较多的文件系统上。这是,最好也指定 --relay-log
到那个文件系统中,因为中继日志可能也会很大。--slave-load-tmpdir
必须指向基于磁盘的文件系统,而不能是基于内存的文件系统:slave可能会在机器重启后同步 LOAD DATA INFILE
语句时需要用到这个临时文件。这个目录同样不能在会被操作系统的启动进程清除的目录下。
--slave-net-timeout=seconds
: salve放弃读之后等待多少秒再次从master读取更多的数据,考虑到了连接断开,尝试重连的情况。第一次重试会在超时后立刻执行。重试的时间间隔由选项 --master-connect-retry
控制。
--slave-skip-errors= [err_code1,err_code2,... | all]
: 通常,发生错误时同步就会停止,以提供手工解决数据不一致的情况。这个选项告诉slave的SQL线程当执行语句时返回的错误代码在该列表中时继续运行。
: 除非真正的理解了为什么会产生相应的错误后,否则不要设置这个选项。如果同步设置以及客户端程序都没有bug,并且也不是MySQL自 身的bug的话,那么就不会出现让同步停止的错误了。不加区分地使用这个选项,会导致slave无可救药地背离master的同步,并且你也不知道这是为 什么。
: 可以在从slave的错误日志并且在slave上执行 SHOW SLAVE STATUS
语句的结果中就能看到错误代码了。服务器错误代码详情请看”22 Error Handling in MySQL“。
: 你也可以(最好不要)使用非常不推荐使用的值 all
,它能忽略所有的错误信息,不管什么情况都继续保持同步。不消说,如果使用这个选项值,就不可能期待有数据的完整性了。这种情况下,就不能抱怨slave的数据无论在哪个地方都和master不接近了。已经警告过你了。例如:
:
--slave-skip-errors=1062,1053
--slave-skip-errors=all
--replicate-*
模式根据以下规则来决定一个语句是要执行还是被忽略:
- 是否有
--replicate-do-db
或--replicate-ignore-db
规则?
- 是:测试
--binlog-do-db
和--binlog-ignore-db
选项(详情请看”5.9.4 The Binary Log“)。测试结果? - 忽略:忽略并且退出。
- 执行:不立刻执行,推迟判断,到下一步。
- 否:到下一步。
- 是否有
--replicate-*-table
规则?
- 否:执行并且退出。
- 是:走到下一步。只有要被更新的表才和这个规则作比较(
INSERT INTO sales SELECT * FROM prices
:中只有sales
和规则比较)。如果有好几个表一起被更新(多表语句),第一个匹配的表(匹配 `do` 或 `ignore`)胜出。也就是说,只有第一个表和规则作比较。然后,如果还没有产生任何决定,就比较第二个表,以此类推。
- 是否有
--replicate-do-table
规则?
- 是:这个表是否匹配这些规则?
- 是:执行并且退出。
- 否:走到下一步。
- 否:走到下一步。
- 是否有
--replicate-ignore-table
规则?
- 是:这个表是否匹配这些规则?
- 是:忽略并且退出。
- 否:走到下一步。
- 否:走到下一步。
- 是否有
--replicate-wild-do-table
规则?
- 是:这个表是否匹配这些规则?
- 是:执行并且退出。
- 否:走到下一步。
- 否:走到下一步。
- 是否有
--replicate-wild-ignore-table
规则?
- 是:这个表是否匹配这些规则?
- 是:忽略并且退出。
- 否:走到下一步。
- 否:走到下一步。
- 没有匹配
--replicate-*-table
规则。是否有其他表匹配这些规则?
- 是:循环查找匹配。
- 否:已经测试所有要被更新的表且找不到任何匹配规则。是否有
--replicate-do-table
或--replicate-wild-do-table
规则? - 是:忽略并且退出。
- 否:执行并且退出。
6.9 同步 FAQ
问: master还在运行中,如何在不停止它的情况下配置slave?
答: 需要设计几个选项参数。如果已经有了master的备份并且记录了数据快照二进制日志文件名以及偏移位置(运行 SHOW MASTER STATUS
查看结果),执行以下步骤:
- 确定slave指定了一个唯一的服务器编号。
- 在slave上执行如下语句,把一些选项值改成实际值:
mysql> CHANGE MASTER TO
-> MASTER_HOST='master_host_name',
-> MASTER_USER='master_user_name',
-> MASTER_PASSWORD='master_pass',
-> MASTER_LOG_FILE='recorded_log_file_name',
-> MASTER_LOG_POS=recorded_log_position;
- 在slave上执行
START SLAVE
语句。
如果事先没有备份master的数据,可以用以下方法快速创建一个备份。以下所有的操作都是在master上。
- 提交语句:
mysql> FLUSH TABLES WITH READ LOCK;
- 确保这个锁一直存在,执行以下命令(或者其他类似的):
shell> tar zcf /tmp/backup.tar.gz /var/lib/mysql
- 执行以下语句,记录下输出的结果,后面要用到:
mysql> SHOW MASTER STATUS;
- 释放锁:
mysql> UNLOCK TABLES;
上述步骤的另一个办法是创建master的SQL转储文件。只需在master上执行 mysqldump --master-data
命令,然后将导出来的SQL转储文件载入slave。不过,这么做会制作二进制数据快照的方式慢一点。
无论使用上述两种方法的哪种,最后都能创建master的数据快照然后记录二进制日志文件名以及偏移位置。可以在好几的其他的slave上使用同一 个备份的二进制数据快照。得到master的快照后,只要master的二进制日志完好无损,接着就能开始设置slave了。两个决定是否需要等待较长时 间的限制是:在master上磁盘空间保存二进制日志,以及slave从master抓取更新事件。
也可以使用 LOAD DATA FROM MASTER
。这个语句可以很方便地在slave上取得数据快照并且能立刻调整二进制日志文件名以及偏移位置。在将来,我们推荐用 LOAD DATA FROM MASTER
来设置slave。警告,它只能用于 MyISAM
表,并且可能会保持一个较长时间的读锁。由于它还没达到所期望的高效率,因此如果数据表很大,最好还是在执行完 FLUSH TABLES WITH READ LOCK
后直接制作二进制数据快照。
问:是否slave总是需要连接到master?
答:不,非必需。slave可以好几小时甚至几天关闭或者不连接master,然后重连再取得更新操作日志。例 如,可以在拨号链接上设置一个mater/slave关系,拨号可能只是零星的不定期的连接。这种做法隐含的是,在任何指定的时间里,除非使用特殊的度量 标准,否则slave不能保证总是能和master保持同步。在未来,有个选项可以阻止master,除非至少有一个slave在同步中。
问:怎么知道比master晚了多少?也就是说,怎么知道slave最后同步的时间?
答:如果slave是4.1.1或者更高,只需查看 SHOW SLAVE STATUS
结果中的 Seconds_Behind_Master
字段。对于老版本,可以用以下办法。如果在slave上执行 SHOW PROCESSLIST
语句结果显示SQL线程(对MySQL 3.23则是slave线程)正在运行,这就意味着该线程至少从master读取一个更新操作事件。详情请看”6.3 Replication Implementation Details“。
当SQL线程执行一个master上读取的更新操作事件时,它把自己的时间改成事件的时间(这也就是 TIMESTAMP
也要同步的原因)。在
SHOW PROCESSLIST
结果中的 Time
字段中,slave的SQL线程显示的秒数就是最后一次同步的时间戳和slave本机的实际时间相差秒数。可以根据这个值来判断最后同步的时间。注意,如果slave已经从master断开好几个小时了,然后重新连接,就能看到slave的
SHOW PROCESSLIST
结果中的SQL线程的Time
字段的值类似3600。这是因为slave正在执行一个小时前的语句。
问:如何强制master在slave赶上全部更新之前阻止更新操作?
答:执行以下步骤:
- 在master上,执行以下语句:
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
记录下结果中的日志文件名以及偏移位置,它们是同步的坐标值。
- 在slave上,提交以下语句,
MASTER_POS_WAIT()
函数的参数的值就是前面取得的同步坐标值:
mysql> SELECT MASTER_POS_WAIT('log_name', log_offset);
SELECT
语句会阻止更新,直到slave同步到了上述日志文件及位置。在这个时候,slave就和master保持同步了,并且这个语句就会返回。
- 在master上,执行以下语句允许master重新处理更新操作:
mysql> UNLOCK TABLES;
问:设置一个双向复制时要注意什么问题?
答:MySQL同步目前还不支持任何在master和slave上的分布式(跨服务器)更新锁协议以保证操作的 原子性。也就是说,存在这样的可能性:客户端A在并存的master 1上做了一个更新,同时,在它同步到并存master 2上之前,客户端B在master 2上可能也做了一个和客户端A在master 1上不同的更新操作。因此,当客户端A所做的更新同步到master 2时,它将产生和master 1上不同的数据表,尽管master 2上的更新操作也全都同步到master 1上去。这意味着除非能确保所有的更新都能以任何顺序安全地执行,否则不要使用双向同步,或者除非注意在客户端程序中的不知原因的无序更新操作。
同时也要意识到在所关心的更新问题上,双向同步实际上并不能很大地改善性能(甚至没有)。两个服务器都需要执行同样数量的更新操作,在一台服务器上 也是。唯一区别的是,可能这样做会减少一些锁争夺,因为来自其他服务器的更新操作都会被串行地放到slave线程中。甚至这种好处还可以作为网络延迟的补 偿。
问:我如何利用同步来提高系统性能?
答:需要安装一个服务器作为master并且把所有的写操作直接放在这上面。然后配置多个廉价的使用机架磁盘的slave,把读操作分配给master和slave。还可以在启动slave时使用 --skip-innodb
, --skip-bdb
, --low-priority-updates
,和 --delay-key-write=ALL
选项来提高slave端的性能。这种情况下,slave会使用非事务的 MyISAM
表来代替 InnoDB
和 BDB
表,已取得更快速度。
问:如何准备客户端应用程序的代码来适应同步应用?
答:如果代码中负责存取数据库的部分已经被合理地抽象化/模块化了,将它们转化成适用运行于同步环境中将会很平 滑和简单。只需要修改数据库存取实现部分,把所有的写操作放到master上,把所有的读操作放到master或者slave上。如果你的代码还没达到这 个层次的抽象化,那么这将成为整理代码的机会和动机。可以使用类似以下函数创建封装类库或者模块:
safe_writer_connect()
safe_reader_connect()
safe_reader_statement()
safe_writer_statement()
每个函数名的 safe_
表示它们会处理所有的错误情况。可以使用其他函数名。重要的是,要为读连接、写连接、读、写定义好统一的接口。
然后将客户端代码转换成使用封装的类库。已开始可能是很痛苦且麻烦的,不过在将来长期运行中就能得到回报了。所有使用上述方法的应用程序都会在 master/slave配置中有优势,即使包含多个slave。这些代码将很容易维护,一些额外的麻烦也会很少。自豪需要修改一个或者两个函数;例如, 想要记录每个语句执行了多长时间,或者在上千个语句中哪个出现错误了。
如果已经写了很多代码,你可能想要自动转换它们,那么可以使用MySQL发布的 replace
工具,或者自己写转换脚本。理想地,你的代码已经使用了统一的编程风格。如果不是,最好重写它们,或者可以遍历检查一下,手工规范化一下代码风格。
问:MySQL同步何时且有多少能提高系统性能?
答:MySQL同步对于频繁读但不频繁写的系统很有好处。理论上来讲,使用单一master/多slave的配置,就可以通过这个方法来衡量系统:增加更多的slave直到用完所有的网络带宽或者master的更新操作增长到了不能再处理的点了。
想要知道增加多少个slave之后得到的性能才能平稳,以及能提高多少性能,就需要知道查询模式,并且根据经验对典型的master和slave做读(每秒读或 max_reads
)和写(max_write
)基准测试得到它们之间的关系。下例展示了一个理想系统取得的性能的简单计算方法。
设定系统负载由10%写和90%读组成,我们已经通过基准测试确定 max_reads
是1200 – 2 * max_writes
。换句话说,系统可以达到每秒做没有写的1200次读操作,写操作平均是读操作的2倍慢,它们之间的关系是线性的。让我们假设master和每个slave都有同样的容量,有一个master和N个slave。每个服务器(master或slave):
reads = 1200 - 2 * writes
reads = 9 * writes / (N + 1)
(读是分开的,但是所有写是在所有的服务器上的)
9 * writes / (N + 1) + 2 * writes = 1200
writes = 1200 / (2 + 9/(N+1))
最后的等式说明了N个slave的最大写数量,给它每分钟的最高读频率1200和1次写9次读的机率。
分析结论比率如下:
- 如果 N = 0(意味着没有同步),系统大致可以处理每秒 1200/11 = 109 次写。
- 如果 N = 1,增加到每秒 184 次写。
- 如果 N = 8,增加到每秒 400 次写。
- 如果 N = 17,增加到每秒 480 次写。
- 最终,随着N接近无穷大(我们的预算为负无穷大),则可以达到几乎每秒 600 次写,大约提高系统吞吐量 5.5 倍。尽管如此,当有8台服务器时,已经提高了4倍了。
注意,上面的计算是假设了网络带宽无穷大,并且忽略了一些系统中比较大的因素。在很多情况下,当系统增加 N 个同步slave之后,是无法精确计算出上述预计结果的。不过,先看看下列问题将有助于你知道是否有和有多少系统性能上的改善:
- 系统读/写得比率是多少?
- 减少读操作后一个服务器能增加处理多少写操作?
- 你的网络带宽足够给多少slave使用?
问:如何利用同步提供冗余/高可用性?
答:使用当前已经可用的特性,可以配置一个master和一个(或多个)slave,并且写一个脚本监控master是否运行着。然后通知应用程序和slave在发现错误时修改master。一些建议如下:
- 使用
CHANGE MASTER TO
语句告诉slave修改master。 - 一个让应用程序定位master所在主机的办法就是给master使用动态DNS。例如bind就可以用
`nsupdate`
来动态更新DNS。 - 使用
--log-bin
选项,不使用--log-slave-updates
选项来启动slave。这样就能让slave运行STOP SLAVE
;RESET MASTER
语句后随时准备变成master,并且在其他slave上运行CHANGE MASTER TO
。例如,有以下配置方案:
WC
v
WC----> M
/ |
/ |
v v v
S1 S2 S3
M 表示masetr,S 表示slave,WC表示提交读写操作的客户端;只提交读操作的客户端没有表示出来,因为它们无需切换。S1,S2,S3都是使用
--log-bin
选项,不用 --log-slave-updates
选项运行的slave。由于除非指定 --log-slave-updates
参数,否则从master读到的更新操作都不会记录到二进制日志中,因此每个slave上的二进制日志都是空的。如果因为某些原因 M 不能用了,可以指定一个slave作为master。例如,如果指定S1,则所有的WC都要重定向到S1上,S2和S3都需要从S1上同步。
确定所有的slave都已经处理完各自的中继日志了。在每个slave上,提交 STOP SLAVE IO_THREAD
语句,然后检查 SHOW PROCESSLIST
的结果直到看到 Has read all relay log
了。当所有的slave都这样子之后,就可以按照新的方案设置了。在slave S1上提交
STOP SLAVE
和 RESET MASTER
语句将其提升为master。
在其他slave S2和S3上,提交 STOP SLAVE
和 `CHANGE MASTER
TO MASTER_HOST=‘S1’(
‘S1’代表S1的真实主机名) 语句修改master。把S2,S3如何连接到S1的参数(用户,密码,端口等)都附加到
CHANGE MASTER后面。在
CHANGE MASTER中无需指定S1的二进制日志文件名和偏移位置:因为
CHANGE MASTER默认就是第一个二进制日志和偏移位置4。最后,在S2和S3上提交
START SLAVE` 语句。
然后让所有的WC都把他们的语句重定向到S1上。从这个时候开始,从所有的WC发送到S1上的更新语句都会写到S1的二进制日志中,它们包含了从M死掉之后发送到S1的全部更新语句。
配置结果如下:
WC
/
|
WC | M(unavailable)
|
|
v v
S1<--S2 S3
^ |
+-------+
当M又起来了之后,只需在M上提交和在S2和S3上的一样的 CHANGE MASTER
语句,将它变成一个slave并且读取自从它死掉之后的全部WC提交的更新操作。想要把M重新变成master(例如因为它的性能更好),就执行类似上面 的操作,把S1当作失效了,把M提升为新的master。在这个步骤中,别忘了在把S2和S3修改成为M的slave之前在M上运行 RESET MASTER
语句。否则的话,它们会从M开始失效的那个时刻开始读取WC提交的更新操作日志。
现在我们就运行着一个完整的自动选择master的MySQL同步系统,不过在它准备好之前,需要创建自己的监控工具。
6.10 同步疑难解答
如果按照上述步骤设定好同步之后,它不能正常工作的话,首先检查以下内容:
- 查看一下错入日志信息。不少用户都在这方面做得不够好以至于浪费时间。
- master是否在记录二进制日志?用
SHOW MASTER STATUS
检查一下状态。如果是,Position
的值不为零;否则,确定master上使用了log-bin
和server-id
选项。 - slave是否运行着?运行
SHOW SLAVE STATUS
语句检查Slave_IO_Running
和Slave_SQL_Running
的值是否都是。如果不是,确定是否用同步参数启动slave服务器了。 - 如果slave正在运行,它是否建立了到master的连接?运行
SHOW PROCESSLIST
语句检查I/O和SQL线程的State
字段值。详情请看”6.3 Replication Implementation Details“。如果I/O线程状态为Connecting to master
,就检查一下master上同步用户的权限是否正确,master的主机名,DNS设置,master是否确实正在运行着,以及slave是否可连接到master,等等。 - 如 果slave以前运行着,但是现在停止了,原因通常是一些语句在master上能成功但在slave上却失败了。如果salve已经取得了master的 全部快照,并且除了slave线程之外不会修改他的数据,那么应该不会发生这样的情形。如果确实发生了,那么可能是一个bug或者你碰到了”6.7 Replication Features and Known Problems“中提到的同步限制之一。如果是一个bug,那么请按照”6.11 Reporting Replication Bugs“的说明报告它。
- 如果一个语句在master上成功了,但是在slave上却失败了,并且这时不能做一次完整的数据库再同步(也就是删除slave上的数据,重新拷贝master的快照),那么试一下:
- 判断slave的数据表是否和master的不一样。试着找到怎么会发生这种情况,然后将slave的表同步成和master一样之后运行
START SLAVE
。 - 如果上述步骤不生效或者没有执行,试着这个语句是否能被手工安全地运行(如果有必要),然后忽略master的下一个语句。
- 如果决定要忽略master的下一个语句,只需在slave上提交以下语句:
mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = n;
mysql> START SLAVE;
如果下一个语句没有使用 AUTO_INCREMENT
或 LAST_INSERT_ID()
,那么 n
的值应为为 1
。否则,它的值为 2
。设定为 2
是因为 AUTO_INCREMENT
或 LAST_INSERT_ID()
在master的二进制日志中占用了2条日志。
- 如果确定slave精确地同步master了,并且没有除了slave线程之外的对数据表的更新操作,则推断这是因为bug产生的差异。如果是使用最近的版本,请报告这个问题,如果使用的是旧版本,试着升级一下。
6.11 报告同步Bugs
当确定没有包含用户的错误,并且同步还是不能正常工作或者不稳定,就可以报告bug了。我们需要你尽量多的跟踪bug的信息。请花点时间和努力准备一个好的bug报告。
如果有一个演示bug的可重现测试案例的话,请进入我们的bug数据库http://bugs.mysql.com/。如果碰到一个幽灵般的问题(不可重现),请按照如下步骤:
- 确定没有包含用户错误。例如,在slave线程以外更新slave的数据,那么数据就会不能保持同步,也可能会导致违反更新时的唯一键问题。这是外部干涉导致同步失败的问题。
- 使用
--log-slave-updates
和--log-bin
选项启动slave。这会导致slave将从master读取的更新操作写到自己的二进制日志中。 - 在重设同步状态之前保存所有的证据。如果我们没有任何信息或者只有粗略的信息,这将很难或者不可能追查到这个问题。需要收集以下证据:
- master上的所有二进制日志
- slave上的所有二进制日志
- 发现问题时,在master上执行
SHOW MASTER STATUS
的结果 - 发现问题时,在master上执行
SHOW SLAVE STATUS
的结果 - 记录master和slave的错误日志
- 用
mysqlbinlog
来检查二进制日志。例如,用以下方法有助于找到有问题的查询:
shell> mysqlbinlog -j pos_from_slave_status
/path/to/log_from_slave_status | head
一旦收集好了问题的证据,首先将它隔离到一个独立的测试系统上。然后在我们的bug数据库http://bugs.mysql.com/上进可能详细地报告问题。