0%

mysql的主从复制

1、binlog文件

Binlog的日志格式可以在命令行中设置

show variables like '%log%';        //要重新登入一次才会看到该变量生效
set global binlog_format='row'/'statement'/'mixed'

binlog有三种格式:Statement, Row和Mixed.

  1. 基于SQL语句的复制(statement-based replication, SBR)
  2. 基于行的复制(row-based replication, RBR)
  3. 混合模式复制(mixed-based replication, MBR),一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一

通过命令

show binlog EVENTS in "mysql-bin.000001";
或者

可以查看binlog的具体sql内容

具体内容如下:

BEGIN
/*!*/;
# at 4123
#190526 19:04:08 server id 1  end_log_pos 4238 CRC32 0x0c948921     Table_map: `account_17_db`.`t_company_account_snap_2` mapped to number 72
# at 4238
#190526 19:04:08 server id 1  end_log_pos 4526 CRC32 0x76cdfa0a     Update_rows: table id 72 flags: STMT_END_F

BINLOG '
qHLqXBMBAAAAcwAAAI4QAAAAAEgAAAAAAAEADWFjY291bnRfMTdfZGIAGHRfY29tcGFueV9hY2Nv
dW50X3NuYXBfMgARCA8PDwH2EgP29vb2DxISCAEVYABgAMAAIAQAIAQgBCAEIAT9AgAAAAAAIYmU
DA==
qHLqXB8BAAAAIAEAAK4RAAAAAEgAAAAAAAEAAgAR////////AAD+AgAAAAAAAAADd3F3AAAAgAAA
AAAAAAAAAAAAAAAAmQLCAAAAAAAAgAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAgAAAAAAA
AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAACZAsIAAJkCwgAAAAAAAAAAAAAAAAD+AgAAAAAAAAAD
d3F3AAJzZACAAAAAAAAAAAAAAAAAAACZAsIAAAAAAACAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAA
AAAAAACAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAJkCwgAAmQLCAAAAAAAAAAAAAAAK
+s12
'/*!*/;
# at 4526
#190526 19:04:08 server id 1  end_log_pos 4557 CRC32 0x2abea70f     Xid = 139
COMMIT/*!*/;
# at 4557
#190526 19:06:01 server id 1  end_log_pos 4654 CRC32 0xf30dd244     Query    thread_id=5    exec_time=0    error_code=0
SET TIMESTAMP=1558868761/*!*/;
BEGIN
/*!*/;
# at 4654
#190526 19:06:01 server id 1  end_log_pos 4829 CRC32 0xc246c0a7     Query    thread_id=5    exec_time=0    error_code=0
use `account_17_db`/*!*/;
SET TIMESTAMP=1558868761/*!*/;
UPDATE `t_company_account_snap_2` SET `Ftrans_id`='34' WHERE (`Findex`='4') LIMIT 1
/*!*/;
# at 4829
#190526 19:06:01 server id 1  end_log_pos 4860 CRC32 0x7f835a25     Xid = 151
COMMIT/*!*/;

xid 139是按照行数据的形式存储的变更,xid 151则是按照statement存储的变更

2、主从同步的过程

主库执行sql,记录到二进制的文件中(记录的过程在事务中),从库启动一个工作线程,和主库建立客户端连接,主库也会启动二进制转储的线程,该转储线程读取binlog中的事件,发送到从库的线程中并接收从库的ack(串行)。如果已经追赶到了最新数据,该转储线程会休眠,等待主库有新事务后唤醒之。如果是一主多从的情况,主库对每个从库都有对应的线程。

ps:5.7之后主库有专门的线程接收从库的ack

从库的工作线程将收到的事件记录到中继日志中,从库的另外的sql线程会读取中继日志,并执行之。同时也会将该事件写入自己的binlog中。一个线程的执行可能会变为瓶颈

3、主从同步的方式

1、语句复制

在mysql 5.0之前只支持语句复制,将主库执行的sql在从库执行一次。

优点:简单,sql更新的数据量很大,但是sql的大小只有几个字节

缺点:无法完全还原主库的执行sql的环境,例如 CURRENT_USER()函数。并且sql在主从的执行时间不一样,5.1和5.2的mysql对触发器和存储过程的支持不够

2、行复制

将binlog中的行数据复制到从库

优点:可以覆盖任何场景的数据变更

缺点:看不出数据变更的逻辑

4、主从同步

1、异步复制:

  • MySQL的异步复制是MySQL自带的数据同步功能,在公司里面也是也就最为常见的。
  • 主库的事务执行不会管备库的同步进度,如果备库落后,主库不幸crash,那么就会导致数据丢失。

2、同步复制 (>=5.7):

全同步复制,当主库提交事务之后,所有的从库节点必须收到、APPLY并且提交这些事务,然后主库线程才能继续做后续操作。但缺点是,主库完成一个事务的时间会被拉长,性能降低。

3、半同步复制 (>=5.5):

  • 半同步复制是由谷歌研发的一种数据库主从复制方式。
  • 与传统的异步复制相比,半同步复制在多个Slave节点中会选取一个节点进行半同步复制。也就是说,当Master提交一个事务的时候,在这个半同步复制的Slave端返回一个同步完成的Ack包之后,服务器才会向用户返回事务提交成功,而其他的节点则是采用传统的异步复制方式进行同步。
  • 如果主库在等待备库ack时候,如果超时会退化为异步,这就可能导致数据丢失。

rpl_semi_sync_master_wait_point、sync_binlog、sync_relay_log配置半同步

rpl_semi_sync_master_wait_point的配置:

WAIT_AFTER_COMMIT:

如上图所示。即在等待Slave ACK时候,虽然没有返回当前客户端,但事务已经提交,其他客户端会读取到已提交事务。如果Slave端还没有读到该事务的events,同时主库发生了crash,然后切换到备库。那么之前读到的事务就不见了,出现了幻读

WAIT_AFTER_SYNC:

在调用binlog sync之后,engine层commit之前等待Slave ACK。这样只有在确认Slave收到事务events后,事务才会提交。在commit之前等待Slave ACK,同时可以堆积事务,利于group commit(一次ack多个事务),有利于提升性能。

使用方式:

主库要安装插件,并启用之:

INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL VARIABLES rpl_semi_sync_master_enabled=1;

从库也一样:

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SET GLOBAL VARIABLES rpl_semi_sync_slave_enabled=1;