深入 MySQL (二) 文件系统

  1. binlog(二进制日志)
  2. redo log(重做日志)
  3. undo log (回滚日志)
  4. 两阶段提交
  5. 延伸阅读

本文介绍 MySQL 的几个重要的日志文件以及两阶段提交的原理。

binlog(二进制日志)

  • binlog 是MySQL Server 层的逻辑日志,可以被所有存储引擎使用;
  • binlog 日志常用于数据恢复、复制以及审计;
  • binlog 可以是 ROW、 STATEMENT、MIXED 三种格式:
    • ROW 格式下 binlog 日志记录的是每个数据行变化前和变化后的内容,因此占用空间相对较大;
    • STATEMENT格式 下,binlog 日志记录的是执行的 SQL 语句;
    • MIXED 格式下,默认采用 STATEMENT 格式,某些情况下会选择性地采用 ROW 格式;
  • 仅凭 binlog 日志是不能确保MySQL crash-safe的;
  • binlog日志是顺序追加写到磁盘文件,文件达到一定大小后会切换到下一个,因此不会发生数据覆盖;
  • 重要主库推荐配置 sync_binlog=1 ,可以使得MySQL每次提交事务都会将binlog日志同步到磁盘上,保证服务器崩溃的时候不会丢失数据;此外,如果是 Innodb 引擎,还需要配置 innodb_support_xa 为 1,才能确保二进制日志与 InnoDB 存储数据文件的同步(也就是下文的两阶段提交确保不丢失数据)。

redo log(重做日志)

  • redo log是InnoDB引擎特有的物理日志;

  • WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘数据;

  • redo log记录的是某个数据页做了什么修改;

  • 凭借redo log可以确保InnoDB的crash-safe;凭借redo log和binlog实现的两阶段提交可以保障MySQL的crash-safe;

  • redo log日志是固定大小的循环写,超过文件大小会擦除老日志;

    redo log循环写.png

  • 重做日志并不是直接写日志文件,而是先写一个重做日志缓冲(redo log buffer),然后再按照一定条件顺序写入日志文件。常见条件包括:

    • 主库配置 innodb_flush_log_at_trx_commit=1 ,可以使得每次提交事务都会将 buffer 刷到日志文件,保证服务器崩溃的时候不会丢失数据;
    • 主线程每秒会将重做日志缓冲写入日志文件,不论事务是否已经提交。

undo log (回滚日志)

  • 回滚日志记录的是事务的行为,当事务由于某种原因执行失败或者用户手动回滚的时候,便可以通过回滚日志来恢复缓冲池数据至历史版本;
  • 回滚日志默认保存在共享表空间中(也就是 ibdata 文件中);如果配置了 innodb_undo_tablespaces=N,则会保存到单独的undo001~undoN 文件中;

两阶段提交

两阶段提交.png

两阶段提交过程:

  • 1.新数据更新到内存;
  • 2.新数据写入redo log,并处于prepare状态;
  • 3.写入binlog;
  • 4.提交事务,使redo log 更新为commit状态。

crash-safe保障原理:

  • 如果在步骤2之前数据库宕机,因为redo log 和binlog都没写入,内存数据丢失,所以不影响一致性;
  • 如果在步骤3之前数据库宕机,因为redo log存在且处于prepare状态,但检查binlog发现不存在,则回滚事务。所以不影响数据一致性;
  • 如果在步骤4之前数据库宕机,因为redo log存在且处于prepare状态,而检查binlog发现存在,则执行步骤4。所以事务成功,也不影响数据一致性;
  • 如果在步骤4之后数据库宕机,因为redo log存在且处于commit状态。所以不影响数据一致性。

binlog和redo log的联系:

它们有一个共同的数据字段,叫XID。崩溃恢复的时候,会按顺序扫描redo log:如果碰到commit状态的redo log,就直接提交;如果碰到只有 parepare状态的redo log,就拿着XID去binlog找对应的事务。

延伸阅读


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 duval1024@gmail.com

×

喜欢就点赞,疼爱就打赏