- 事务在执行过程中,先把日志写到
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 -- 数据可靠性」获取最佳阅读体验并参与讨论
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Zero to One
Peter Thiel、Blake Masters / Crown Business / 2014-9-16 / USD 27.00
“This book delivers completely new and refreshing ideas on how to create value in the world.” - Mark Zuckerberg, CEO of Facebook “Peter Thiel has built multiple breakthrough companies, and ......一起来看看 《Zero to One》 这本书的介绍吧!