关于日志的那些事
2018.11.19 16:58今天刚好看到了 MySQL 中日志系统的设计,谈谈自己的理解。
mysql 中有两个十分重要的日志模块 —— redo log 和 binlog。
redo log
顾名思义,是重做日志。redo log 是由 InnoDB 引擎实现的。
当有一条记录需要更新时,InnoDB 会把记录写到 redo log 里,并更新内存,更新就算完成了。之后 InnoDB 会在空闲的时候,把日志里的操作记录拿出来,更新到磁盘上。
这种技术就是 WAL - Write-Ahead Logging,即先写日志再写磁盘。
为什么要这样做呢?
首先如果没有 redo log ,更新操作是这样的:客户端发起更新请求 -> InnoDB 开始处理更新 -> 先从磁盘中找到对应的记录 -> 更新这条记录到磁盘中。整个过程 I/O 成本、查找成本都很高。
而有了 redo log,InnoDB 当下不需要到磁盘中查找对应的记录,只需要把这条更新行为记录到日志中,并更新内存中的数据即可。然后等空闲的时候,再从 redo log 中拿出那些待处理的日志开始处理,这中间甚至可能会有一些重复的操作,也可以顺便进行合并,效率提高了不是一点点啊。
redo log 的一些细节
InnoDB 的 redo log 是固定大小的,也就是说一旦写满了,InnoDB 就需要提前开始清算工作,把一部分日志对应的操作落实到磁盘上,以便释放这部分空间让后面的日志能够写进来。
有了 redo log,InnoDB 就能够应对异常重启问题,之前提交的记录都不会丢失,这个能力称为 crashed-safe。
binlog
redo log 属于 InnoDB 引擎层的日志,是物理日志,而 binlog 属于 mysql server 层面的日志,是逻辑日志。
binlog 记录的是原始操作,并且可以不断追加写入,不需要覆盖以前的日志
一个数据的更新操作可以描述如下:
- 先找到对应要被更新的记录,优先在内存中找,找不到的话再从磁盘读入到内存中返回
- 更新数据结果到内存中,同时将这个操作记录到 redo log 中,此时 redo log 处于 prepare 状态,然后告知执行器执行完成,随时可以提交事务。
- 执行器生成这个对应的 binlog ,并写入到磁盘中
- 执行器调用引擎的事务提交接口,引擎把刚刚的 redo log 记录更新为 commit 状态。
这里使用到了两阶段提交,来保证事务的一致性。 也就是说,redo log 所记录的行为必须与 binlog 所记录的行为一致才行,两个日志不一致,最终一定会导致数据不一致。
启发
- 不要不重视日志,在很多系统中,日志也极为重要
- 在程序设计中,我们也有很多地方可以借鉴 redo log 和 binlog 的设计,将一些耗时耗性能的事情放到空闲时候做。感觉有点类似于生产者 - 消费者模式,比如我们分析用户行为,可以把用户行为先写入到日志中,之后再由别的程序消费日志中的数据,分析用户行为。
- 日志可以用来重放某一时间段内发生的事情,保留日志我们能够复原现场。
最后
关于 mysql 日志的知识点是从专栏 —— MySQL实战45讲 中看到的,作者原文讲的很棒,推荐你也去订阅看看。

痕迹
没有过去,就没法认定现在的自己
