原文:https://www.jianshu.com/p/9d84a725332d

https://www.cnblogs.com/fengzheng/p/13401783.html
https://juejin.im/entry/6844903458290532366


主从配置一般都是和读写分离相结合,主服务器负责写数据,从服务器负责读数据,并保证主服务器的数据及时同步到从服务器。

主从模式示意图

主节点

1、当主节点上进行 insert、update、delete 操作时,会按照时间先后顺序写入到 binlog 中;
2、当从节点连接到主节点时,主节点会创建一个叫做 binlog dump 的线程;
3、一个主节点有多少个从节点,就会创建多少个 binlog dump 线程;
4、当主节点的 binlog 发生变化的时候,也就是进行了更改操作,binlog dump 线程就会通知从节点 (Push模式),并将相应的 binlog 内容发送给从节点;

从节点

当开启主从同步的时候,从节点会创建两个线程用来完成数据同步的工作。

(1)I/O线程: 此线程连接到主节点,主节点上的 binlog dump 线程会将 binlog 的内容发送给此线程。此线程接收到 binlog 内容后,再将内容写入到本地的 relay log。

(2)SQL线程: 该线程读取 I/O 线程写入的 relay log,并且根据 relay log 的内容对从数据库做对应的操作。


理论上怎么实现从库和主库的数据一致性?

1、异步复制
主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从库上,如果此时,强行将从提升为主,可能导致“数据不一致”。早期MySQL(5.5以前)仅仅支持异步复制。
2、半同步复制
MySQL在5.5中引入了半同步复制,主库在应答客户端提交的事务前需要保证至少一个从库接收并写到relay log中,半同步复制通过rpl_semi_sync_master_wait_point参数来控制master在哪个环节接收 slave ack,master 接收到 ack 后返回状态给客户端,此参数一共有两个选项 AFTER_SYNC & AFTER_COMMIT。

  • AFTER_COMMIT

AFTER_COMMIT时,commitTrx的调用在engine层commit之后,即在等待Slave ACK时候,虽然没有返回当前客户端,但事务已经提交,其他客户端会读取到已提交事务。如果Slave端还没有读到该事务的events,同时主库发生了crash,然后切换到备库。那么就会出现数据不一致的问题。如果主库永远启动不了,那么实际上在主库已经成功提交的事务,在从库上是找不到的,也就是数据丢失了。

PS:早在11年前后,阿里巴巴数据库就创新实现了在engine层commit之前等待Slave ACK的方式来解决此问题。

3、全同步复制

MySQL官方针对上述问题,在5.7.2引入了Loss-less Semi-Synchronous,在调用binlog sync之后,engine层commit之前等待Slave ACK。这样只有在确认Slave收到事务events后,事务才会提交。

set rpl_semi_sync_master_wait_point=AFTER_SYNC
SET GLOBAL rpl_semi_sync_master_wait_for_slave_count= N;
// 应答多少个slave才commit
  • AFTER_SYNC: 官方推荐的方式    # 即是先确认从库接收到数据并成功写入relaylog,主库再在引擎层提交数据。

客户端发出commit请求后,在主库上写入binlog并推送给slave,slave接收到binlog并写入relaylog,发送ACK确认已经接收binlog后,master在引擎层commit,客户端接收commit完成,此时其他会话才可以看见已提交的数据。

故障分析:假设master在接收ACK确认时宕机,因为在引擎层并没有提交,HA切换到从库,因为binlog已经写入从库的relaylog,因此不会造成数据丢失。

但是也不是万无一失,因为当主库在binlog flush并且binlog同步到了备库之后,binlog sync之前发生了abort,那么很明显这个事务在主库上是未提交成功的(由于abort之前binlog未sync完成,主库恢复后事务会被回滚掉),但由于从库已经收到了这些Binlog,并且执行成功,相当于在从库上多出了数据,从而可能造成“数据不一致”。

在after_sync模式下解决了after_commit模式带来的数据不一致的问题,因为主库没有提交事务。

此外,MySQL半同步复制架构中,主库在等待备库ack时候,如果超时会退化为异步后,也可能导致“数据不一致”。(等待的时间以rpl_semi_sync_master_timeout参数为准,默认为10秒。)

其他防丢失操作

  1. 在master上修改配置
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1

上述两个选项的作用是:保证每次事务提交后,都能实时刷新到磁盘中,尤其是确保每次事务对应的binlog都能及时刷新到磁盘中,只要有了binlog,InnoDB就有办法做数据恢复,不至于导致主从复制的数据丢失。

  1. 在slave上修改配置
master_info_repository = "TABLE"
relay_log_info_repository = "TABLE"
relay_log_recovery = 1

上述前两个选项的作用是:确保在slave上和复制相关的元数据表也采用InnoDB引擎,受到InnoDB事务安全的保护,而后一个选项的作用是开启relay log自动修复机制,发生crash时,会自动判断哪些relay log需要重新从master上抓取回来再次应用,以此避免部分数据丢失的可能性。


配置示例

Master配置:

开启远程连接
使用命令行或者客户端工具进入 MySQL,执行命令:

GRANT REPLICATION SLAVE ON *.* to 'root'@'192.168.0.108' identified by 'P@ssw0rd';
FLUSH PRIVILEGES;

上面语句执行完成后,在从服务器中使用客户端或者命令行测试是否生效。

mysql -h 192.168.0.101 -uroot -p

启用 bin-log,并设置 server-id
需要在 MySQL 配置文件中修改,MySQL 配置文件默认位置在如下位置,从上下到下优先级降低:

/etc/my.cnf
/etc/mysql/my.cnf
/usr/local/etc/my.cnf
~/.my.cnf

配置内容如下:

[mysqld]
log-bin=mysql-bin
server-id=101
  • 其他参数

除了上面两个必要参数外,还有其他的几个参数。

(1)binlog_format
bin-log 日志的格式,支持下面三种,推荐使用 mixed 。

statement:会将对数据库操作的sql语句写入到binlog中。
row:会将每一条数据的变化写入到binlog中。
mixed:statement 与 row 的混合。MySQL 决定什么时候写 statement 格式,什么时候写 row 格式。

(2) binlog-do-db

配置要同步的数据库,如果不配置默认为全部数据库。

binlog-do-db=db1
binlog-do-db=db2

(3)binlog-ignore-db

配置不需要同步的数据库。

binlog-ignore-db=db3

(4)expire-logs-days

bin-log 日志保存天数,保存天数越久占用空间越大。

然后重启 MySQL 服务

mysql.server restart

使用下面的命令可以查看配置是否生效:

show variables like 'log_bin';
show variables like 'server_id';

使用下面的语句查看 master 状态。

show master status;

从服务器配置

1、打开从服务器的配置文件,在其中加上如下配置:

server-id=108

2、重启 MySQL 服务。

mysql.server restart

3、配置主从同步

change master to master_host='192.168.0.101',master_user='root',master_password='P@ssw0rd',master_log_file='mysql-bin.000001' ,master_log_pos=154;

其中 master_host表示主服务器 IP,master_user和master_password分别是主服务器的用户名和密码,master_log_file和master_log_pos在主服务器中通过show master status语句可以查到。

4、开启同步进程。

start slave

5、查看同步状态。

show slave status;

  • Slave挂了怎么恢复同步?

重启,只要同步服务再次启动,那就可以从上次同步的位置继续增量同步了。

  • 单Master挂了怎么办?

如果马上启动那就是最好的解决办法。如果由于硬件或者比较棘手的问题导致没办法立即重启,那就要选一个从库升级为主库,选择的标准是数据最接近主库的,也就是最后一次同步时间最晚的。如果有可能(比如主服务只是数据库无法启动,但机器还在)还要到主服务上拉取最新的 bin-log 进行同步。最后进行一系列设置将选中的从库变更为主库配置。

  • 大致步骤:

身份调换之前,主服务器会对表上锁,保证调换期间,不会写进新的数据。

从服务器先停止从服务器IO线程,此期间,会应用完RelayLog中的所有信息,保证主、从数据完全一致。接下来,主、从服务器都会把自身的Binlog文件清除掉,建立起新的Binlog文件,再将之前两者的交互信息删干净,此时,可以重新建立主从连接了,从服务器俨然成为新一代主服务器,而原主服务器也解开之前的表锁,担起了从服务器的角色,事实证明,这是一次完美的试炼。


作者:小幸运Q
链接:https://www.jianshu.com/p/9d84a725332d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted on 2020-12-29 18:06  51core  阅读(306)  评论(0编辑  收藏  举报