Semi-sync 流程
概况
Semi-sync 利用原有的异步模式,通过嵌入等待从库ack binlog pos的模式,实现事务同步等待,保证事务提交前完成binlog redo 发送到slave节点
问题
After_sync 确认为ack应答为group commit 阶段的第三阶段开始,如果在收到应答之前宕机,会出现主从不一致的情况。
1 sync_binlog 为1 时 发送binlog的时机为binlog sync 之后,在宕机的瞬间无法确定从库是否收到binlog
1>从库未收到binlog 则主比从多一个事物
2>冲库收到binlog ,则主从一致
2 sync_binlog 为0 或者 大于1 时,发送binlog的时机为group commit 的一阶段内,
在收到ack应答前宕机
1>设sync_binlog 为100 ,则前99条从库一定有,第100条从库不一定有,主库这100条存在多少不确定,可能全都有,可能仅有一部分,可能一条都没有sync到磁盘,
主从不一致的存在很多不确定性,从库的最后一个事物不确定是否存在
从安全的角度,较好的解决方案:
Sync_binlog 设置为1 ,主库宕机后,切换到从库,主库需要修复,数据从从库全量数据复制一份,保持与从库一致。当从库为主库时,旧主库与新主库数据不一致的可能性非常大
整体流程
1 semi-sync 在原有异步复制的基础上,启动一个ack线程等待从库的应答,确定从库接收的binlog及大小(binlog的偏移地址)
2 semi 通过插件的形式,在第三阶段通过阻塞等待的形式,等待从库的应答
3 ack线程得到从库的应答后,即binlog的pos(文件大小),大于等待线程生成binlog的偏移大小,则说明binlog 已经到达从库并保存,ack激活阻塞的此线程,用户线程返回此事务执行完毕的应答
Update 流程
Update set xx=xx where id=xx id为主键
1 开启一个事物,生成事物id
2 根据索引条件,通过B+tree 索引确定数据页的pageid (确定是否在内存中,如果不在则读取磁盘)
3 在页内通过二分法查找到记录,添加行锁,分别添加当前事物的锁链表和page页的锁链表上
4 添加undo log ,先分配undo 空间,添加undo 到链表中,添加undo log的redo日志,
Redo日志添加完成后,写入unlog日志,把当前修改的数据,增加到undo log中,当前行中的undo 链表指向此redo日志
5 添加数据的redo日志,redo日志写完后,把当前事物id 及整理数据修改到当前数据行中(修改数据长度与当前行的数据长度一致),并把此页添加到脏页链表中
6 引擎层数据修改完成后,返回sever层,生成binlog数据,保存到线程binlog Cache中
7 commit提交
Group commit 中一阶段 sync redo 日志,把redo日志sync到磁盘
生成binlog,并把binlog 写入pageCache
二阶段 sync binlog ,把binlog 写入磁盘
三阶段 引擎层事务提交,释放行锁,修改事务的状态,事务完成,数据可见