MySQL gtid半同步复制详解与主从搭建

MySQL复制默认是异步复制,存在一定的概率备库与主库的数据是不对等的,如果Master宕机,事务在Master上已提交,但很可能这些事务没有传到任何的Slave上,此时Slave也可能会丢失事务。在半同步复制的架构下,当master在将自己binlog发给slave上的时候,要确保slave已经接受到了这个二进制日志以后,才会返回数据给客户端。

半同步复制原理 


半同步复制架构图如下所示:

2.png

半同步复制的概念:

1,当Slave主机连接到Master时,能够查看其是否处于半同步复制的机制。

2,当Master上开启半同步复制的功能时,至少应该有一个Slave开启其功能。此时,一个线程在Master上提交事务将受到阻塞,直到得知一个已开启半同步复制功能的Slave已收到此事务的所有事件,或等待超时。

3,当一个事务的事件都已写入其relay-log中且已刷新到磁盘上,Slave才会告知已收到。在 Master 实例上,有一个专门的线程(ack_receiver)接收备库的响应消息,并以通知机制告知主库备库已经接收的日志,可以继续执行。

4,如果等待超时,也就是Master没被告知已收到,此时Master会自动转换为异步复制的机制。当至少一个半同步的Slave赶上了,Master与其Slave自动转换为半同步复制的机制。

5,半同步复制的功能要在Master,Slave都开启,半同步复制才会起作用;否则,只开启一边,它依然为异步复制。

6,半同步特性的出现,就是为了保证在任何时刻主备数据一致的问题。相对于异步复制,半同步复制要求执行的每一个事务,都要求至少有一个备库成功接收后,才返回给用户。

事物在主库执行完binlog后接受到从库的ACK,才会回复客户端。所以,相比而言,性能有所降低。

基于gtid主从复制简介:
mysql数据库从5.6.5开始新增一种基于gtid的复制方式。gtid(global transaction id)是对于一个已提交事务的编号。gtid实际上是由uuid+tid组成的,其中uuid是mysql实例的一个标识,tid则代表了该实例上交的事务数量,并且随着事务的提交单调递增。

主从复制默认是通过pos(position)复制,就是说在日志文档里,将用户进行的每一项操作都进行编号(pos),每一个事件都有一个起始编号,一个终止编号,在配置主从复制节点时,要求其从master的pos开始同步数据库里面的数据,这也称作传统复制技术。

gtid就是类似pos的作用,不过它是整个mysql复制架构全局通用的,即在整个mysql冗余架构中,它们的日志文件里面事件的gtid的数值是一致的。

gtid是一个对于已提交的事物的编号,并且是一个全局唯一的编号。通过gtid保证每个主库上提交的事务在集群中有一个唯一的id。这种方式强化了主备的一致性,故障恢复及其容错能力。

pos与gtid的区别
两者都是日志文件里的一个标志,如果将整个mysql集群看作一个整体,pos就是局部的,gtid就是全局的。

半同步搭建


环境: 

主机名

IP

系统

角色

db01

192.168.179.102

CentOS7.4

Master

db02

192.168.179.103

CentOS7.4

Slave

#主库配置
[root@localhost ~]# sed -e '/#/d' -e '/^$/d' /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

server_id=1
gtid-mode = on
enforce-gtid-consistency = 1 
log-bin=master-bin      
binlog_format = row     
log-slave-updates = 1

#从库配置
[root@localhost ~]# sed -e '/#/d' -e '/^$/d' /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

server_id=2
gtid-mode = on
enforce-gtid-consistency = 1 
log-bin=slave-bin      
binlog_format = row     
log-slave-updates = 1

#修改完配置文件以后重启数据库实例






# 主库查看GTID开启状态
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery      | ON        |
| enforce_gtid_consistency         | ON        |
| gtid_executed_compression_period | 1000      |
| gtid_mode                        | ON        |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
| session_track_gtids              | OFF       |
+----------------------------------+-----------+
# 从库查看GTID开启状态
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery      | ON        |
| enforce_gtid_consistency         | ON        |
| gtid_executed_compression_period | 
      |
| gtid_mode                        | ON        |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
| session_track_gtids              | OFF       |
+----------------------------------+-----------+


#主库安装半同步插件 -------------------------------
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
#主库查看半同步插件
mysql> select plugin_name,plugin_status from information_schema.plugins where plugin_name like '%semi_sync%';
+----------------------+---------------+
| plugin_name          | plugin_status |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE        |
+----------------------+---------------+
注:如果想卸载半同步插件,可以使用如下命令:
mysql> uninstall plugin rpl_semi_sync_master;

#启用插件
mysql> set global rpl_semi_sync_master_enabled=on; 
#设置超时时间
mysql> set global rpl_semi_sync_master_timeout=1000;
mysql> show global variables like '%semi%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 1000       |
| 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_master_enabled=1的效果,第一行是ON则表示半同步复制已经开启。

#rpl_semi_sync_master_enabled是控制Master是否开启半同步,开启或不开启,将其设置为ON或OFF(1or0).
#rpl_semi_sync_master_timeout是控制Master等待多长时间被告知Slave已收到,也就是所谓的超时时间。



#从库安装半同步插件 -------------------------------
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
mysql> select plugin_name,plugin_status from information_schema.plugins where plugin_name like '%semi_sync%';
+---------------------+---------------+
| plugin_name         | plugin_status |
+---------------------+---------------+
| rpl_semi_sync_slave | ACTIVE        |
+---------------------+---------------+

mysql> set global rpl_semi_sync_slave_enabled= 1;
mysql> show global variables like '%semi%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | OFF        |
| 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         |
| rpl_semi_sync_slave_trace_level           | 32         |
+-------------------------------------------+------------+
#重启io_thread,使用相同步骤配置从节点,完成后需要重启io_thread,不重启当执行时会超时,超时后则自动降为异步:
mysql> stop slave io_thread;
mysql> start slave io_thread;

#rpl_semi_sync_slave_enabled是控制Slave是否开启半同步,开启或不开启,将其设置为ON或OFF(1or0)。

#主库查看未开启gtid状态
mysql> SHOW PROCESSLIST \G
*************************** 1. row ***************************
     Id: 2
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: starting
   Info: SHOW PROCESSLIST
1 row in set (0.00 sec)


# 主库创建复制用户 --------------------------------------------------------------
mysql>  grant replication slave on *.* to repl@'%' identified by '123456';


# 从库建立复制通道---------------------------------------------------------------
mysql> CHANGE MASTER TO 
    -> MASTER_HOST='192.168.179.102',
    -> MASTER_USER='repl',
    -> MASTER_PASSWORD='123456',
    -> MASTER_PORT=3306,
    -> MASTER_CONNECT_RETRY=10,
    -> MASTER_AUTO_POSITION=1;
mysql> start slave;

写入你的配置文件,避免宕机之后重启失效 

以上的启动方式是在命令行操作,也可写在配置文件中。

主:
plugin-load=rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_enabled=1

从:
plugin-load=rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=1
在有的高可用架构下,master和slave需同时启动,以便在切换后能继续使用半同步复制


#如果不配置在配置文件里面从库宕机重启不会启用半同步复制。会出现如下:
mysql>  show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF   |
+----------------------------+-------+

查看是否成功开启GTID同步,Command显示Binlog Dump GTID表示成功开启GTID同步。

mysql> SHOW PROCESSLIST \G
*************************** 3. row ***************************
     Id: 4
   User: repl
   Host: 192.168.179.103:59046
     db: NULL
Command: Binlog Dump GTID
   Time: 146
  State: Master has sent all binlog to slave; waiting for more updates
   Info: NULL

#查看主库和从库上的半同步复制是否在运行
mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON    |
+-----------------------------+-------+
#登录从库查看
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.179.102
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: master-bin.000001
          Read_Master_Log_Pos: 429
               Relay_Log_File: localhost-relay-bin.000002
                Relay_Log_Pos: 644
        Relay_Master_Log_File: master-bin.000001
             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: 429
              Relay_Log_Space: 855
              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: 18f5da07-a096-11ea-8c70-000c290e1abf
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 18f5da07-a096-11ea-8c70-000c290e1abf:1
            Executed_Gtid_Set: 18f5da07-a096-11ea-8c70-000c290e1abf:1
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 

在此过程出现问题和解决方式:
问题1:Slave_SQL_Running: No 

解决方法:start  slave;            # 启动slave(或者关闭slave之后,---> reset slave,再启动slave)

问题2:Slave_IO_Running: Connecting,说明主从库没有连接上
解决方法:1) 在master中是否对用户进行授权     

         2) 密码或pos号是否正确     

         3) 防火墙是否关闭

监控半同步复制的状态变量(几个常用的):

mysql> show status like '%semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 1     |
| 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      | 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     |
+--------------------------------------------+-------+

Rpl_semi_sync_master_clients:查看有多少个开启半同步复制的插件的Slave

Rpl_semi_sync_master_status:查看在Master上半同步复制是否正在运行,其值为ON时,说明Master已启用半同步且已被告知有Slave收到;其值为OFF时,说明Master没启用半同步或是没被告知,由于timeout等原因。

Rpl_semi_sync_master_no_tx:查看有多少事务没有用半同步复制的机制进行复制。

Rpl_semi_sync_master_yes_tx:查看有多少事务是通过半同步复制机制成功复制。

Rpl_semi_sync_slave_status:查看Slave上半同步复制是否正常运行,其值为ON时,说明Slave正通过半同步复制且Slave I/O正在运行;为OFF时,反之。

验证半同步复制是否正常


验证方法:正常在主库上创建一张表,会立刻返回,耗时0.1s。关闭从库的io线程,然后在主库上执行建表操作,会发现,主库上回阻塞10秒之后才会返回,而这个时间正好和主库上的rpl_semi_sync_master_timeout相同,表示半同步起作用了,主库的DDL操作需要等到从库应用完relaylog之后才返回

#从库执行:
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
mysql> STOP SLAVE IO_THREAD;
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | OFF   |
+----------------------------+-------+

#主库执行:
mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON    |
+-----------------------------+-------+
mysql> insert into test values(6666);
Query OK, 1 row affected (10.00 sec)
#主库上回阻塞10秒之后才会返回

mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | OFF   |
+-----------------------------+-------+

mysql> show master status\G
*************************** 1. row ***************************
             File: master-bin.000001
         Position: 3139
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 18f5da07-a096-11ea-8c70-000c290e1abf:1-12


#从库执行,重新打开IO线程可以看到在主库没有同步的事务同步到从库了
mysql> START SLAVE IO_THREAD;
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
[root@localhost ~]# mysqlbinlog  /var/lib/mysql/slave-bin.000001 | tail -n 50
# at 904
#200605 16:22:01 server id 1  end_log_pos 969 CRC32 0xe29e844e 	GTID	last_committed=3	sequence_number=4	rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '18f5da07-a096-11ea-8c70-000c290e1abf:12'/*!*/;
# at 969
#200605 16:22:01 server id 1  end_log_pos 1032 CRC32 0x50b908b4 	Query	thread_id=18	exec_time=336	error_code=0
SET TIMESTAMP=1591345321/*!*/;
BEGIN
/*!*/;
# at 1032
#200605 16:22:01 server id 1  end_log_pos 1083 CRC32 0x296d8336 	Table_map: `students`.`test` mapped to number 108
# at 1083
#200605 16:22:01 server id 1  end_log_pos 1123 CRC32 0xf886bfea 	Write_rows: table id 108 flags: STMT_END_F

BINLOG '
qQDaXhMBAAAAMwAAADsEAAAAAGwAAAAAAAEACHN0dWRlbnRzAAR0ZXN0AAEDAAE2g20p
qQDaXh4BAAAAKAAAAGMEAAAAAGwAAAAAAAEAAgAB//4KGgAA6r+G+A==
'/*!*/;
# at 1123
#200605 16:22:01 server id 1  end_log_pos 1154 CRC32 0x9faa662d 	Xid = 44
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

开启半同步复制意味着什么?


在主库开启一个事务,这个事务在主库和远端的从库各存一份。此时 Rpl_semi_sync_master_yes_tx 的值加一。忽然断网时,会有10s的hang住(rpl_semi_sync_master_timeout =10000),然后mysql会自己关闭主从复制。然后变成异步。此时Rpl_semi_sync_master_yes_tx 值不变了,而Rpl_semi_sync_master_no_tx 的值就开始加一。
 

总结:使用半同步复制机制,性能也许会受到影响,但其主要是为了维持数据完整性,安全性的的一个策略,虽会损失一点性能,但还是值得的。

猜你喜欢

转载自blog.csdn.net/qq_34556414/article/details/106543412
今日推荐