初识 MySQL 5.5 半同步复制

背景:
MySQL5.5之前的复制都是异步复制,在服务器崩溃时丢失事务是使用异步复制不可避免的结果。而5.5的一项新功能:半同步复制可以限制事务丢失的数量。半同步复制的原理是:提交事务的线程会被锁定,直到至少一个Slave收到这个事务,由于事务的事件在被提交到存储引擎之后才被发送到Slave上,所以事务的丢失数量可以下降到最多每线程一个。

安装、配置:半同步复制模式必须在主服务器和从服务器端同时启用,否则主服务器默认使用异步复制模式。

1,在Master上装插件:
install plugin rpl_semi_sync_master soname 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled=ON;
在my.cnf配置文件里,加入 rpl_semi_sync_master_enabled = 1

2,在Slave上装插件:
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled =ON;
在my.cnf配置文件里,加入rpl_semi_sync_slave_enabled = 1

3,和异步复制设置步骤一样。(帐号,Change。)这样半同步就算完成。

配置成功后,从的日志里面会有
121210  7:28:43 [Note] Slave I/O thread: Start semi-sync replication to master 'repl@192.168.222.222:3306' in log 'mysql-bin.000001' at position 107

参数:
当所有的Slave崩溃,或则断开,甚至是只有Master没有Slave(不可能)。从而Slave接受不到Master的事务,导致M得不到S返回的确认信息。M会一直等待。这里有2个参数可以设置:
Master上:

rpl_semi_sync_master_enabled:表示在 master 上已经开启半同步复制模式。
rpl_semi_sync_master_timeout :为了防止半同步复制在没有收到S发出的确认发生堵塞,该可以设置一个计时器,用来设置超时,超过这个时间值没有收到信息,则切换到异步复制,执行操作。(默认为10000毫秒,等于10秒,这个参数动态可调,表示主库在某次事务中,如果等待时间超过10秒,那么则降级为异步复制模式,不再等待SLAVE从库。如果主库再次探测到,SLAVE从库恢复了,则会自动再次回到半同步复制模式。)
rpl_semi_sync_master_wait_no_slave :当一个事务被提交,但是Master没有Slave连接,这时M不可能收到任何确认信息,但M会在时间限制范围内继续等待。如果没有Slave链接,会切换到异步复制。(是否允许master每个事务提交后都要等待slave的接收确认信号。默认为on,每一个事务都会等待。如果为off,则slave追赶上后,也不会开启半同步复制模式,需要手工开启。)
Slave上:
rpl_recovery_rank:当 slave 从库宕机后,假如 Relay-Log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log,并且重新从 MASTER 上获取日志,这样保证 relay-log 的完整。默认情况下该功能是关闭的, relay_log_recovery 的值设置为 1 时,将可在 slave从库上开启该功能。

mysql> show variables like '%rpl%';
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_recovery_rank                  | 0     |
| rpl_semi_sync_master_enabled       | ON    |
| rpl_semi_sync_master_timeout       | 10000 |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
+------------------------------------+-------+
5 rows in set (0.00 sec)
mysql> show variables like 'rpl%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_recovery_rank               | 0     |
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
3 rows in set (0.00 sec)

状态:
如何知道是半同步复制?

mysql> show global status like 'rpl_semi%';
+--------------------------------------------+--------+
| Variable_name                              | Value  |
+--------------------------------------------+--------+
| Rpl_semi_sync_master_clients               | 1      |
| Rpl_semi_sync_master_net_avg_wait_time     | 40203  |
| Rpl_semi_sync_master_net_wait_time         | 361832 |
| Rpl_semi_sync_master_net_waits             | 9      |
| Rpl_semi_sync_master_no_times              | 1      |
| Rpl_semi_sync_master_no_tx                 | 1      |
| Rpl_semi_sync_master_status                | ON     |
| Rpl_semi_sync_master_timefunc_failures     | 0      |
| Rpl_semi_sync_master_tx_avg_wait_time      | 402    |
| Rpl_semi_sync_master_tx_wait_time          | 2011   |
| Rpl_semi_sync_master_tx_waits              | 5      |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0      |
| Rpl_semi_sync_master_wait_sessions         | 0      |
| Rpl_semi_sync_master_yes_tx                | 4      |
+--------------------------------------------+--------+
14 rows in set (0.00 sec)
mysql> show global status like 'rpl_semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

解释:
Rpl_semi_sync_master_clients:说明支持和注册半同步复制的已链接Slave数。
Rpl_semi_sync_master_status:ON是活动状态(半同步),OFF是非活动状态(异步),要么是他没有启用或则已恢复到异步复制状态。用于指示主服务器使用的是异步复
制模式,还是半同步复制模式。
Rpl_semi_sync_master_yes_tx:成功提交数量。
Rpl_semi_sync_master_no_tx :不成功提交数量。
Rpl_semi_sync_slave_status :Slave上的半同步复制状态,ON表示已经被启用,OFF表示非活动状态。

测试:
复制正常的情况下,在主上插入一条会直接同步到从上去:

mysql> insert into test1 values(1,'a');
Query OK, 1 row affected (0.12 sec)

要是出现意外,从挂了,那么:

mysql> slave stop;
Query OK, 0 rows affected (0.11 sec)

mysql> show global status like 'rpl_semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF   |
+----------------------------+-------+
1 row in set (0.00 sec)
mysql> insert into test1 values(2,'aa');
Query OK, 1 row affected (10.12 sec)

mysql> insert into test1 values(3,'aaa');
Query OK, 1 row affected (0.10 sec)

mysql> show global status like 'rpl_semi%';
+--------------------------------------------+--------+
| Variable_name                              | Value  |
+--------------------------------------------+--------+
| Rpl_semi_sync_master_clients               | 0      |
| Rpl_semi_sync_master_net_avg_wait_time     | 32934  |
| Rpl_semi_sync_master_net_wait_time         | 362277 |
| Rpl_semi_sync_master_net_waits             | 11     |
| Rpl_semi_sync_master_no_times              | 2      |
| Rpl_semi_sync_master_no_tx                 | 3      |
| Rpl_semi_sync_master_status                | OFF    |
| Rpl_semi_sync_master_timefunc_failures     | 0      |
| Rpl_semi_sync_master_tx_avg_wait_time      | 402    |
| Rpl_semi_sync_master_tx_wait_time          | 2011   |
| Rpl_semi_sync_master_tx_waits              | 5      |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0      |
| Rpl_semi_sync_master_wait_sessions         | 0      |
| Rpl_semi_sync_master_yes_tx                | 5      |
+--------------------------------------------+--------+

上面可以看到第一次插入,受rpl_semi_sync_master_timeout参数影响,超时等待了10s。第二次则直接可以执行,因为此时已经切换到了异步复制(Rpl_semi_sync_master_status = OFF因为这2个插入语句是在非半同步情况下执行的,所以Rpl_semi_sync_master_no_tx 从1变成了3。
重新开启从,或则修复好了从崩溃的问题:

mysql> slave start;
Query OK, 0 rows affected (0.01 sec)

mysql> show global status like 'rpl_semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

主的情况:主自动的开启了半同步。

| Rpl_semi_sync_master_status                | ON     |

注意:要是上面的情况频繁出现,会导致主上更新数据变得更慢。因为半同步复制和异步复制切换频繁,致使主频繁的等待接受从的信息而超时。

IO线程和SQL线程问题:
上面提到日志里面记录的信息:7:28:43 [Note] Slave I/O thread: Start semi-sync replication to master... ;是涉及到IO线程的,要是SQL线程挂了。那会怎么样?

主:
mysql> set sql_log_bin =0; Query OK, 0 rows affected (0.00 sec) mysql> create table test2 like test1; Query OK, 0 rows affected (0.14 sec) mysql> set sql_log_bin =1; Query OK, 0 rows affected (0.00 sec) mysql> drop table test2; Query OK, 0 rows affected (0.07 sec)

从:
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.200.245
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 784
               Relay_Log_File: mysqld2-relay-bin.000010
                Relay_Log_Pos: 634
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1051
                   Last_Error: Error 'Unknown table 'test2'' on query. Default database: 'test'. Query: 'DROP TABLE `test2` /* generated by server */'
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 677
              Relay_Log_Space: 1045
              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: 1051
               Last_SQL_Error: Error 'Unknown table 'test2'' on query. Default database: 'test'. Query: 'DROP TABLE `test2` /* generated by server */'
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
1 row in set (0.00 sec)

mysql> show global status like 'rpl_semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

上面可以看到:即使SQL线程报错了,半同步复制还是没有切换。表明半同步复制是跟 IO_THREAD 有直接关系,跟 SQL_THREAD 没关系。也就是说SLAVE 从库接收完二进制日志后给 master 主库一个确认,并不管relay-log 中继日志是否正确执行完。

总结:
好处:半同步复制可以有效的限制事务丢失的数量,更好的保证数据的安全和一致性;
坏处:更新、插入、删除的速度要比异步复制要慢,因为多了一个从返回信息给主的步骤。要是出现异常:网络问题或则数据库问题,半同步复制和异步复制就会来回切换,导致主库的更新、插入、删除操作会受到影响。

 


更多的测试信息见:
http://hcymysql.blog.51cto.com/5223301/887938

posted @ 2012-12-11 18:39 jyzhou 阅读(...) 评论(...) 编辑 收藏