Mysql 复制介绍

MySQL 复制执行流程

1. Master上语句执行解释之前,将更新数据库的操作记录在二进制日志中(select语句不记录)。

2.Master上有个转储线程,读取二进制日志文件的内容发送到slave机器的I/O线程上。

3.slave I/O线程接收数据写入中继日志。

4.salve的sql线程从中继日志读取并执行




如果主机和备机要穿越网络,为保证安全性,可以配置SSL或者使用stunnel建立安全链接。

启停slave机器上的复制线程: 

  start/stop slave : 停止I/O线程和SQL线程    

  START/STOP  SLAVE  IO_THREAD(SQL_THREAD):仅开始或者停机IO线程(SQL线程)      


查询状态的命令

  show slave hosts:显示主机上配置的备机信息,该备机必须配置了report_host参数

  show master logs:显示主机上的二进制日志文件和大小

  show master status:给出下一个事件即将写入二进制日志的位置

 show slave status: 查看备机的运行状态,几个关键的变量含义如下:

  --- Master_Log_File和Read_Master_Log_Pos: Mater的读位置,I/O线程即将从master二进制日志读取的下一个事件位置。对应slave_master_info表的Mater_Log_name和master_log_pos字段。

 ---  Relay_Master_Log_File和Exec_Master_Log_Pos: Master的执行位置,SQL线程即将执行的master二进制日志的下一个位置。对应slave_relay_log_info表的Master_log_name字段和Master_log_pos字段

 ---  Relay_Log_File和Relay_Log_Pos:中继日志的执行位置,sql线程即将执行的slave中继日志的下一个位置。对应slave_relay_log_info表的Relay_log_name字段和Relay_log_pos字段

---  Seconds_Behind_Master: 正在执行的sql时间与slave当前时间的差值

    

                

相关配置参数

log_bin:二进制日志文件名

log_bin_index: 二进制日志文件的目录列表

relay_log:中继日志文件名

relay_log_index:中继日志文件目录

####以上参数缺省采用的是机器名,不安全,如果机器名改变,程序启动会找不到文件出错

server_id: 必须要配置的参数,保持唯一。

expire_logs_days:二进制日志的保留天数,mysql会在刷新日志文件的时候将超时的日志清理。注意二进制日志不能自己再系统中删除,可以通过配置该参数或者purage logs来清理。 

log-slave-updates:来自master上的事件同样也会写入备机的二进制日志,级联场景中有用。


sync_binlog:控制二进制日志写入磁盘的频率。0:不主动刷新到磁盘,由操作系统刷新到磁盘。 其他:多少个事务刷新一次。

  如果设置为非1,mysqld崩溃的情况下,数据并没有丢失。但是如果系统断电,操作系统没有刷新缓存,会导致二进制日志数据丢失。这个会导致备机slave读取不到对应位置的日志,进一步导致备机事务退出。相关errno:1236

innodb_flush_log_at_trx_commit:控制事务日志的刷新频率,0:每秒写事务日志(只是刷新到系统缓存)、每秒刷新到磁盘   1:事务提交时写日志,刷新到磁盘    2:事务提交时写日志,每秒刷新磁盘    

    1是最安全的。 0:mysqld挂掉,会最多丢失一秒内的事务     2:系统掉电,会丢失最多一秒内的事务。mysqld挂掉不会丢失数据



Retrieved_Gtid_Set:从master获取的,存储在中继日志的GTID组

Executed_Gtid_Set:在slave上已经执行的GTID组


#尝试重连参数

slave-net-timeout:超过该时间无响应,slave和master已经丢失连接,并尝试重连

master-connect-retry:两次尝试间隔的秒

master-retry-count:最大尝试次数


#复制过滤数据和表

#slave上SQL线程的过滤,该过滤可以保证master上二进制日志的完整  缺点是占用网络带宽

replicate-do-db   replication-ignore-db  replicate-do-table  replicate-ignore-table   replicate-wild-do-table  replicate-wild-ignore-table

#master上的过滤,对应的表和数据库修改不会记录到二进制日志中,优点减少网络带宽,缺点二进制日志不完整

binlog-do-db   binlog-ignore-db

#过滤操作如果配置为基于行的复制模式没有问题。如果是基于语句的模式,会根据use语句过滤数据库,没法拆分一个语句中对多个表的修改,建议采用以下规则:

# 语句前使用use db,不使用db.table的格式;不要在一个语句中修改多张表;不要在一个语句中跨库修改表;


MySQL的复制模式

MySQL的复制是异步的,这样能够提高处理速度,但是备机上的数据的安全性不能完全保证。

MySQL有插件支持半同步复制:确保至少有一个slave将变更写到磁盘。这样最多只有一个事务丢失。通过rpl-semi-sync-master-timeout和rpl-semi-sync-master-wait-no-slave参数可以设置超时和无slave连接的情况下将本同步还原为异步同步。

基于GTID复制: mysql5.6版本引入,但是有些问题,建议在5.7之后的版本中再使用

   GTID=UUID(服务器唯一ID) + 事务标记符(在一台机器上唯一标记事务,根据服务提交的顺序分配)。GTID可以唯一标记任意一个事务。

   在change master to语句中使用master_auto_position=1,当slave连接master的时候,自动与master协商应该发送什么事务。

   变量GTID_EXECUTED表示已经执行的GTID组,GTID_PURED表示已经从二进制日志中清除的事务组。


   使用GTID进行故障转移和slave升主都比较容易。



Slave的安全与恢复

复制不是崩溃安全的。

slave端I/O线程要做2件事:刷新master上的二进制日志到中继日志文件;将master上的位置信息记录到master_info文件。

slave段sql线程要做2件事:执行中继日志中的事务,更新replay_log_info文件中的位置信息。

这些操作都是事务型的,在任意位置可能发生崩溃。有2种结果:先执行操作,后记录位置,如果中间发生崩溃,下次重启的时候操作会再执行一次;先记录位置,再执行操作,如果中间发生崩溃,会丢失操作。mysql选择的前一种,这样至少不会丢失事务,但是操作可能执行两次。

解决方法:mysql5.6版本增加事务性复制。将复制信息写入innodb表中,从而将要做的2件事处理为事务型的。

  配置:master_info_repository=TABLE     master_log_info_repository=TABLE



复制的二进制日志模式

基于语句复制STATMENT:  缺点:某些场景下不安全,对于事件、触发器、复制的过滤等。

基于行复制ROW:   基于行的模式对于事件、触发器、数据库和表的复制过滤都支持的很好。 但是二进制日志的量可能非常大。

   binlog-row-image控制哪些列写入日志。如果master和slave上的索引完全一致,可以将binlog-row-image设置为minimal(只有主键和需要更改的列写入二进制日志,缺省是表的所有列写入二进制日志)。在我的测试环境上二进制日志的大小可以减少1/3。

MIXED:缺省使用基于语句的模式,如果遇到不安全的语句,才用基于行的模式。如果是Read committed和Read uncommitted隔离级别,会自动切换到基于行的模式。