• mysql组提交


    当mysql开启binlog日志时,会存在一个内部XA的问题:事务在存储引擎层redo log的写入和binlog的写入一致性问题。

    mysql通过两阶段提交很好的解决了redo log和binlog一致性问题:

    第一阶段:innodb prepare, 持有prepare_commit_mutex,redo log持久化到磁盘(flush/sync redolog),并将回滚段设置为prepare状态。

    第二阶段:分为两步。

      a. flush/sync binlog

      b. commit(写入commit标记,释放prepare_commit_mutex,并释放回滚段)

    事务的崩溃恢复过程如下:

    1. 事务恢复时,扫描最后一个binlog,提取出其中的xid

    2. xid也会写到redo中,重做检查点后的所有事务,包括未提交的事务和已回滚的事务,读取事务的undo段信息,搜集处于prepare阶段的事务链表,将redo中prepared状态的xid与binlog中的xid做比较,如果在binlog中存在,则提交;否则回滚。

    为什么只扫描最后一个binlog?

    因为binlog rotate的binlog文件中对应的事务一定是已经提交的

    Group Commit:

    上面的整个过程,通过持有 prepare_commit_mutex来保证redolog的写入和binlog的写入完全一致,会导致group commit无法生效。

    在mysql56中,同时支持了redolog 和 binlog的组提交,其提交流程如下:

    第一阶段: innodb prepare(Redo Group Commit)

    在innodb中,每条redolog都有自己的LSN,这是一个单调递增的值。每个事务的更新操作都会包含一条或者多条redo log, 各个事务在将redo log写入 log_sys_buffer(通过log_sys mutex保护)时,都会获取当前事务最大的LSN。那么假设三个事务 tx1, tx2, tx3的最大LSN分别为 LSN1 < LSN2 < LSN3时,他们同时进行提交,如果tx3获取到了 log_mutex, 那么他会将小于LSN3之前的redo log一起落盘,这样 tx1, tx2不用再次请求磁盘io。同时,如果存在tx0的LSN0 < LSN3,LSN0也会落盘,即使tx0还没有提交。

    1. 获取 log mutex

    2. 如果 flushed_to_disk_lsn >= lsn, 表示日志已经被刷盘,跳转 5

    3. 如果 current_flush_lsn >= lsn, 表示日志正在刷盘中,跳转 5 后进入等待状态

    4. 将小于 lsn 的日志刷盘 (flush and sync)

    5. 退出 log_mutex

    第二阶段: Binlog Group Commit的基本思想是引入队列机制,保证 innodb commit 的顺序与 binlog落盘的顺序一致,并将事务分组,组内的 binlog刷盘动作交给一个事务进行,实现组提交的目的。队列中的第一个事务称为 leader, 其他事务称为 follower。所有的事情交给 leader 去做。: flush stage, sync stage, commit stage

    Flush Stage:

    将每个事务的 binlog 写入内存

    1. 持有 Lock_log mutex [leader持有,follwer等待]

    2. 获取队列中的一组 binlog(队列中的所有事务)

    3. 将 binlog buffer 到 I/O cache

    4. 通知 dump线程 dump binlog [sync_binlog != 1]

    Sync Stage:

    将内存中的二进制日志刷新到磁盘, 若队列中有多个事务,那么仅一次 fsync 操作就完成了二进制日志的写入,这就是 BLGC。

    1. 释放 Lock_log mutex, 持有 Lock_sync mutex[leader持有,follower等待]

    2. 将一组 binlog 落盘(sync操作,最耗时,假设 sync_binlog 为 1)

    3. 通知 dump线程 dump binlog [sync_binlog = 1]

    Commit Stage:

    leader根据顺序调用存储引擎层的提交

    1. 释放 Lock_sync mutex, 持有 Lock_commit mutex[ leader持有,follower等待]

    2. 遍历队列中的事务,逐一进行 innodb commit.

    3. 释放 Lock_commit mutex

    4. 唤醒队列中等待的线程。

    Redo Group Commit优化

    每个事务提交时,都会触发一次redo flush/sync动作,由于磁盘读写比较慢,因此很影响系统的吞吐量。

    mysql57中,做了针对redo group commit的优化。将 redo log的write/sync延迟到了binlog group commit的 flush stage之后,sync binlog之前。

    通过延迟写redo log的方式,显式的为redo log做了一次组写入,并减少了(redo log) log_sys->mutex的竞争。

    第一阶段:Innodb Prepare

    1. 记录当前的LSN到thd中

    第二阶段:Binlog Group Commit

    1. 进入Binlog Group Commit的flush阶段;同时,leader搜索队列,算出thd中最大的LSN

    2. 将innodb的redo log flush/sync到指定LSN

    3. sync binlog

    4. commit

    参考

    https://blog.csdn.net/weixin_38597669/article/details/104096684

    https://blog.csdn.net/zhang123456456/article/details/83857127

  • 相关阅读:
    【JavaScript知识点一】JavaScript 数据类型
    grunt操作之Gruntfile.js
    js重定向后跳转到当前页面锚点
    Java-变量和方法
    Java-运算符
    Java-类型转化
    Java-数组
    Java-循环结构(for,while)
    Java-选择结构(if-else)
    Java-数据类型(引用类型)
  • 原文地址:https://www.cnblogs.com/juanmaofeifei/p/13324674.html
Copyright © 2020-2023  润新知