0

0

一文贯通MySQL日志

WBOY

WBOY

发布时间:2022-10-07 09:00:29

|

2544人浏览过

|

来源于掘金

转载

本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了关于日志的相关问题,mysql的日志系统是mysql保证无论何时崩溃数据都不会丢失的关键,下面一起来看一下,希望对大家有帮助。

一文贯通MySQL日志

推荐学习:mysql视频教程

Mysql的日志系统是Mysql保证无论何时崩溃数据都不会丢失的关键

众所周知Mysql是持久化的数据库, 所有的数据都是持久化到硬盘中的, 保证数据不会丢失

Mysql保证数据不会丢失是从以下两个方面来体现的

  • 能够恢复到任意时刻的数据状态

  • 无论在事务提交前还是提交后崩溃都能保证数据不丢失

事务过程中崩溃能够恢复到事务提交前的状态

事务提交后崩溃已提交的数据不会丢失

MySQL保证以上两个点的关键就是通过 undo log, redo log 和 binlog 这三个日志来实现的, 接下来将逐一介绍

undo log 回滚日志

undo log是Mysql的回滚日志, 存储的是老版本的数据

主要作用

存储老版本的数据

配合Read View和隐藏字段实现了Mysql的快照读

用于在事务执行失败的时候回滚到事务开始前的版本

undo log 有什么类型

undo log 有两种类型

对于 insert 命令, undo log 记录的是新增的记录的主键, 在回滚的时候根据 undo log 中的主键去删除对应的记录即可

对于 update / delete 命令, undo log 记录的是被修改的记录的旧数据

Mysql中的每一行数据都有一个最新修改当前数据行的事务id和回滚指针这两个字段, 当对数据行进行修改之后, undo log指针就会指向旧的这一行数据, 而新生成的这一行数据的回滚指针就会指向undo log指针当前指向的旧数据行

  • Mysql为了避免undo log指针修改指向的时候出现并发问题, 在修改之前会对undo log指针增加排他锁以保证undo log的正确写入

08.png

undo log 什么时候删除

undo log是用于保证事务在未提交的时候可以顺利回滚到事务开始前的状态, 当事务提交之后undo log就失去作用了, 就需要被删除

undo log是交由Mysql中的 Purage 线程来负责删除的, purage会定期检查undo log中的deleted_bit 标志, 这个标志会在事务提交后被设置为true, purage 线程发现为true的记录就会负责将其删除

redo log 重做日志

redo log是Mysql的物理日志, 负责记录某个数据页执行了什么样的操作

redo log 的作用

  • 负责记录提交的事务对数据的修改, 记录的内容大概就是对x表的y页z偏移做了a更新

  • 让Mysql在提交事务的时候无需等待数据持久化磁盘, 只需要将redo log持久化到磁盘就可以了

  • 未清除的redo log的数量标识了未刷盘的脏页数量

为什么提交事务是选择持久化redo log, 而不是持久化数据到磁盘

持久化数据到磁盘是随机IO过程, 所以Mysql选择将数据缓存起来, 等待一个合适的时机将数据一次性写入磁盘, 减少IO

但是数据缓存在内存中有丢失的风险, 所以Mysql选择将redo log持久化

redo log是顺序写, 持久化的效率比随机写的效率要高, 并且redo log记录了数据的变化情况, 只要redo log在就可以保证在Mysql重启后恢复数据

在InnoDB中, redo log是一个固定大小的类似循环队列的存在, 每次写入都从后面write pos的位置, 在持久化数据的时候就移动check point往前读取

09.png

这样设计的原因是因为redo log是防止Mysql崩溃后缓存的脏页数据丢失而存在的

当Mysql中的数据被持久化到磁盘中后, 被持久化部分的redo log其实就没有用了, 就可以腾出空间来记录新的数据

undo log 和 redo log 的区别

undo log记录的是事务执行过程中旧数据的状态, redo log记录的是数据更新之后的状态

redo log其实保障的是事务的持久性和一致性,而undo log则保障了事务的原子性

binlog 归档日志

binlog是Mysql server层实现的日志, 是所有引擎通用的

作用

binlog记录的是mysql原始的语句逻辑, 并且是采用追加写入的形式记录的, 所以可以用于恢复mysql在任意时刻的数据库数据状态

所以叫binlog是归档日志

同时binlog也是Mysql实现主从复制的依赖, 从库通过从主库中复制binlog回放来同步主库的数据状态

定义

先写日志到磁盘中, 再写数据到磁盘中Mysql的写操作不是立刻写入到磁盘中的, 而是先写日志, 保证redo log和binlog都持久化到磁盘中再由后台线程选择时机将数据持久化到硬盘的

为什么要先写日志到磁盘中

因为刷脏页是一个随机读写的过程, 持久化到磁盘中的速度肯定没有redo log | binlog这些顺序写的速度快, 所以选择先在内存中对数据进行修改, 再后期选择时机异步持久化到磁盘中

所以在脏页还未刷入磁盘中的这段时间就由redo log | binlog来保证数据的持久化, 防止断电重启等情况内存中的数据丢失

当脏页满的时候需要将脏页写入到磁盘再淘汰, 为何不全部淘汰掉下次使用的时候再通过redo log来恢复呢

从性能方面考虑的, 如果每次从磁盘中读取数据到内存都需要和redo log比对更新, 效率很低

MySQL刷脏页写入到磁盘保证了数据页只要在内存中, 就肯定是当前最新的数据可以返回

如果内存中没有数据只要从磁盘中读取肯定能得到最新的正确数据, 而不用再去同redo log进行比对

binlog和redo log的写入过程 - WAL机制的基本保证

binlog和redo log都是将日志写入划分为三个过程 写入cache, write和sync

在事务执行过程中会将binlog和redo log写入到对应分配的缓存中, 以便在事务提交的时候一次性写入到磁盘中

华友协同办公自动化OA系统
华友协同办公自动化OA系统

华友协同办公管理系统(华友OA),基于微软最新的.net 2.0平台和SQL Server数据库,集成强大的Ajax技术,采用多层分布式架构,实现统一办公平台,功能强大、价格便宜,是适用于企事业单位的通用型网络协同办公系统。 系统秉承协同办公的思想,集成即时通讯、日记管理、通知管理、邮件管理、新闻、考勤管理、短信管理、个人文件柜、日程安排、工作计划、工作日清、通讯录、公文流转、论坛、在线调查、

下载

在事务提交的时候会先进行write将数据写入到操作系统的页缓存中, 此时数据还未真正写入文件, 但是已经是交由操作系统的缓存来保管了, 如果此时Mysql进程崩溃这部分写入的数据也不会丢失, 操作系统的内核线程会负责将这部分缓存中的数据写入磁盘

  • 但是如果操作系统崩溃了这部分数据就丢失了

最后就是mysql手动调用sync将写入在页缓存中的数据持久化到硬盘, 写入完成后数据就是持久化成功了

最后的write和sync步骤mysql提供了对应的参数来控制写入策略

redo log是通过innodb_flush_log_at_trx_commit来控制的

  • 设置为 0 的时候,表示每次事务提交时都只是把redo log留在redo log的缓存中

丢失风险最大

  • 设置为 1 的时候,表示每次事务提交时都将redo log直接持久化到磁盘

丢失风险最小, 但是IO占用大

  • 设置为 2 的时候,表示每次事务提交时都只是把redo log写到page cache

IO占用居中, 将写入到磁盘这个最占用IO的过程交由操作系统来负责

binlog是通过参数sync_binlog来控制的

  • sync_binlog=0 的时候,表示每次提交事务都只 write,不 fsync

  • sync_binlog=1 的时候,表示每次提交事务都会执行 fsync

  • sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync

两阶段日志提交

什么是两阶段日志提交

10.png

将redo log日志提交的过程分为prepare和commit这两个阶段, binlog日志提交在这两个阶段中间

事务提交时redo log先提交后进入prepare状态, 然后binlog提交完成后redo log才能将日志的状态修改为commit已提交

为什么需要两阶段日志提交

和InnoDB引擎的回滚机制有关, InnoDB的redo log提交了事务就无法回滚了, 如果在redo log提交后binlog写入失败的话就会出现两份不统一的情况

如果此时数据库异常重启的话要依据那一份来恢复数据就值得思考了, 所以才需要两阶段日志提交

假设现在在时刻A数据库崩溃的话, 因为binlog还未写入, redo log还未提交, 所以重启后事务会回滚, 两份日志依旧是统一状态

如果是时间段B的话, 就需要对redo log的提交标志进行判断了, 在查询redo log中是否有commit提交标志, 如果有的话事务没有问题, 直接提交

  • 如果redo log中没有对应事务的提交标志的话会对binlog进行检查

  • 如果binlog完整并且带有commit标志, 就会提交事务并在redo log后面补上commit标志如果binlog不完整就回滚事务

这里可以发现两阶段日志提交中发生了崩溃是依据binlog来进行标准判断的, 原因是因为主从复制是依据binlog来进行的

如果对两份日志都需要检查完整性的话, 主库挂掉切换到从库的时间会变长, 以binlog为基准的话主库挂了直接拿着binlog去从库恢复数据即可, 无需检查redo log的完整性

此外binlog是Mysql Server层的通用日志, 这也是选择binlog作为基准的原因

两阶段日志提交的缺点

  • 磁盘IO次数高

在提交日志的时候会有redo log和binlog对应的刷盘操作, IO次数高

  • 锁竞争激烈

为了保证多个事务提交的时候日志的记录和事务的提交顺序是一致的, 会使用锁来保证日志提交的相对顺序

但是在并发量大的情况下性能会变差

组提交机制

组提交机制的作用

当有躲过事务提交的时候, 将多个事务的日志合并在一起去写入, 减少磁盘IO操作

组提交机制的实现

组提交机制将commit过程拆分成三个过程, 对每个过程都维护了一个队列, 并且通过锁来保证事务的写入顺序

  • 分成三个阶段分别加锁可以减少锁粒度, 无需锁住事务的整个提交过程

当队列为空的时候第一个进入队列的事务会成为后续进入的事务的领导者, 带领后续事务完成接下来的阶段操作

阶段一 : flush阶段 : 多个事务按进入的顺序将binlog从cache中写入文件 (不刷盘)

第一个进入flush阶段的事务会作为领导者领导后面进入的事务

领导者事务会带领所有的事务对 redo log 进行一次 write + fsync, 也就是将redo log 写入磁盘, 完成redo log 的propare阶段

如果在这个阶段Mysql崩溃了, 会在重启后回滚这组事务

阶段二 : sync : 对binlog文件做fsync操作 (将多个事务的binlog合并一起刷盘)

在flush阶段将binlog写入到binlog文件后, 会等待一段时间再进行刷盘, 目的是组合更多事务的binlog一起刷盘减少消耗

等待会有时间限制和最大事务限制, 满足其中一个条件就会立刻对binlog进行刷盘

sync阶段主要负责binlog的组提交, 如果当前阶段Mysql崩溃的话, 在重启后可以通过redo log的刷盘记录继续完成事务提交

  • 因为此时binlog已经完成提交了, 所以可以根据redo log来继续提交事务

阶段三 : commit : 对各个事务做InnoDB的commit操作

推荐学习:mysql视频教程

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

0

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

22

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

48

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

93

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

216

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

413

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

143

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

221

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

31

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 2.5万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 846人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号