一、GTID复制
GTID的概念是Mysql 5.6版本之后才有的
这是官方文档的介绍,
https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html
GTID = source_id:transaction_id
其实GTID是由UUID:序列号 组成,这样每一个事务在集群中都有一个唯一编号,能确定这个事务是由哪个实例执行的。
主主搭方法参考:
https://www.cnblogs.com/nanxiang/p/12902170.html
在搭建完成后,需要对其中的一些参数进行调整,修改my.cnf添加如下内容
gtid_mode=ON enforce-gtid-consistency=ON master_info_repository=TABLE relay_log_info_repository=TABLE
启动主备数据库,
在服务器A执行,
mysql> create database ceshi; Query OK, 1 row affected (0.01 sec) mysql> show master status\G *************************** 1. row *************************** File: mysql-bin.000014 Position: 321 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 9fef2262-97b1-11ea-92b5-000c29cd3ff3:1 #GTID编号,前边是UIID,后边的是1序列号 1 row in set (0.00 sec)
在服务器B执行
mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.150.101 Master_User: replicator Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000014 Read_Master_Log_Pos: 321 Relay_Log_File: host102-relay-bin.000005 Relay_Log_Pos: 534 Relay_Master_Log_File: mysql-bin.000014 Slave_IO_Running: Yes Slave_SQL_Running: Yes ...... ...... #内容较多,省略部分内容 Retrieved_Gtid_Set: 9fef2262-97b1-11ea-92b5-000c29cd3ff3:1 #代表接收到的位点 Executed_Gtid_Set: 9fef2262-97b1-11ea-92b5-000c29cd3ff3:1 #代表目前执行到哪个位点,如果Retrieved_Gtid_Set和Executed_Gtid_Set不相等,代表有延迟。
Auto_Position: 0 #等于0代表不自动定位GTID位点,在使用GTID复制模式下,这个值一定要为1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
主备库都要执持如下命令:
mysql> stop slave; Query OK, 0 rows affected (0.01 sec) mysql> change master to master_auto_position=1; Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.01 sec)
再次执行show slave status\G
可以看到Auto_Position 值已经为1了。
Executed_Gtid_Set: 9fef2262-97b1-11ea-92b5-000c29cd3ff3:1 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
使用GTID复制会有一些限制,
官方文档,
https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-restrictions.html
CREATE TABLE ... SELECT语句 将不支持。
事务、存储过程、函数、触发器内部,将不能使用CREATE TEMPORARY TABLE
and DROP TEMPORARY TABLE
创建临时表。
sql_slave_skip_counter 跳过事务的方式将不支持。
二、半同步复制
如下图是半步复制流程,
1、主库写入数据,生成binlog日志,
2、发送到备库,
3、本地将binlog刷盘,
4、主库存储引擎层提交事务
5、等待备库返回ACK确认信息,
6、返回给客户端事务成功。
这其中有一些问题,如果因为网络等原因,备库没有收到主库发送的binlog,但在第4步时,存储引擎已经提交了。此时宕机了,就会出现主备数据不一致的问题。
5.7版本中新加入了无损半同步复制,如下图。
1、主库写入数据,生成binlog日志,
2、发送到备库,
3、本地将binlog刷盘,
4、等待备库返回ACK确认信息,
5、主库存储引擎层提交事务
6、返回给客户端事务成功。
与之前的半同步相比,第4步和第5步互换了,要先收到备库的ACK信息,才做存储引擎层提交。
搭建步骤:
安装插件,
主库需要安装semisync_master.so
备库需要安装semisync_slave.so
为了满足主备切换后,还能继续使用半同步,主备库都需要同时安装这两个插件。
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; Query OK, 0 rows affected (0.01 sec) mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'; Query OK, 0 rows affected (0.00 sec) mysql> show plugins; +----------------------------+----------+--------------------+--------------------+---------+ | Name | Status | Type | Library | License | +----------------------------+----------+--------------------+--------------------+---------+ | binlog | ACTIVE | STORAGE ENGINE | NULL | GPL | | mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL | | sha256_password | ACTIVE | AUTHENTICATION | NULL | GPL |
.....
.....中间省略 | rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL | #可以看到状态是ACTIVE了 | rpl_semi_sync_slave | ACTIVE | REPLICATION | semisync_slave.so | GPL | #可以看到状态是ACTIVE了
+----------------------------+----------+--------------------+--------------------+---------+ 46 rows in set (0.00 sec)
查看一些安装插件后新增加的参数
mysql> show global variables like '%rpl_semi%'; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | OFF | #半同步复制是否开启 | rpl_semi_sync_master_timeout | 10000 | #半同步复制超时后转为异步复制时间(单位:毫秒) | rpl_semi_sync_master_trace_level | 32 | #用于开启半同步复制模式时的调试级别,默认是32 | rpl_semi_sync_master_wait_for_slave_count | 1 | #最少需要等到几个备库收到binlog后,主库才会提交。 | rpl_semi_sync_master_wait_no_slave | ON | #是否允许master每个事务提交后都要等待slave的接收确认信号。默认为on,每一个事务都会等待。如果为off,则slave追赶上后,也不会开启半同步复制模式,需要手工开启。 | rpl_semi_sync_master_wait_point | AFTER_SYNC | #AFTER_SYNC:备库收到binlog,并返回ACK确认后,主库存储引擎层才做提交操作。 AFTER_COMMIT:主库存储引擎层先提交,再收到备库ACK确认,这个也是旧的半同步复制方案。 | rpl_semi_sync_slave_enabled | OFF | #ON表示在slave上已经开启半同步复制模式,由于还没开启半同步复制,所以现在显示为OFF | rpl_semi_sync_slave_trace_level | 32 | #用于开启半同步复制模式时的调试级别,默认是32 +-------------------------------------------+------------+ 8 rows in set (0.01 sec)
开启半同步复制,主备库都要执行
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1; 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)
再看下半同步复制状态
mysql> show global variables like '%rpl_semi%'; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | ON | #已经为ON | rpl_semi_sync_master_timeout | 10000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_SYNC | | rpl_semi_sync_slave_enabled | ON | #已经为ON | rpl_semi_sync_slave_trace_level | 32 | +-------------------------------------------+------------+ 8 rows in set (0.01 sec)
虽然状态都为ON了,但是需要重启io thread线程才会生效。
mysql> stop slave io_thread; Query OK, 0 rows affected (0.01 sec) mysql> start slave io_thread; Query OK, 0 rows affected (0.00 sec)
为了这方便以后每次启动数据库,都运行在同步复制模式下,需要将这些参数加入到my.cnf配置文件中
plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" rpl-semi-sync-master-enabled = 1 rpl-semi-sync-slave-enabled = 1
验证半同步复制实验:
T1时间点在主库操作:
mysql> create table t1(id int primary key); Query OK, 0 rows affected (0.01 sec) mysql> insert into t1 select 1; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0
T2时间点在备库操作:
mysql> select * from t1; +----+ | id | +----+ | 1 | #可以看到数据已经正常同步过来了 +----+ 1 row in set (0.00 sec) mysql> stop slave io_thread; #把IO_THREAD线程关掉,停止主备复制 Query OK, 0 rows affected (0.00 sec)
T3时间点在备库操作:
mysql> insert into t1 select 2; Query OK, 1 row affected (10.01 sec) #这条插入命令执行了10秒,一直在等备库的ACK,超过10秒就不再等了,从而半同步复制变为了异常复制。 Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into t1 select 3; #因为处于异步复制状态了,不用再等备库的ACK,数据就直接写入了。 Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0
介绍一些关于半步复制的状态变量
官方文档连接:
https://dev.mysql.com/doc/refman/5.7/en/replication-options-reference.html
mysql> show global status like '%rpl_semi%'; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 1 | #有几个备库配置了半同步复制,如上述实验完成后,这里看到的是0,因为备库的io_thread线程停掉了,已经感知不到备库的存在了。 | Rpl_semi_sync_master_net_avg_wait_time | 0 | | Rpl_semi_sync_master_net_wait_time | 0 | | Rpl_semi_sync_master_net_waits | 5 | | Rpl_semi_sync_master_no_times | 1 | | Rpl_semi_sync_master_no_tx | 2 | #显示备库确认的不成功提交数量 | Rpl_semi_sync_master_status | ON | #主库是异步复制模式,还是半同步复制模式 | Rpl_semi_sync_master_timefunc_failures | 0 | | Rpl_semi_sync_master_tx_avg_wait_time | 1685 | | Rpl_semi_sync_master_tx_wait_time | 5055 | | Rpl_semi_sync_master_tx_waits | 3 | | Rpl_semi_sync_master_wait_pos_backtraverse | 0 | | Rpl_semi_sync_master_wait_sessions | 0 | | Rpl_semi_sync_master_yes_tx | 3 | #显示备库确认的成功提交数量 | Rpl_semi_sync_slave_status | ON | +--------------------------------------------+-------+ 15 rows in set (0.00 sec)
三、多线程复制
默认情况下,MYSQL的复制是单线程的,即备库的io_thread取的binlog日志,并写入到中继日志后,只有sql_thread一个线程去回放日志,
在开启多线程复制后,SQL会变为coordinator线程,同时会有多个worker线程,
coordinator线程主要作用是分发日志给worker线程执行,
如果遇到大事务,coordinator线程便不再发送给worker线程执行,由自己去回放这个大事务。
多线程复制原理基于MYSQL组提交实现,
5.6的多线程程复制是基于库的,也就是不同库中的事务操作,可以并行回放,如果一个库中的多个事务操作,只能顺序回放。
5.7的多线程程复制是基于事务的,一个库中的多个事务,可以实现并行回放。
开启方法:
mysql> show variables like 'slave_parallel%'; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | slave_parallel_type | DATABASE | #默认是基于库的,需要修改参数为LOGICAL_CLOCK,修改这个参数,要先停掉主从复制 | slave_parallel_workers | 0 | +------------------------+----------+ 2 rows in set (0.01 sec) mysql> stop slave; Query OK, 0 rows affected (0.01 sec) mysql> set global slave_parallel_type='LOGICAL_CLOCK'; Query OK, 0 rows affected (0.00 sec) mysql> set global slave_parallel_workers=4; #设置worker线程数据,配置较低选择4或8,配置较高可以配置为16 Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.01 sec)
同时也要修改my.cnf配置文件,重启数据库后也能生效:
slave_parallel_workers=4 slave_parallel_type='LOGICAL_CLOCK'
可以看到已经有4个worker线程了
mysql> show processlist; +----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+ | 1 | system user | | NULL | Connect | 11 | Slave has read all relay log; waiting for more updates | NULL | | 2 | system user | | NULL | Connect | 11 | Waiting for master to send event | NULL | | 4 | system user | | NULL | Connect | 11 | Waiting for an event from Coordinator | NULL | | 5 | system user | | NULL | Connect | 11 | Waiting for an event from Coordinator | NULL | | 6 | system user | | NULL | Connect | 11 | Waiting for an event from Coordinator | NULL | | 7 | system user | | NULL | Connect | 11 | Waiting for an event from Coordinator | NULL | | 8 | root | localhost | NULL | Query | 0 | starting | show processlist | +----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+ 7 rows in set (0.00 sec)