MySQL 支持一台主服务器同时向多台从服务器进行复制,从服务器同时也可以作为其他服务器的主服务器,实现链状的复制。 一、异步复制 (1)确保主从服务器上安装了相同版本的数据库。 (2)在主服务器上,设置一个复制使用的账户,并授予REPLICATION SLAVE 权限。这里创建一个复制用户repl: mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY '123'; (3)修改主数据库服务器的配置文件my.cnf,开启BINLOG,并设置server-id 的值。这两个参数的修改需要重新启动数据库服务才可以生效。 My.cnf 中修改: [mysqld] log-bin=mysql-bin server-id=1 [root@CentOS 3306]# ./stop.sh [root@CentOS 3306]# ./start.sh (4)在主服务器上,设置读锁定有效,这个操作是为了确保没有数据库操作,以便获得一个一致性的快照: mysql> flush tables with read lock; ##这个session不要断开 (5)然后得到主服务器上当前的二进制日志名和偏移量值。这个操作的目的是为了在从数据库启动以后,从这个点开始进行数据的恢复。 mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000001 | 120 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) (6)现在主数据库服务器已经停止了更新操作,需要生成主数据库的备份,备份的方式有很多种,可以直接在操作系统下cp 全部的数据文件到从数据库服务器上,也可以通过mysqldump 导出数据等。 方法一:mysqldump -uroot -p -S /mydata/data/3306/mysql_3306.sock -l -F test >test.dmp 方法二: [root@CentOS 3306]# ./stop.sh [root@CentOS data]# cp -R 3306 3306_bak (7)主数据库的备份完毕后,主数据库可以恢复写操作,剩下的操作只需要在从服务器上执行: [root@CentOS 3306]# ./start.sh mysql> unlock tables; (8)将主数据库的一致性备份恢复到从数据库上。如果是使用.tar 打包的文件包,只需要解开到相应的目录即可。 方法一:mysql -uroot -p -S /mydata/data/3307/mysql_3307.sock test < test.dmp ##如果是用mysqldump导入,就需要先做(9)(10)步。 方法二:替换文件包括: [root@CentOS 3306]# ll 总用量 176208 -rw-rw----. 1 mysql mysql 79691776 12月 5 00:04 ibdata1 -rw-rw----. 1 mysql mysql 50331648 12月 5 00:04 ib_logfile0 -rw-rw----. 1 mysql mysql 50331648 11月 19 04:35 ib_logfile1 drwx------. 2 mysql mysql 4096 11月 19 04:35 mysql drwx------. 2 mysql mysql 4096 11月 19 04:35 performance_schema drwx------. 2 mysql mysql 4096 12月 4 18:14 test (9)修改从数据库的配置文件my.cnf,增加server-id 参数。注意server-id 的值必须是唯一的,不能和主数据库的配置相同,如果有多个从数据库服务器,每个从数据库服务器必须有自己唯一的server-id 值。 my.cnf 中修改: [mysqld] server-id=2 log-bin=mysql-bin relay-log=mysql-relay-bin (10)在从服务器上,使用--skip-slave-start 选项启动从数据库,这样不会立即启动从数据库服务上的复制进程,方便我们对从数据库的服务进行进一步的配置: [root@CentOS 3307]# mysqld_safe --defaults-file=/mydata/data/3307/my.cnf --skip-slave-start 2>&1 > /dev/null & (11)对从数据库服务器做相应设置,指定复制使用的用户,主数据库服务器的IP、端口以及开始执行复制的日志文件和位置等,具体语法如下: 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; 举例说明如下: CHANGE MASTER TO MASTER_HOST='10.10.10.8', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='123', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=120; (12)在从服务器上,启动slave 线程: mysql> start slave; (13)这时slave 上执行show processlist 命令将显示类似如下进程: mysql> show processlist \G *************************** 1. row *************************** Id: 2 User: root Host: localhost db: NULL Command: Query Time: 0 State: init Info: show processlist *************************** 2. row *************************** Id: 3 User: system user Host: db: NULL Command: Connect Time: 74 State: Waiting for master to send event Info: NULL *************************** 3. row *************************** Id: 4 User: system user Host: db: NULL Command: Connect Time: 44 ##从服务器当前执行的SQL 时间戳与系统时间之间的差距,单位是秒。也就是复制延迟多少秒! State: Slave has read all relay log; waiting for the slave I/O thread to update it Info: NULL 3 rows in set (0.00 sec) mysql> show slave status \G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event ##显示slave的当前状态 Master_Host: 10.10.10.8 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000005 ##显示当前读取的master节点二进制日志的文件名称 Read_Master_Log_Pos: 120 ##显示当前读取的master节点二进制日志位置 Relay_Log_File: mysql-relay-bin.000008 ##显示当前slave节点正在处理的中继日志的文件名称 Relay_Log_Pos: 283 ##显示当前slave节点正在处理的中继日志位置 Relay_Master_Log_File: mysql-bin.000005 Slave_IO_Running: Yes ##Slave_IO_Running:此进程负责从服务器(Slave)从主服务器(Master)上读取BINLOG日志,并写入从服务器上的中继日志中。 Slave_SQL_Running: Yes ##Slave_SQL_Running:此进程负责读取并且执行中继日志中的BINLOG 日志。 Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 120 ##显示当前slave节点正在应用的日志文件位置 Relay_Log_Space: 503 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 ##预估从库落后主库的秒数! Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: bc0f7676-9cca-11e5-8bf0-000c29395546 Master_Info_File: /mydata/data/3307/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 1 row in set (0.00 sec) 主库上: mysql> show processlist \G *************************** 1. row *************************** Id: 1 User: root Host: localhost db: test Command: Query Time: 0 State: init Info: show processlist *************************** 2. row *************************** Id: 4 User: repl Host: 10.10.10.8:36089 db: NULL Command: Binlog Dump Time: 942 State: Master has sent all binlog to slave; waiting for binlog to be updated Info: NULL 2 rows in set (0.00 sec) mysql> show slave hosts; +-----------+------+------+-----------+--------------------------------------+ | Server_id | Host | Port | Master_id | Slave_UUID | +-----------+------+------+-----------+--------------------------------------+ | 2 | | 3307 | 1 | 3f8e9993-9cc8-11e5-8be0-000c29395546 | +-----------+------+------+-----------+--------------------------------------+ 1 row in set (0.00 sec) (14)也可以测试复制服务的正确性,在主数据库上执行一个更新操作,观察是否在从数据库上同步。在主数据库上test 数据库创建一个测试表,插入数据: mysql> delete from t where id in(1,2,3,4,5,6); Query OK, 18 rows affected (1.06 sec) mysql> select * from t; +------+------+ | id | name | +------+------+ | 101 | a | | 102 | b | | 103 | c | | 104 | d | | 105 | d | | 106 | d | +------+------+ 6 rows in set (0.00 sec) mysql> insert into t1 values(4,'d'); Query OK, 1 row affected (1.94 sec) mysql> select * from t1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | +------+------+ 4 rows in set (0.01 sec) (15)在从数据库上检查新表是否被创建,数据是否同步: mysql> select * from t; +------+------+ | id | name | +------+------+ | 101 | a | | 102 | b | | 103 | c | | 104 | d | | 105 | d | | 106 | d | +------+------+ 6 rows in set (0.00 sec) mysql> select * from t1; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | +------+------+ 4 rows in set (0.00 sec) 可以看到数据可以正确同步到从数据库上,复制服务配置成功完成。MySQL引入sync_binlog参数来控制binlog刷新到磁盘的频率: mysql> show variables like '%sync_binlog%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | sync_binlog | 0 | +---------------+-------+ 1 row in set (0.01 sec) 如果sync_binlog>0,则表示sync_binlog次事务提交,MySQL调用文件系统的刷新操作将binlog刷到磁盘。为了更好的保证数据的完整性和安全性,其实就是更好的保证二进制日志binlog的完整性和安全性,MySQL5.5引入了半同步复制部分的解决问题。 二、半同步复制 主库在每次事务成功提交时,并不及时反馈给前端应用用户,而是等待其中一个从库也接收到binlog事务并成功写入中继日志后,主库才返回commit操作成功给客户端。半同步模式是作为MySQL5.5的一个插件来实现的,主库和从库使用不同的插件。在前面异步复制的环境上,安装半同步复制插件即可。 (1)首先,判断MySQL服务器是否支持动态增加插件: mysql> select @@have_dynamic_loading; +------------------------+ | @@have_dynamic_loading | +------------------------+ | YES | +------------------------+ 1 row in set (0.00 sec) (2)检查MySQL的安装目录下是否存在插件,一般在$MYSQL_HOME/lib/plugin目录下 : mysql> show variables like '%plugin_dir%'; +---------------+------------------------------+ | Variable_name | Value | +---------------+------------------------------+ | plugin_dir | /usr/local/mysql/lib/plugin/ | +---------------+------------------------------+ 1 row in set (0.00 sec) [root@CentOS plugin]# pwd /usr/local/mysql/lib/plugin [root@CentOS plugin]# ll semisync_*.so -rwxr-xr-x. 1 mysql mysql 399898 9月 18 23:34 semisync_master.so -rwxr-xr-x. 1 mysql mysql 244216 9月 18 23:34 semisync_slave.so 在主库上安装插件semisync_master.so: mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (8.84 sec) mysql> select * from mysql.plugin; +----------------------+--------------------+ | name | dl | +----------------------+--------------------+ | rpl_semi_sync_master | semisync_master.so | +----------------------+--------------------+ 1 row in set (0.00 sec) 从库上安装semisync_slave.so插件: mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so'; Query OK, 0 rows affected (1.60 sec) mysql> select * from mysql.plugin; +---------------------+-------------------+ | name | dl | +---------------------+-------------------+ | rpl_semi_sync_slave | semisync_slave.so | +---------------------+-------------------+ 1 row in set (0.30 sec) (3)需要分别在主库和从库上配置参数打开半同步semi-sync: 主库参数: mysql> set global rpl_semi_sync_master_enabled=1; Query OK, 0 rows affected (0.53 sec) mysql> set global rpl_semi_sync_master_timeout=30000; ##主库在等待rpl_semi_sync_master_timeout毫秒后超时后,自动转成异步复制 Query OK, 0 rows affected (0.01 sec) 从库参数: mysql> set global rpl_semi_sync_slave_enabled=1; Query OK, 0 rows affected (0.00 sec) 注意,由于之前配置的复制是异步复制,所以需要重启一下从库上的I/O线程(如果全新配置的半同步复制则不需要): mysql> stop slave io_thread; Query OK, 0 rows affected (4.26 sec) mysql> show slave status \G *************************** 1. row *************************** Slave_IO_State: Master_Host: 10.10.10.8 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000006 Read_Master_Log_Pos: 333 Relay_Log_File: mysql-relay-bin.000011 Relay_Log_Pos: 496 Relay_Master_Log_File: mysql-bin.000006 Slave_IO_Running: No ##注意这里 Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 333 Relay_Log_Space: 832 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: bc0f7676-9cca-11e5-8bf0-000c29395546 Master_Info_File: /mydata/data/3307/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 1 row in set (0.00 sec) mysql> start slave io_thread; Query OK, 0 rows affected (0.01 sec) mysql> show slave status \G *************************** 1. row *************************** Slave_IO_State: Connecting to master Master_Host: 10.10.10.8 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000006 Read_Master_Log_Pos: 333 Relay_Log_File: mysql-relay-bin.000011 Relay_Log_Pos: 496 Relay_Master_Log_File: mysql-bin.000006 Slave_IO_Running: Connecting ##注意这里 Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 333 Relay_Log_Space: 832 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: bc0f7676-9cca-11e5-8bf0-000c29395546 Master_Info_File: /mydata/data/3307/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 1 row in set (0.00 sec) mysql> show slave status \G *************************** 1. row *************************** Slave_IO_State: Queueing master event to the relay log Master_Host: 10.10.10.8 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000006 Read_Master_Log_Pos: 333 Relay_Log_File: mysql-relay-bin.000011 Relay_Log_Pos: 496 Relay_Master_Log_File: mysql-bin.000006 Slave_IO_Running: Yes ##注意这里 Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 333 Relay_Log_Space: 716 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: bc0f7676-9cca-11e5-8bf0-000c29395546 Master_Info_File: /mydata/data/3307/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 1 row in set (2.70 sec) (4)到此半同步配置完毕,下面可以来验证一下。 主库: mysql> show status like '%semi_sync%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 1 | ##显示当前处于半同步模式的slave节点数量 | Rpl_semi_sync_master_net_avg_wait_time | 0 | | Rpl_semi_sync_master_net_wait_time | 0 | | Rpl_semi_sync_master_net_waits | 0 | | Rpl_semi_sync_master_no_times | 0 | | Rpl_semi_sync_master_no_tx | 0 | ##表示当前有0个事务不是半同步模式下从库及时响应的 | Rpl_semi_sync_master_status | ON | ##半同步复制打开 | Rpl_semi_sync_master_timefunc_failures | 0 | | Rpl_semi_sync_master_tx_avg_wait_time | 0 | | Rpl_semi_sync_master_tx_wait_time | 0 | | Rpl_semi_sync_master_tx_waits | 0 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 0 | ##表示主库当前尚未有任何一个复制是通过半同步复制的 +--------------------------------------------+-------+ 14 rows in set (0.00 sec) mysql> show variables like '%semi_sync%'; +------------------------------------+-------+ | Variable_name | Value | +------------------------------------+-------+ | rpl_semi_sync_master_enabled | ON | | rpl_semi_sync_master_timeout | 30000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_no_slave | ON | +------------------------------------+-------+ 4 rows in set (0.00 sec) 从库: mysql> show status like '%semi_sync%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Rpl_semi_sync_slave_status | ON | +----------------------------+-------+ 1 row in set (0.00 sec) mysql> show variables like '%semi_sync%'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | rpl_semi_sync_slave_enabled | ON | | rpl_semi_sync_slave_trace_level | 32 | +---------------------------------+-------+ 2 rows in set (0.09 sec) 注意:当从库网络异常时,自动切换为异步复制;当从库网络恢复正常后,会自动切换成为半同步复制。 半同步复制的“半”就体现在:虽然主库和从库的binlog日志是同步的,但是主库并不等待从库应用这部分日志就返回提交结果,这部分操作是异步的,从库的数据并不是和主库实时同步的,所以只能称为半同步,而不是完全的实时同步。 三、主要复制启动选项 log-slave-updates 这个参数用来配置从服务器上的更新操作是否写二进制日志,默认是不打开的。但是,如果这个从服务器同时也要作为其他服务器的主服务器,搭建一个链式的复制,那么就需要打开这个选项,这样它的从服务器将获得它的二进制日志以进行同步操作。这个启动参数需要和--logs-bin 参数一起使用。 master-connect-retry 这个参数用来设置在和主服务器的连接丢失的时候,重试的时间间隔,默认是60 秒,即每60 秒重试一次。 read-only 该参数用来设置从服务器只能接受超级用户的更新操作,从而限制应用程序错误的对从服务器的更新操作。 replicate-do-db、replicate-do-table、replicate-ignore-db、replicate-ignore-table 或replicate-wild-do-table 来指定从主数据库复制到从数据库的数据库或者表。有些时候用户只需要将关键表备份到从服务器上,或者只需要将提供查询操作的表复制到从服务器上,这样就可以通过配置这几个参数来筛选进行同步的数据库和表。从数据库启动的时候指定。 slave-skip-errors 此参数可以定义多个错误号,或者通过定义成all 跳过全部的错误。具体语法如下:--slave-skip-errors=[err_code1,err_code2,... | all] 如果从数据库主要是作为主数据库的备份,那么就不应该使用这个启动参数,设置不当,很可能造成主从数据库的数据不同步。但是,如果从数据库仅仅是为了分担主数据库的查询压力,且对数据的完整性要求不是很严格,那么这个选项的确可以减轻数据库管理员维护从数据库的工作量。 slave_parallel_workers MySQL5.6提供了基于schema的多线程复制,允许从库并行更新。通过设置参数slave_parallel_workers为2,让MySQL从库在复制时启动两个SQL线程。 SQL_SLAVE_SKIP_COUNTER 跳过来自主服务器的语句的命令为SET GLOBALSQL_SLAVE_SKIP_COUNTER = n,其中n 的取值为1 或者2。如果来自主服务器的更新语句不使用AUTO_INCREMENT 或LAST_INSERT_ID(),n 值应为1,否则,值应为2。原因是使用AUTO_INCREMENT 或LAST_INSERT_ID()的语句需要从二进制日志中取两个事件。 auto_increment_increment 和auto_increment_offset 在某些情况下,可能会需要使用多主复制(多台主服务器对一台从服务器)。这个时候,如果主服务器的表采用自动增长变量,那么复制到从服务器的同一张表后很可能会引起主键冲突,因为系统参数auto_increment_increment 和auto_increment_offset 默认值为1,这样多台主服务器的自增变量列迟早会发生冲突。就需要定制auto_increment_increment 和auto_increment_offset 的设置,保证多主之间复制到从数据库不会有重复冲突。比如,两个master 的情况可以按照以下设置。 ? Master1 上:auto_increment_increment = 2,auto_increment_offset = 1;(1,3,5,7…序列)。 ? Master2 上:auto_increment_increment = 2,auto_increment_offset = 0;(0,2,4,6…序列)。 四、日常管理维护 ##查看从服务器状态 mysql> show slave status \G ##启/停线程 mysql> start slave; mysql> start slave io_thread; mysql> start slave sql_thread; mysql> stop slave; mysql> stop slave io_thread; mysql> stop slave sql_thread; ##主从服务器同步维护 在某些繁忙的OLTP(在线事务处理)系统上,由于主服务器更新频繁,而从服务器由于各种原因(比如硬件性能较差)导致更新速度较慢,从而使得主从服务器之间的数据差距越来越大,最终对某些应用产生影响。在这种情况下,我们就需要定期地进行主从服务器的数据同步,使得主从数据差距能够减到最小。常用的方法是:在负载较低的时候暂时阻塞主数据库的更新,强制主从数据库更新同步。具体操作步骤如下。 (1)在主服务器上,执行以下语句(注意,会阻塞主数据库的所有更新操作): mysql> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.03 sec) mysql> SHOW MASTER STATUS; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000006 | 545 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) ##记录SHOW 语句的输出的日志名和偏移量,这些是从服务器复制的目的坐标。 (2)在从服务器上,执行下面语句,其中MASTER_POS_WAIT()函数的参数是前面步骤中得到的复制坐标值: mysql> select MASTER_POS_WAIT('mysql-bin.000006','545'); +-------------------------------------------+ | MASTER_POS_WAIT('mysql-bin.000006','545') | +-------------------------------------------+ | 0 | +-------------------------------------------+ 1 row in set (0.02 sec) ##这个SELECT 语句会阻塞直到从服务器达到指定的日志文件和偏移量后,返回0,如果返回-1,则表示超时退出。查询返回0 时,则从服务器与主服务器同步。 (3)在主服务器上,执行下面的语句允许主服务器重新开始处理更新: mysql> UNLOCK TABLES; Query OK, 0 rows affected (0.02 sec) ##切换主从服务器 假设有一个复制的环境,一个主数据库服务器M,两个从数据库服务器S1、S2 同时指向主数据库服务器M。 (1)首先要确保所有的从数据库都已经执行了relay log 中的全部更新,在每个从服务器上,执行STOP SLAVE IO_THREAD,然后检查SHOW PROCESSLIST 的输出,直到看到状态是Has read all relay log,表示更新都执行完毕。 mysql> STOP SLAVE IO_THREAD; mysql> SHOW PROCESSLIST \G (2)在从数据库S1 上,执行STOP SLAVE 停止从服务,然后RESET MASTER 重置成主数据库。 mysql> STOP SLAVE; mysql> reset master; mysql> show master status; (3)在S2 上,执行STOP SLAVE 停止从服务,然后执行CHANGE MASTER TO MASTER_HOST= 'S1'重新设置主数据库,然后再执行START SLAVE 启动复制。 mysql> STOP SLAVE; mysql> CHANGE MASTER TO MASTER_HOST = '192.168.1.101'; mysql> start slave; (4)通知所有的客户端将应用指向S1,这样客户端发送的所有的更新语法写入到S1 的二进制日志。 (5)删除新的主数据库服务器上的master.info 和relay-log.info 文件,否则下次重启的时候还会按照从服务器启动。 (6)最后,如果M 服务器可以修复,则可以按照S2 的方法配置成S1 的从服务器。 注意:上面测试的步骤是默认S1 是打开log-bin 选项的,这样重置成主数据库后可以将二进制日志传输到其他从服务器。其次,S1 上没有打开log-slave-updates 参数,否则重置成主数据库后,可能会将已经执行过的二进制日志重复传输给S2,导致S2 的同步错误。