- 事务在执行过程中,先把日志写到
binlog cache,事务 提交 时,再把binlog cache写到binlog file - 一个事务的binlog是 不能被拆开 的,不论事务多大,也要确保 一次性写入
- 系统会给 每个线程 分配一块内存
binlog cache,由参数binlog_cache_size控制- 如果超过了
binlog_cache_size,需要 暂存到磁盘
- 如果超过了
- 事务提交时,执行器把
binlog cache里面的 完整事务 写入到binlog file,并 清空binlog cache
-- 2097152 Bytes = 2 MB mysql> SHOW VARIABLES LIKE '%binlog_cache_size%'; +-----------------------+----------------------+ | Variable_name | Value | +-----------------------+----------------------+ | binlog_cache_size | 2097152 | | max_binlog_cache_size | 18446744073709547520 | +-----------------------+----------------------+
写入过程
- 每个线程都有自己的
binlog cache,但共用一份binlog file -
write:把日志写入到 文件系统的page cache ,但并没有将数据持久化到磁盘, 速度比较快 -
fsync:将数据持久化到磁盘,fsync才会占用磁盘的 IOPS
sync_binlog
mysql> SHOW VARIABLES LIKE '%sync_binlog%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | sync_binlog | 0 | +---------------+-------+
-
sync_binlog=0,每次提交事务都只write,不fsync -
sync_binlog=1,每次提交事务都会执行fsync -
sync_binlog=N,每次提交事务都会write,但累计N个事务后才fsync- 一般为
(100 ~ 1,000),可以 提高性能 - 如果主机 断电 ,会 丢失最近的N个事务的binlog
- 一般为
redolog的写入机制
- 事务在执行过程中,生成的
redolog需要先写到redolog buffer -
redolog buffer里面的内容,并不需要 每次 生成后都直接持久化到磁盘- 如果事务执行期间,MySQL异常重启,那么这部分日志丢失了
- 由于事务 没有提交 ,所以这时的日志丢失不会有什么影响
- 在事务还未提交时,
redolog buffer中的 部分日志 也是有可能 持久化到磁盘 的
redolog的状态
- 红色部分:存在于
redolog buffer中,物理上存在于 MySQL进程的内存 - 黄色部分:写到磁盘(
write),但没有持久化(fsync),物理上存在于 文件系统的page cache - 绿色部分:持久化到磁盘,物理上存在于
hard disk - 日志写到
redolog buffer是很快的,write到FS page cache也比较快,但fsync到磁盘的速度就会慢很多
redolog的写入策略
事务提交
mysql> show variables like '%innodb_flush_log_at_trx_commit%'; +--------------------------------+-------+ | Variable_name | Value | +--------------------------------+-------+ | innodb_flush_log_at_trx_commit | 2 | +--------------------------------+-------+
-
innodb_flush_log_at_trx_commit=0- 每次事务提交时都只是将
redolog写入到redolog buffer( 红色部分 ) -
redolog只存在内存中,MySQL本身异常重启也会丢失数据, 风险太大
- 每次事务提交时都只是将
-
innodb_flush_log_at_trx_commit=1- 每次事务提交时都将
redolog持久化到磁盘( 绿色部分 ) - 两阶段提交:
redolog prepare->写binlog->redolog commit -
redolog prepare需要持久化一次,因为崩溃恢复依赖于 prepare 的redolog和binlog -
redolog commit就不需要持久化(fsync)了,只需要write到FS page cache即可 - 双1配置 :一个事务完整提交前,需要 2次刷盘 :
redolog prepare+binlog- 优化: 组提交
- 每次事务提交时都将
-
innodb_flush_log_at_trx_commit=2- 每次事务提交时都将
redolog写入到FS page cache( 黄色部分 )
- 每次事务提交时都将
后台刷新
- 后台线程:每隔 1秒 ,就会将
redolog buffer中的日志,调用write写入到FS page cache,再调用fsync持久化到磁盘 - 事务执行期间的
redolog是直接写到redolog buffer,这些redolog也会被后台线程一起持久化到磁盘- 即一个 未提交 的事务的
redolog也是有可能已经持久化到磁盘的
- 即一个 未提交 的事务的
事务未提交
-- 16777216 Bytes = 16 MB mysql> SHOW VARIABLES LIKE '%innodb_log_buffer_size%'; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | innodb_log_buffer_size | 16777216 | +------------------------+----------+
- 当
redolog buffer占用的空间即将达到innodb_log_buffer_size的 一半 时,后台线程会 主动写盘- 由于事务尚未提交,因此这个写盘动作是在
write,不会调用fsync,停留在FS page cache
- 由于事务尚未提交,因此这个写盘动作是在
- 在 并行事务提交 时,顺带将 未提交事务 的
redolog buffer持久化到磁盘- 事务A执行到一半,有部分
redolog在redolog buffer - 事务B提交,且
innodb_flush_log_at_trx_commit=1,事务B要把redolog buffer里面的日志 全部 持久化到磁盘 - 这时会带上事务A在
redolog buffer里的日志一起持久化到磁盘
- 事务A执行到一半,有部分
组提交
LSN
-
LSN:log sequence number -
LSN是 单调递增 的,对应redolog的 写入点- 每次写入长度为length的
redolog,LSN就会加上length
- 每次写入长度为length的
-
LSN也会写入到 数据页 中,用来 确保数据页不会被多次执行重复的redolog
样例
- 三个 并发事务 处于
prepare阶段:tx1、tx2、tx3- 都完成写入
redolog buffer和 持久化到磁盘 的过程 - 对应的
LSN为50、120、160
- 都完成写入
-
tx1第一个到达,被选为组leader - 等
trx1要开始 写盘 的时候,组内已经有3个事务,LSN变成了160 -
trx1带着LSN=160去写盘,等trx1返回时,所有LSN<160的redolog都已经持久化到磁盘-
trx2和trx3可以 直接返回
-
小结
- 一次组提交里面,组员越多,节省磁盘的IOPS的效果越好
- 在 并发更新 场景下,第1个事务写完
redolog buffer后,接下来的fsync越晚调用,节省磁盘的IOPS的效果越好
binlog组提交
写binlog 其实分两步:
binlog cache -> (write) -> binlog file +
binlog file -> (fsync) -> disk
MySQL为了让组提交效果更好,延后了 fsync 执行时机,两阶段提交细化如下
binlog 也可以支持 组提交 了,但第3步执行很快,导致了 binlog 的组提交效果不如 redolog 的组提交效果
参数
mysql> SHOW VARIABLES LIKE '%binlog_group_commit_sync%'; +-----------------------------------------+-------+ | Variable_name | Value | +-----------------------------------------+-------+ | binlog_group_commit_sync_delay | 0 | | binlog_group_commit_sync_no_delay_count | 0 | +-----------------------------------------+-------+
-
binlog_group_commit_sync_delay:延迟多少 微秒 才调用fsync -
binlog_group_commit_sync_no_delay_count:累计多少次之后才调用fsync - 两者关系: 或 ,但当
binlog_group_commit_sync_delay=0时,binlog_group_commit_sync_no_delay_count无效
WAL性能
-
redolog和binlog都是 顺序写 - 组提交机制 :可以大幅降低磁盘的 IOPS消耗
MySQL的IO瓶颈
- 设置
binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count- 故意等待 ,利用 组提交 减少 IOPS 消耗,同时可能会 增加语句的响应时间 ,但 没有丢数据风险
-
sync_binlog=N(100~1,000)- 主机 断电 会丢失
binlog日志
- 主机 断电 会丢失
-
innodb_flush_log_at_trx_commit=2- 主机 断电 会丢失数据
-
2和0的 性能接近 ,但设置为0(数据仅在redolog buffer),在MySQL 异常重启 时也会丢失数据
crash-safe的保证
- 如果客户端收到 事务成功 的消息,事务就一定持久化了的
- 如果客户端收到 事务失败 (主键冲突、回滚等)的消息,事务一定是失败的
- 如果客户端收到 执行异常 的消息,应用需要 重连 后通过 查询 当前状态来继续后续的逻辑
- 数据库只需要保证内部( 数据与日志之间 , 主从之间 )一致即可
参考资料
《MySQL实战45讲》
转载请注明出处:http://zhongmingmao.me/2019/02/21/mysql-reliability/
访问原文「MySQL -- 数据可靠性」获取最佳阅读体验并参与讨论
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Filter Bubble
Eli Pariser / Penguin Press / 2011-5-12 / GBP 16.45
In December 2009, Google began customizing its search results for each user. Instead of giving you the most broadly popular result, Google now tries to predict what you are most likely to click on. Ac......一起来看看 《The Filter Bubble》 这本书的介绍吧!