MySQL中各种日志、缓冲区都是干嘛的?

科技   2024-11-09 15:14   安徽  

来源:juejin.cn/post/7411489477283856419

👉 欢迎加入小哈的星球,你将获得: 专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 点击查看项目介绍
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2期已完结,演示链接:http://116.62.199.48/;

截止目前,累计输出 65w+ 字,讲解图 2776+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,解锁全部项目,已有2300+小伙伴加入

  • 介绍
  • 写入数据流程
    • undo log
    • buffer pool
    • change buffer
    • redo log 与 redo log buffer
    • binlog
  • 总结

介绍

本篇文章主要以innodb存储引擎为主;在了解mysql的过程中经常能听到它内部有各种log以及缓冲区,他们在mysql中具有重要作用,例如binlog可以进行主从恢复,undo log可以进行数据回滚等。

这篇文章主要讲解在mysql运行期间每个区域都是用来做什么的。

写入数据流程

对于mysql来讲,读写任何数据都是在内存中进行操作的;下图为mysql写入数据的详细流程:

  • 写入undo log,为了实现回滚的功能,在写入真实数据前需要记录它的回滚日志,防止写入完数据后无法进行回滚;
  • 写入buffer poolchange buffer,在缓存中记录下数据内容;
  • 为了防止mysql崩溃内存中的数据丢失,此时会记录下redo log,记录redo log时也是写入它的buffer,通过不同的刷盘策略刷入到磁盘redo log文件中;
  • 为了实现主从同步,数据恢复功能,mysql提供了binlog日志,写入完redo log后写binlog文件;
  • 为了使binlog和redo log保持数据一致,这里采用的二阶段提交,写入binlog成功会再在redo log buffer中写入commit;
  • redo log进行刷盘,这里有三种刷盘策略,介绍一下刷盘策略;
  • buffer pool中的数据进行刷盘。

undo log

undo log记录事务开始前的数据状态,它主要用于数据回滚和实现MVCC:

  • 回滚操作: undo log记录了事务开始前的数据状态,当事务需要回滚时,以便可以恢复到原始状态。
  • 多版本并发控制(MVCC) : 在读取历史数据时,undo log允许读取到事务开始前的数据版本,从而实现非锁定读取。

buffer pool

innodb中无论是查询还是写绝大部分都是在buffer pool中进行操作的,它相当于innodb的缓存区,可以通过show engine innodb status来查看buffer pool的使用情况;可以通过innodb_buffer_pool_size来设置buffer pool的大小,线上不要吝啬给几个G内存都是正常的,但无论给多大内存都会有不够的时候,innodb采用了变种的LRU算法对数据页进行淘汰;如下图:

传统的LRU算法当碰到扫描一张大表时可能会直接把buffer pool中的所有页都更换为该表的数据,但这张表可能就使用一次,并不是热点数据;

innodb为了避免这种场景发生,会把整个buffer pool按照 5:3分成了young区域和old区域;其中绿色区域就是young区域也就是热点数据区域,紫色区域就是old区域也就是冷数据区域;整体的淘汰流程为:

  • 如果想访问绿色区域内的数据,会把访问页直接放在young head处;
  • 如果想访问一个不存在的页,会把tail页淘汰掉,并且把新访问的数据页插入在old head处;
  • 如果访问old区域的数据页,并且这个数据页在LRU链表中存在的时间超过了innodb_old_blocks_time(默认1000毫秒),就把它移动到yound head处;
  • 如果访问old区域的数据页,并且这个数据页在LRU链表中存在的时间短于innodb_old_blocks_time,把该页移动到old head处。

在上图中可以看到除了LRU链表还有一个Flush链表,它是用来管理脏页的;在写入数据时绝大部分都会先写入buffer pool中,再更改buffer pool中的页数据时,该页就变成了脏页,此时就会被加入到flush链表中,定时会把flush中的脏页刷到.idb数据文件中。

change buffer

在介绍buffer pool时用的是绝大部分操作,是因为在innodb中还存在change buffer,还有一部分操作是写入change buffer的。

change buffer的定义是当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,innodb会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中加载这个数据页了,如果有查询需要访问这个数据页的时候,再将数据页读到内存中,然后执行change buffer中与这个页有关的操作,这样就能保证这个数据的正确性。

change buffer用的是buffer pool中的内存,可以通过innodb_change_buffer_max_size来设置它占用buffer pool的内存比例。使用change buffer的前提条件是该数据页还没被加载到buffer pool中,并且如果是根据唯一索引进行更新,由于要检查数据的唯一性,必须把数据页加载到buffer pool中是无法享受change buffer带来的收益的。

redo log 与 redo log buffer

redo log是为了防止由于mysql异常退出导致buffer pool中还未持久化的数据丢失而诞生的;

它也是一个环形文件写数据写满时会覆盖历史的数据,它记录了数据页的物理变化,并且是顺序写入的提升了写入的性能;当mysql重启时可以使用redo log来恢复数据。

每次写redo log时并不是直接写入redo log文件,而是写入redo log buffer中,通过三种刷盘策略把数据同步到redo log中,可以通过innodb_flush_log_at_trx_commit参数来控制刷盘的时机

  1. 事务提交时,日志缓冲(log buffer)被写入到日志文件,但并不立即刷新到磁盘。日志文件的刷新操作由后台线程每隔一秒执行一次;
  2. 事务提交时,日志缓冲被写入到日志文件,并立即刷新到磁盘;
  3. 事务提交时,日志缓冲被写入到日志文件,但不立即刷新到磁盘。而是每秒由后台线程将日志文件刷新到磁盘。

如果对数据的正确性要求很高应该设置为1。

注:第一张图流程中,在第5步有二次commit,在数据恢复如果发现一个事务没有commit,则去binlog日志中查询,如果发现binlog中有相应数据则直接恢复,如果没有则丢弃。

binlog

binlog为了高效地记录和传输数据更改信息,它采用了二进制格式存储数据库的更改操作,这样还可以占用更小的存储空间;它可以实现数据恢复、数据同步等功能。

默认mysql是关闭binlog日志的,可以通过在[mysqlId]部分中设置log-binserver-id来开启binlog日志。它也是在事务提交时才进行数据记录,它有以下三种数据格式:

  • Statement: 记录每一条执行的sql,但由于mysql中存在一些函数,例如一些随机生成函数,此时数据同步时会发生同步过去的数据不一致;
  • Row: 记录每行被修改成什么,这样可以解决statement带来的数据不一致问题,但由于记录的太详细如果出现了全表更新,那记录的数据量就会特别大;
  • Mixed: Statement和Row的混合体,mysql会根据执行的每一条具体的SQL语句来区别对待记录的日志格式。

总结

为了实现更高的性能,在innodb中的任何操作都是优先在内存中操作的;为了支持数据的数据回滚、MVVC引入了undo log,进而可以实现查询历史版本或数据回滚;同时为了防止异常退出导致的数据丢失引入了redo log;为了支持数据同步等功能mysql引入了binlog日志。

这就是各个区域的作用,由于篇幅原因本篇文章只对每个区域做了简单介绍,后续会写各个区域详细内容的文章。

👉 欢迎加入小哈的星球,你将获得: 专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 点击查看项目介绍
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2期已完结,演示链接:http://116.62.199.48/;

截止目前,累计输出 65w+ 字,讲解图 2776+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,解锁全部项目,已有2300+小伙伴加入


1. 我的私密学习小圈子,从0到1手撸企业实战项目!

2. 面试官:业务开发时,接口不能对外暴露怎么办?

3. 记一次使用规则引擎改造任务系统的经验

4. SpringBoot + minio + kkfile 实现文件预览

最近面试BAT,整理一份面试资料Java面试BATJ通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。

PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。

“在看”支持小哈呀,谢谢啦

小哈学Java
码龄9年,前某厂中台研发。专注于Java领域干货分享,不限于BAT面试, 算法,数据库,Spring Boot, 微服务,高并发, JVM, Docker容器,ELK相关知识,期待与您一同进步。
 最新文章