注:文中有个易混淆的地方"事务"
- sql事务,即每次数据库操作生成的事务,这个事务trx_id只在undolog里存储,同时undolog维护了此事务是否完成的状态。
- 日志持久化事务,为了保证redolog和binlog的一致性而用的Mysql内部独立维护的2PC提交事务。这个xid只有在redolog和binlog持久化文件中存储。
各日志的存储内容
阅读前提:需要对mysql的数据存储结构有一定了解,即数据页的持久化和内存读取逻辑。
binlog日志
binlog日志存储的是对数据库实际的数据操作,可以理解为存储的所有的数据库更新sql。
mysql默认不开启binlog,binlog主要用于主从同步和与其他数据库的数据共享(通过中间件监听binlog)。
undolog日志
undolog存储的是事务的回滚数据,存储的数据回滚的关键信息。undolog数据存储在undolog表空间中,也是通过数据页的形式存储,和普通的数据页一样,也会不定期的进行持久化。
undolog也通过页存储,有自己独立的表空间,所以undolog记录的时候,旧的undolog可能会被覆盖(当然mysql会保证未提交事务的undolog和用于mvvc的undolog是不会被覆盖的),同时也会生成相应的redolog。有的人理解为redolog里也存储了undolog的日志,其实是不对的,这个日志只是用来恢复undolog表空间的,并不是undolog实际的日志。
redo log日志
redolog存储的是对页结构的更新日志,可以理解为记录了数据页里修改了哪几个字节。用于mysql崩溃后的数据恢复,数据存储在ib_logfile中。
redolog中有一个重要参数即checkpoint_lsn记录了哪些redolog对应的数据页已经持久化了,是数据恢复的一个非常重要的参数。
同时为了保证数据持久化,事务提交时所有的redolog必须持久化,由于多个事务的redolog是可以穿插写入的,这就导致有部分未提交的事务被刷盘了。
redolog和binlog的二阶段提交
redolog和binlog的二阶段提交主要是为了防止系统崩溃时,redolog写完,binlog没有写,导致主从不一致的问题。
innodb维护了一套事务表(注意这里的事务不是mysql的事务,是redolog持久化的事务),redolog和binlog持久化时会生成一个新的事务,并分配一个xid即2PC事务id给这次持久化操作。
持久化流程
- redolog写盘并存储xid
- undolog写盘并存储xid,2PC事务标记已提交,redolog事务提交。
崩溃恢复
- 扫描最后一个binlog文件,提取其中的xid;
- InnoDB 维持了状态为Prepare的事务链表,将这些事务的xid和binlog中记录的xid做比较,如果在binlog中存在则提交,不存在则回滚事务。
数据恢复流程 基于binlog redolog undolog
- 通过binlog的xid和事务链表中的事务xid比较,找到不存在的事务的xid,去redolog中把这些事务回滚(删除)。
- 以checkpoint点的redolog为起点开始恢复数据,即恢复上图checkpoint到binlog之间的redolog数据。
- 由于undolog数据页的修改也记录在redolog中,未写盘的undolog数据页也被恢复。
- 在undolog表空间中查询中未提交的事务(Sql事务)执行undolog日志进行回滚
- 数据恢复完成
参考资料:《MySQL是怎样运行的》及其他网络资料