MySQL Binlog/Redolog和CrashSafe机制

redo log

redo log是MySQL InnoDB的日志, 是物理日志, 记录的是"在某个数据页上做了什么修改"

提一下MySQL里经常说到的WAL技术, WAL的全称是Write Ahead Logging, 它的关键点就是先写日志, 再写磁盘. 日志是顺序写的, 磁盘是随机写. 顺序写速度是比随机写快的.

当有一条记录需要更新的时候, InnoDB引擎就会先把记录写到redo log 里面, 并更新内存, 这个时候更新就算完成了. 同时, InnoDB引擎会在适当的时候, 将这个操作记录更新到磁盘里面, 而这个更新往往是在系统比较空闲的时候做

redo log的大小

InnoDB的redo log是固定大小的, 比如可以配置为一组4个文件, 每个文件的大小是1GB, 那么总共就可以记录4GB的操作. 从头开始写, 写到末尾就又回到开头循环写

redo log的两个指针

  1. write pos是当前记录的位置, 一边写一边后移, 写到第3号文件末尾后就回到0号文件开头.
  2. checkpoint是当前要擦除的位置, 也是往后推移并且循环的, 擦除记录前要把记录更新到数据文件. write pos和checkpoint之间的是文件上还空着的部分, 可以用来记录新的操作. 如果write pos 追上checkpoint, 表示文件满了, 这时候不能再执行新的更新, 需要把redo log对应的所有脏页都flush到磁盘上, 把checkpoint推进一下, 让redo log留出空间继续写

binlog

binlog是MySQL Server的日志, binlog是逻辑日志, 记录的是这个语句的原始逻辑, 比如"给 ID = 2这一行的 c 字段加 1 "

binlog的大小

binlog是追加写入的. “追加写”是指binlog文件写到一定大小后会切换到下一个, 并不会覆盖以前的日志

一个更新操作的流程

  1. 执行器(Server)先找引擎取ID=2这一行. ID是主键, 引擎直接用树搜索找到这一行. 如果ID=2这一行所在的数据页本来就在内存中, 就直接返回给执行器; 否则, 需要先从磁盘读入内存, 然后再返回.
  2. 执行器拿到引擎给的行数据, 把这个值加上1, 比如原来是N, 现在就是N+1, 得到新的一行数据, 再调用引擎接口写入这行新数据
  3. 如果数据页在内存中就直接更新, 而如果这个数据页还没有在内存中的话, 在不影响数据一致性的前提下, InooDB会将这些更新操作缓存在change buffer(用的是buffer pool里的内存)中
  4. 引擎将这个更新操作记录到redo log里面 (如果把innodb_flush_log_at_trx_commit设置成1, 那么redo log在prepare阶段就要刷盘一次), 此时redo log处于prepare状态. 然后告知执行器执行完成了, 随时可以提交事务.
  5. 执行器生成这个操作的binlog, 并把binlog写入磁盘 (sync_binlog设置为1).
  6. 执行器调用引擎的提交事务接口, 引擎把刚刚写入的redo log改成提交(commit)状态(如果innodb_flush_log_at_trx_commit设置成1, 则redo log更改成commit状态时, 无需再次刷盘, 只写到文件系统中, redo log的prepare阶段就已经刷盘了), 更新完成

crash后mysql如何使用redo log和binlog进行校验

如果binlog写入完成, redo log未改成提交状态时, mysql crash了, 则mysql重启后, 会检查redo log为prepare的记录, 通过xid这个共同的字段与binlog的记录进行对比.

  1. 若redo log中存在的记录, 但binlog中没有, 则mysql认为此事务需要回滚
  2. 若redo log中存在的记录, binlog中也存在且是完整的, 则认为此次事务已完成, 将redo log改成提交状态

为什么日志要用二阶段提交

假设当前ID=2的行, 字段c的值是0, 再假设执行update语句 + 1 过程中在写完第一个日志后, 第二个日志还没有写完期间发生了crash

  1. 如果先写redo log再写binlog: 假如redo log写完后mysql崩溃, 由于redo log写完后, mysql即使崩溃, 仍然可以把数据恢复回来. 通过redo log恢复后, 数据库值为1, 如果后续通过binlog恢复备库数据时, 就会少了这一次更新, 备库数据为0, 数据不一致
  2. 如果先写binlog再写redo log: 假如binlog写完后mysql崩溃, 数据库就无法把数据恢复回来, 数据仍然为0, 但使用binlog恢复备库数据时会多了这一次更新, 备库数据为1, 数据不一致

只使用redolog或binlog中的其一能否实现crash-safe

  1. 只用redolog: 仍然可以实现crash-safe, 但是binlog在mysql中可以用来归档和主从复制, 有非常多基于binlog的中间件
  2. 只用binlog: 不能实现crash-safe, 因为binlog是逻辑日志, 不能实现数据页级别的恢复, 数据落盘是以页为单位,而一个sql可能涉及多个页(如abc三页),一旦crash的时候,只有a没有落盘,bc落盘了,那么根据sql进行重放就会出错了

相关参数的设置

  1. redo log用于保证crash-safe能力. innodb_flush_log_at_trx_commit这个参数设置成1的时候, 表示每次事务的redo log都直接持久化(fsync)到磁盘. 设置成1, 可以保证MySQL异常重启之后数据不丢失. 如果设置0, 每隔1s将数据持久化到磁盘. 设置为2, 事务提交后, 将数据提交到文件系统缓存内, 由文件系统控制何时持久化到磁盘
  2. sync_binlog这个参数设置成1的时候, 表示每提交1次事务, binlog都持久化到磁盘. 这个参数建议设置成1, 这样可以保证MySQL异常重启之后binlog不丢失. 若设置成0, 表示事务提交之后, 将数据提交到文件系统, 不立马持久化到磁盘, 而让文件系统自行决定什么时候来做同步, 或者cache满了之后才同步到磁盘

change buffer

当需要更新一个数据页时, 如果数据页在内存中就直接更新, 而如果这个数据页还没有在内存中的话, 在不影响数据一致性的前提下, InooDB会将这些更新操作缓存在change buffer中, 这样就不需要从磁盘中读入这个数据页了. 在下次查询需要访问这个数据页的时候, 将数据页读入内存, 然后执行change buffer中与这个页有关的操作. 通过这种方式就能保证这个数据逻辑的正确性.

需要说明的是, 虽然名字叫作change buffer, 实际上它是可以持久化的数据. 也就是说, change buffer在内存中有拷贝, 也会被写入到磁盘上. 将change buffer中的操作应用到原数据页, 得到最新结果的过程称为merge. 除了访问这个数据页会触发merge外, 系统有后台线程会定期merge. 在数据库正常关闭(shutdown) 的过程中, 也会执行merge操作.

显然, 如果能够将更新操作先记录在change buffer, 减少读磁盘, 语句的执行速度会得到明显的提升. 而且, 数据读入内存是需要占用buffer pool的, 所以这种方式还能够避免占用内存, 提高内存利用率

但是假设一个业务的更新模式是写入之后马上会做查询, mysql将更新先记录在change buffer, 但之后由于马上要访问这个数据页, 会立即触发merge过程. 这样随机访问IO的次数不会减少, 反而增加了change buffer的维护代价. 所以, 对于这种业务模式来说, change buffer反而起到了副作用

原文地址:https://cloud.tencent.com/developer/article/2191508

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340