23 | MySQL是怎么保证数据不丢的?
23 | MySQL是怎么保证数据不丢的?
讲述:林晓斌
时长17:04大小15.59M
binlog 的写入机制
redo log 的写入机制
小结
上期问题时间
赞 116
提建议
精选留言(182)
- 锅子置顶2019-01-04老师好,有一个疑问:当设置sync_binlog=0时,每次commit都只时write到page cache,并不会fsync。但是做实验时binlog文件中还是会有记录,这是什么原因呢?是不是后台线程每秒一次的轮询也会将binlog cache持久化到磁盘?还是有其他的参数控制呢?
作者回复: 你看到的“binlog的记录”,也是从page cache读的哦。 Page cache是操作系统文件系统上的😄 好问题
共 15 条评论166 - WilliamX2019-01-04为什么 binlog cache 是每个线程自己维护的,而 redo log buffer 是全局共用的? 这个问题,感觉还有一点,binlog存储是以statement或者row格式存储的,而redo log是以page页格式存储的。page格式,天生就是共有的,而row格式,只跟当前事务相关
作者回复: 嗯,这个解释也很好。👍🏿
共 7 条评论146 - alias cd=rm -rf2019-01-28事务A是当前事务,这时候事务B提交了。事务B的redolog持久化时候,会顺道把A产生的redolog也持久化,这时候A的redolog状态是prepare状态么?
作者回复: 不是。 说明一下哈,所谓的 redo log prepare,是“当前事务提交”的一个阶段,也就是说,在事务A提交的时候,我们才会走到事务A的redo log prepare这个阶段。 事务A在提交前,有一部分redo log被事务B提前持久化,但是事务A还没有进入提交阶段,是无所谓“redo log prepare”的。 好问题
共 16 条评论120 - 倪大人2019-01-04老师求解sync_binlog和binlog_group_commit_sync_no_delay_count这两个参数区别 如果 sync_binlog = N binlog_group_commit_sync_no_delay_count = M binlog_group_commit_sync_delay = 很大值 这种情况fsync什么时候发生呀,min(N,M)吗? 感觉sync_binlog搭配binlog_group_commit_sync_delay也可以实现组提交? 如果 sync_binlog = 0 binlog_group_commit_sync_no_delay_count = 10 这种情况下是累计10个事务fsync一次?展开
作者回复: 好问题,我写这篇文章的时候也为了这个问题去翻了代码,是这样的: 达到N次以后,可以刷盘了,然后再进入(sync_delay和no_delay_count)这个逻辑; Sync_delay如果很大,就达到no_delay_count才刷; 只要sync_binlog=0,也会有前面的等待逻辑,但是等完后还是不调fsync😄
共 8 条评论77 - Komine2019-01-22为什么binlog 是不能“被打断的”的呢?主要出于什么考虑?
作者回复: 好问题 我觉得一个比较重要的原因是,一个线程只能同时有一个事务在执行。 由于这个设定,所以每当执行一个begin/start transaction的时候,就会默认提交上一个事务; 这样如果一个事务的binlog被拆开的时候,在备库执行就会被当做多个事务分段自行,这样破坏了原子性,是有问题的。
共 4 条评论73 - 猪哥哥2019-01-10老师 我想问下文件系统的page cache还是不是内存, 是不是文件系统向内核申请的一块的内存?
作者回复: 你理解的是对的
共 3 条评论41 - 某、人2019-01-06有调到非双1的时候,在大促时非核心库和从库延迟较多的情况。 设置的是sync_binlog=0和innodb_flush_log_at_trx_commit=2 针对0和2,在mysql crash时不会出现异常,在主机挂了时,会有几种风险: 1.如果事务的binlog和redo log都还未fsync,则该事务数据丢失 2.如果事务binlog fsync成功,redo log未fsync,则该事务数据丢失。 虽然binlog落盘成功,但是binlog没有恢复redo log的能力,所以redo log不能恢复. 不过后续可以解析binlog来恢复这部分数据 3.如果事务binlog fsync未成功,redo log成功。 由于redo log恢复数据是在引擎层,所以重新启动数据库,redo log能恢复数据,但是不能恢复server层的binlog,则binlog丢失。 如果该事务还未从FS page cache里发送给从库,那么主从就会出现不一致的情况 4.如果binlog和redo log都成功fsync,那么皆大欢喜。 老师我有几个问题: 1.因为binlog不能被打断,那么binlog做fsync是单线程吧? 如果是的话,那么binlog的write到fsync的时间,就应该是redo log fsync+上一个事务的binlog fsync时间。 但是测试到的现象,一个超大事务做fsync时,对其它事务的提交影响也不大。 如果是多线程做fsync,怎么保证的一个事务binlog在磁盘上的连续性? 2. 5.7的并行复制是基于binlog组成员并行的,为什么很多文章说是表级别的并行复制?展开
作者回复: 1. Write的时候只要写进去了,fsync其实很快的。连续性是write的时候做的(写的时候保证了连续) 2. 你的理解应该是对的。不是表级
共 17 条评论36 - 浩瀚有边2019-08-28刚开始我也遇到了jacy一样的问题,认为binlog写到file里面就是写到disk了,就不理解为什么还要fsync,后来仔细回读了文章,发现binlog写到file是指写到pagecache,并不是disk。 建议老师在描述binlog写盘的那两个步骤时,把写到file直接描述为写到pagecache,避免歧义28
- xiaoyou2019-01-09老师,请教一个问题,文章说innodb的 redo log 在commit的时候不进行fsync,只会write 到page cache中。当sync_binlog>1,如果redo log 完成了prepare持久化落盘,binlog只是write page cache,此时commit标识完成write 但没有落盘,而client收到commit成功,这个时候主机掉电,启动的时候做崩溃恢复,没有commit标识和binglog,事务会回滚。我看文章说sync_binlog设置为大于1的值,会丢binlog日志,此时数据也会丢失吧?
作者回复: 你说的对,分析得很好
共 15 条评论23 - 一大只😴2019-01-05你是怎么验证的?等于0的时候虽然有走这个逻辑,但是最后调用fsync之前判断是0,就啥也没做就走了 回复老师: 老师,我说的sync_binlog=0或=1效果一样,就是看语句实际执行的效果,参数binlog_group_commit_sync_delay我设置成了500000微秒,在=1或=0时,对表进行Insert,然后都会有0.5秒的等待,也就是执行时间都是0.51 sec,关闭binlog_group_commit_sync_delay,insert执行会飞快,所以我认为=1或=0都是受组提交参数的影响的。展开
作者回复: 👍🏿 非常好 然后再补上我回答的这个逻辑,就完备了
21 - Mr.Strive.Z.H.L2019-01-08老师你好,看了@倪大人的问题,个人认为: sync_binlog和binlog_group_commit_sync_no_delay_count的最大区别主要在于,数据的丢失与否吧? sync_binlog = N:每个事务write后就响应客户端了。刷盘是N次事务后刷盘。N次事务之间宕机,数据丢失。 binlog_group_commit_sync_no_delay_count=N: 必须等到N个后才能提交。换言之,会增加响应客户端的时间。但是一旦响应了,那么数据就一定持久化了。宕机的话,数据是不会丢失的。 不知道我这么理解对不对?展开
作者回复: 你的理解很到位
共 9 条评论20 - liao xueqiang2019-03-01每秒一次后台轮询刷盘,再加上崩溃恢复这个逻辑,InnoDB 就认为 redo log 在 commit 的时候就不需要 fsync 了,只会 write 到文件系统的 page cache 中就够了。老师好,这句话怎么理解呢?这不是服务器重启的情况下,会丢失1秒的数据吗
作者回复: 不是,这意思就是,即使异常掉电,只要redo log的prepare 部分+binlog完整,就会保证不丢数据。 也就是说,最多会丢失1秒的“redo log commit信息”,但是这个commit信息丢失,并不会影响数据(就是崩溃恢复慢一点)
共 8 条评论12 - melon2019-02-28老师帮忙看一下我binlog 组提交这块理解的对不对 binlog write 阶段 组里面第一个走到 binlog write 的事务记录一个时间戳,用于在 binlog fsync 阶段计算 sync delay了多少时间,姑且计为 start_time 组里已 sync write 次数+1,姑且记为 group_write 全局已 sync wirte 次数+1,姑且记为 global_write binlog fsync 阶段 IF ( NOW - sart_time ) >= binlog_group_commit_sync_delay || group_write >= binlog_group_commit_sync_no_delay_count IF sync_binlog >0 && global_write >= sync_binlog fsync 设置 binlog 组提交信号,让其它等待的事务继续 ELSE 等待 binlog 组提交信号 另外 binlog_group_commit_sync_no_delay_count 这个参数是不是不应该设置的比并发线程数大,因为一个组里的事务应该不会比并发线程数多吧,设置大了也就没什么意义了,可以这么理解吧老师。展开
作者回复: 前面的伪代码不错哈 ”binlog_group_commit_sync_no_delay_count这个参数是不是不应该设置的比并发线程数大“,最好是这样的,否则的话,就只能等binlog_group_commit_sync_delay |时间到了
共 2 条评论10 - alias cd=rm -rf2019-01-28老师不好意思,我接着刚才的问题问哈 并发事务的redolog持久化,会把当前事务的redolog持久化,当前事务的redolog持久化后prepare状态么?redolog已经被持久化到磁盘了,那么当前事务提交时候,redolog变为prepare状态,这时候是从redologbuffer加载还是从磁盘加载?
作者回复: 每个事务在提交过程的prepare阶段,会把redolog持久化; “当前事务的redolog持久化后prepare状态么”这个描述还是不清楚,你用事务A、事务B这样来描述吧😆 redolog已经被持久化到磁盘了,那么当前事务提交时候, (其实这里只是“部分”被持久化,因为这个事务自己在执行的过程中,还会产生新的日志),只需要继续持久化剩下的redo log
共 3 条评论10 - Geek_5270202019-01-08事务还未结束,binlog和redo log就写到磁盘中了,如果出现了事务回滚,写到磁盘的数据要删除吗,如果不删除,MYSQL奔溃重启,岂不是多了操作,请老师解答下疑惑
作者回复: 没事,这些操作没提交,崩溃恢复的时候就回滚了
共 4 条评论9 - Justin2019-01-05您说的Lsn 确保不会二次执行 意思是持久化在磁盘中的页也有和redo log record相关的lsn吗 然后根据lsn的大小在recovery阶段确定redo log需不需要执行?
作者回复: 对的,lsn 就是写在数据页的 i
9 - jacy2019-05-301.先把 binlog 从 binlog cache 中写到磁盘上的 binlog 文件; 2.调用 fsync 持久化。 老师,这两步我不不太理解,写到磁盘binlog文件,不就是持久化了吗,为啥还要调用fsync再刷一次盘呢?能否帮忙解答一下,感谢🙏
作者回复: wrie很多次,fsync一次
共 2 条评论8 - 慧鑫coming2019-01-04这里提示和我一样的小白,注意老师最后的说的提升io性能方法3,是在主机掉电或os崩溃的时候,page cache 会丢失;而最后老师建议将redo log写到page cash,说的是能防止“MySQL异常重启时数据丢失”。也就是仅仅写数据的程序crash,那么已经写入page cash中的数据不会丢失,但如果系统crash或者重启的话,那就没办法啦😆
作者回复: 是的是的哦 最好就是机器Io特别好,不用改最好了。实在要改就尽量选风险小的
7 - 莫名2019-05-11老师,sync_binlog=N,N之间客户端已明确收到事务提交,而如果期间机器崩溃或掉电,重启会导致数据库数据也丢失或回滚,那不是客户端处理的数据可能也会有问题?比如账户类数据、银行转账等?望解惑!
作者回复: 是的 所以我们说,如果要保证数据不丢,就要设置=1
6 - HuaMax2019-01-04老师在解释组提交的原理那里的图中第二步应该是binlog cache写入到系统page cache的意思吧?
作者回复: 是的,write是到page cache
6