• MySQL重做日志(redo log)


    为什么要有 redo log

    用个酒店掌柜记账的例子说明 redo log的作用。

    酒店掌柜有一个粉板,专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账的人多了,粉板总会有记不下的时候,这个时候掌柜一定还有一个专门记录赊账的账本

    如果有人要赊账或者还账的话,掌柜一般有两种做法:

    1. 直接翻开账本记录(直接写磁盘)
    2. 先记在粉板(redo log)上,等空闲时再记录到账本(磁盘)上

    当生意火爆时,不停有人来要赊账或者还账(更新操作),如果掌柜还是用第一种做法,由于记到账本上需要查找记录(随机读)那就会出现大量的人(更新操作)在等待,会影响工作(阻塞)。

    第二种做法,先记在粉板上,空闲时再写回账本。因为记粉板的速度是很快的,就能大量处理赊账或者还账,当掌柜(MySQL)没那么忙的时候,就把粉板上的内容记到账本上。但如果粉板(redo log)写满了,那这时候掌柜(MySQL)就要停下工作,先去把粉板(redo log)的内容写回账本(磁盘)。

    两种做法的区别是:

    1. 第一种是要找到记录后更新,这里涉及随时读,而随时读是很费时间的
    2. 第二种是记在日志上,这是顺序写的,而顺序写是很快的

    因此MySQL采用第二种做法,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。

    这就是WAL(Write-Ahead Logging),先写日志,再写磁盘。

    与粉板类似,redo log 也是有固定大小的。比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

    image

    两个指针:

    • write pos是当前记录的位置
    • checkpoint是当前要擦除的位置

    有了 redo log,InnoDB 可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。

    如何写入

    下面以一条Update语句来介绍 binlog 是如何记录的。这里在 binlog 里也有介绍过。

    mysql> update T set c=c+1 where ID=2;
    

    image

    1. 取得 ID=2 这一行(通过内存或磁盘读取)
    2. 这行的 c 值加1
    3. 更新到内存
    4. 写入 redo log(处于 prepare 阶段)
    5. 写 binlog
    6. 提交事务(处于 commit 状态)

    两阶段提交

    上面的流程采用了两阶段提交,那为什么要采用两阶段提交呢?是为了让 binlog 和 redo log 之间的逻辑一致。

    我们假设一下上面的 update 语句在执行的每个时刻,MySQL 崩溃了,看一下两个日志间的逻辑是如何保持一致的。

    • 假设在步骤4前,MySQL崩溃重启,那么事务提交失败,不会影响数据。虽然更新了内存,但崩溃后,内存会丢失。
    • 假设在步骤4完成后崩溃,此时已经写入 redo log 了,重启后,发现 redo log 处于 prepare 阶段,就不恢复。
    • 假设在步骤5完成后崩溃,此时已经写入 binlog 了,重启后,发现 binlog 已经写入了,就把对应的 redo log 改为 commit 状态。

    这样就能保证 redo log 和 binlog 的逻辑一致性。

    两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案。

    如何使用

    这里要介绍一下 redo log 里非常重要的一个参数:innodb_flush_log_at_trx_commit

    innodb_flush_log_at_trx_commit=0 表示提交事务的时候,不立即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存里的数据全部丢失。

    innodb_flush_log_at_trx_commit=1 表示提交事务的时候,就必须把 redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么 redo log 就必然在磁盘里了。注意,因为操作系统的“延迟写”特性,此时的刷入只是写到了操作系统的缓冲区中,因此执行同步操作才能保证一定持久化到了硬盘中。

    innodb_flush_log_at_trx_commit=2 表示提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件,可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。

    如何选择

    • 对数据丢失很敏感,设置为1,保证写到磁盘上。但性能较差。
    • 对数据不太敏感,设置为0或2,性能较好。但可能会丢失1秒的数据。

    如何查看和设置

    通过以下命令查看当前 innodb_flush_log_at_trx_commit 的值是多少:

    mysql> select @@innodb_flush_log_at_trx_commit;
    +----------------------------------+
    | @@innodb_flush_log_at_trx_commit |
    +----------------------------------+
    |                                1 |
    +----------------------------------+
    1 row in set (0.00 sec)
    

    在 /etc/mysql/my.cnf 文件里设置 innodb_flush_log_at_trx_commit 选项:

    #/etc/mysql/my.cnf
    innodb_flush_log_at_trx_commit=1
    

    修改后,重启 MySQL 服务即可。

    redo log 与 binlog 的区别

    • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
    • redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑
    • redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。
  • 相关阅读:
    数据预处理
    数据挖掘-聚类分析
    数据挖掘分类--判别式模型 ----支持向量机
    神经网络
    数据挖掘-贝叶斯定理
    数据挖掘之分类和预测
    关于stm32的IO口的封装
    星际炸弹——炸弹爆炸时间计算
    共阳极数码管三极管驱动
    自定义的TIME.H头文件
  • 原文地址:https://www.cnblogs.com/wht123/p/14258092.html
Copyright © 2020-2023  润新知