它的工作原理就是当slave从库的IO_Thread线程将binlog日志接收完毕时,要给master主库一个确认,如果rpl_semi_sync_master_timeout=10 000(10秒)超过10秒未收到slave从库的接收确认信号,那么就会自动转换为传统的异步复制模式。
场景一:stop slave
在slave从库上,停止I/O接收binlog线程,执行以下操作:
MySQL> stop slave io_thread;
Query OK, 0 rows affected (0.04 sec)
该操作会将IO_Thread线程关闭,等待10秒后,如果master主库未收到slave从库的接收确认信号,此时看下面的程序:
MySQL> show status like '%semi%';
+------------------------------------------------------------------------+--------+
| Variable_name | Value |
+------------------------------------------------------------------------+--------+
| Rpl_semi_sync_slave_status | OFF |
+------------------------------------------------------------------------+--------+
1 rows in set (0.00 sec)
可以发现,此时已经转换为异步复制模式。
再次到slave从库上执行以下操作:
MySQL> start slave;
Query OK, 0 rows affected (0.01 sec)
然后查看以下程序:
MySQL> show status like '%semi%';
+------------------------------------------------------------------------+---------+
| Variable_name ?? | Value |
+------------------------------------------------------------------------+---------+
| Rpl_semi_sync_slave_status | ON ??|
+------------------------------------------------------------------------+---------+
1 rows in set (0.00 sec)
可以看到,此时已经由原先的异步复制模式转换为半同步复制模式。
场景二:模拟同步报错
我们来试着这样操作:先在slave从机上drop database test删除一个test库;然后到master主机上再次执行drop database test,删除一个test库,这时主从同步复制就会报错,如下所示。
MySQL> show slave status\G;
*************************** 1. row ***************************
slave_IO_State: Waiting for master to send event
master_Host: 192.168.8.22
master_User: repl
master_Port: 3306
Connect_Retry: 60
master_Log_File: MySQL-bin.000003
Read_master_Log_Pos: 378
Relay_Log_File: vm02-relay-bin.000020
Relay_Log_Pos: 445
Relay_master_Log_File: MySQL-bin.000003
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: 1008
Last_Error: Error 'Can't drop database 'sdf'; database doesn't exist' on query. Default database: 'sdf'. Query: 'drop database sdf'
Skip_Counter: 0
Exec_master_Log_Pos: 299
Relay_Log_Space: 1016
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: 1008
Last_SQL_Error: Error 'Can't drop database 'sdf'; database doesn't exist' on query. Default database: 'sdf'. Query: 'drop database sdf'
Replicate_Ignore_Server_Ids:
master_Server_Id: 22
1 row in set (0.00 sec)
查看半同步复制状态:
MySQL> show status like '%semi%';
+------------------------------------------------------------------------+--------+
| Variable_name | Value |
+------------------------------------------------------------------------+--------+
| Rpl_semi_sync_slave_status | ON |
+------------------------------------------------------------------------+--------+
1 rows in set (0.00 sec)
从上面的状态信息可以看出,没有转化为异步复制模式,仍然是半同步复制模式,可见半同步复制跟IO_THREAD是有直接关系的,但跟SQL_THREAD没关系。也就是说,slave从库接收完二进制日志后会给master主库一个确认,但它并不会管relay-log中继日志是否执行完。
场景三:commit提交等待
我们先在slave从机上关闭主从复制,为了方便看出效果,调整rpl_semi_sync_master_timeout = 200 000毫秒,约等于3分钟。
rpl_semi_sync_master_wait_no_slave = on,表示允许master每个事务提交后等待slave的接收确认信号。
下面是操作步骤:
1)在slave从库,停止同步复制,执行命令:“Stop slave;”。
2)master主库上,执行下面的操作:
MySQL> use test;
Database changed
MySQL> begin;
Query OK, 0 rows affected (0.00 sec)
MySQL> update t set name='ccd' where id=3;
Query OK, 2 rows affected (0.07 sec)
Rows matched: 2 Changed: 2 Warnings: 0
MySQL> select * from t;
+------+---------+
| id | name |
+------+---------+
| 1 | a |
| 1 | a |
| 2 | b |
| 2 | b |
| 3 | ccd |
| 3 | ccd |
+------+---------+
6 rows in set (0.01 sec)
MySQL> commit;
Query OK, 0 rows affected (3 min 20.00 sec)
可以看到,一个简单的update需要耗时3分20秒,原因就是半同步复制需要等待slave从库的接收确认,因为rpl_semi_sync_master_timeout设置的是200 000毫秒,约等于3分钟,所以提交就变慢了。