技术分享 | show engine innodb status中Pages flushed up to 的含义

作者:胡呈清

爱可生 DBA 团队成员,擅长故障分析、性能优化,个人博客:https://www.jianshu.com/u/a95ec11f67a8,欢迎讨论。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


有一个很久前就存在的疑惑:
在没有写入的情况下,show engine innodb status 中的 Pages flushed up to 为什么不等于 Last checkpoint point?它表示什么?

今天在写一篇文章时,想通过一个测试,从这几个 LSN 的变化来验证一个说法,结果重新勾起了这个问题,在一番“研究”后(其实就是google了一通,当然还是需要一些测试验证),终于弄明白了其中含义。

主要还是借鉴了一篇文章:http://blog.itpub.net/30221425/viewspace-2154670/,因为有大量的源码分析,而我看不懂源码,所以花了不少时间才理解其中原理,并且通过测试验证了其准确性,然后整理成了一个让像我这样不懂代码的人更方便阅读的文档。

今天在写一篇文章时,想通过一个测试,从这几个 LSN 的变化来验证一个说法,结果重新勾起了这个问题,这次我决定彻底弄明白到底是怎么一回事。

主要还是借鉴了一篇文章:http://blog.itpub.net/30221425/viewspace-2154670/,因为有大量的源码分析,而我也看不懂源码,所以花了不少时间才理解其中原理,并且通过测试验证了其准确性,然后整理成了一个更方便让像我这样不懂代码的人理解的文档。

LSN

show engine innodb status 的输出中,有一部分是 LSN 的状态:

mysql> pager grep -A 5 LOG                                      
PAGER set to 'grep -A 5 LOG'
mysql> show engine innodb status\G
LOG
---
Log sequence number 2471197058
Log flushed up to   2471197058
Pages flushed up to 2471197058
Last checkpoint at  2471197049
1 row in set (0.00 sec)

Log sequence number:所有修改数据的操作都会产生 redo log,这是系统当前 redo log 序列号(后面简称 LSN)的最大值;

Log flushed up to:当前已经刷盘的 redo log 的序列号;

Pages flushed up to:讨论的重点;

Last checkpoint at:最后一次 checkpoint 的位置。

Pages flushed up to 到底表示什么?最常见的说法就是脏页刷新到磁盘的 LSN,但 Last checkpoint at 也表示在此之前的数据页已经刷盘,而且通常我们看到的 Pages flushed up to 总是比 Last checkpoint at 大 ,所以这个说法肯定是错误的。

根据参考文章中的源码分析,Pages flushed up to 的取值逻辑是:

Pages flushed up to 取的是所有 buffer pool instance 中的 flush list 中最大 oldest modification lsn 页中的带有最小的 oldest modification lsn 的值(这里可能有点难以理解,我们可以简化理解为取 flush list 中最大的 oldest modification lsn);

如果取到的 oldest modification lsn 为0,意味着没有脏页,那么我们就取 log_sys->lsn 的值,即 show engineinnodb status 显示的 Log sequence number。

LSN 更新的逻辑

取 Pages flushed up to 的目的是什么?因为是取的 flush list 中脏页的最大 LSN,接下来做 checkpoint 时,可以用作这次刷脏的一个结束位置。

在一个正常运行的 MySQL 中,系统 LSN 随着 SQL 的执行(修改数据的SQL)不断增大(实时的),Pages flushed up to 值也会按某个频率获取更新,所以 Pages flushed up to 一般会落后于系统 LSN。然后 InnoDB master thread 每秒和每十秒做 checkpoint 时(还有其他的机制触发 checkpoint,这里不考虑并不影响理解),在将脏页刷盘后会将 Last checkpoint at 的值更新成 Pages flushed up to,由于 Pages flushed up to 在不断更新,所以我们观察到的 Last checkpoint at 一般会小于 Pages flushed up to。

在没数据写入的情况下,为什么 Last checkpoint point 不等于 Pages flushed up to?

是因为做 checkpoint 时同时 redo 日志会写 MLOG_CHECKPOINT,而 MLOG_CHECKPOINT 占用9个字节,所以系统 LSN 会加9,而由于脏页都被刷盘了,flush list 为空,获取 Pages flushed up to 时会直接取系统 LSN 值,所以也会比 Last checkpoint point 大 9。

获取 Pages flushed up to 和 checkpoint 不是一个原子操作,它是在 checkpoint 前就获取了,指的是下一次 checkpoint 结束的位置。

测试验证

我们手工开启一个事务写入一行数据(不提交),会发现如下图所示:

  • Log sequence number 增加了,因为系统 LSN 是实时产生的;

  • Log flushed up to 没变,说明 redo log 还没刷盘(也可能观察到这个值增加并且和 Log sequence number 一致,因为 InnoDB 后台线程每秒会刷 redo log,未提交事务的 redo log 可能提前刷盘);

  • Pages flushed up to 没变,因为这个值不是实时产生的,只要我们手速够快,在执行完 insert 后立刻查看 LSN,就可以看到这个值不变;

  • Last checkpoint point 没变,同样的只要手速够快,在 checkpoint 前查看到的值就不会变。

我们隔几秒钟后再查看 LSN,会发现:所有值都变了,并且前 3个值一样,Last checkpoint point 比它们的值小 9。这是因为InnoDB Master Thread 每秒、每十秒都会做 checkpoint,所有脏页都刷盘后,flush list 为空,符合我们前面所说的原理:

在持续写入的情况下,是可以观察到 Last checkpoint point 等于 Pages flushed up to 的(checkpoint 后还没有获取新的 Pages flushed up to):

<think>好的,我现在需要详细解析InnoDB缓冲池,也就是InnoDB Buffer Pool。首先,用户之前询问了MySQL的缓存机制,现在特别关注InnoDB缓冲池,说明他们对这部分特别感兴趣或者在实际应用中遇到了相关问题。用户可能是数据库管理员或开发人员,需要深入了解缓冲池的工作原理和优化方法,以提升数据库性能。 首先,我要回忆InnoDB缓冲池的基本概念。缓冲池是InnoDB引擎的核心组件,主要用于缓存数据和索引,减少磁盘I/O。接下来需要覆盖它的结构,比如数据页、索引页、自适应哈希索引、变更缓冲区等。然后需要解释它的工作原理,比如如何读取和写入数据,页面淘汰策略,以及LRU算法的具体实现,尤其是冷热数据分离的部分,避免全表扫描导致缓存污染。 接下来,配置参数是关键部分。用户可能需要知道如何设置缓冲池的大小,多实例配置,以及相关的状态监控命令。比如innodb_buffer_pool_size的设置建议,通常建议设置为物理内存的70-80%,但也要考虑其他内存使用情况。innodb_buffer_pool_instances用于减少锁竞争,提高并发性能。 然后,性能监控方面,需要介绍如何通过SHOW ENGINE INNODB STATUS和Performance Schema来查看缓冲池的命中率、页面使用情况等指标。命中率低可能意味着需要调整缓冲池大小或者优化查询。 优化策略部分,要包括预热方法,比如如何通过导出和导入缓冲池状态来加速重启后的性能恢复。还有如何结合SSD进行优化,调整innodb_io_capacity等参数。此外,云数据库的优化可能也是用户关心的点,比如阿里云或AWS的特定功能。 需要注意用户可能的误区,比如缓冲池设置过大导致系统内存不足,或者未正确配置多实例导致锁竞争。还要提醒用户,虽然缓冲池很重要,但也需要综合其他因素如查询优化、索引设计等来提升整体性能。 最后,要总结常见问题,比如命中率下降的原因和解决方法,帮助用户快速排查问题。可能还需要比较InnoDB缓冲池与其他缓存机制(如MyISAM的密钥缓存)的不同,但用户当前的问题集中在InnoDB,所以重点在此。 现在需要组织内容的结构,确保逻辑清晰,从基本概念到工作原理,再到配置、监控和优化,最后是常见问题处理。使用示例代码和参数设置建议能增加实用性。同时,保持语言简洁,技术点准确,避免错误,比如LRU算法的具体实现细节要正确,冷热区的划分和比例要准确描述。 可能还需要检查是否有最新的MySQL版本更新影响了缓冲池的某些行为,比如在MySQL 8.0中是否有相关改动。根据之前的对话,用户知道查询缓存在8.0被移除,但缓冲池依然是核心,所以不需要特别说明版本差异,除非有重大变化。 总之,回答需要全面覆盖缓冲池的各个方面,同时提供实用的配置建议和问题排查方法,帮助用户真正理解和应用这些知识来优化他们的数据库环境。</think>以下是InnoDB缓冲池的详细解析(基于MySQL 8.0+版本): --- ### **一、核心定位** InnoDB缓冲池是MySQL性能的核心组件,承担以下关键角色: - 内存与磁盘的桥梁:通过内存缓存减少95%+的物理磁盘I/O - 数据中转站:统一管理数据页的读取、修改和刷盘操作 - 查询加速器:使高频访问数据实现微秒级响应 --- ### **二、内存结构设计** #### 1. 核心区域划分 ```sql +-------------------------------+ | Buffer Pool | | +--------------------------+ | | | Data Pages | | # 实际数据(B+树叶子节点) | +--------------------------+ | | | Index Pages | | # 非叶子节点索引 | +--------------------------+ | | | Adaptive Hash Index | | # 自动优化的哈希索引 | +--------------------------+ | | | Change Buffer | | # DML操作的临时缓存(插入/删除) | +--------------------------+ | | | Lock Info & Undo Logs | | # 行锁信息/回滚日志 | +--------------------------+ | +-------------------------------+ ``` #### 2. 页管理机制 - 标准页大小:16KB(可通过`innodb_page_size`调整) - 页状态标记: - `干净页`(数据与磁盘一致) - `脏页`(已修改未刷盘) - `空闲页`(可分配空间) --- ### **三、工作流程** #### 1. 数据读取流程 ```mermaid graph TD A[查询请求] --> B{检查缓冲池} B -->|命中| C[直接返回内存数据] B -->|未命中| D[发起磁盘IO读取] D --> E[数据页载入缓冲池] E --> F[更新访问记录] F --> C ``` #### 2. 数据写入流程 ```mermaid graph TD A[数据修改] --> B[写入缓冲池脏页] B --> C[记录redo log] C --> D{检查点触发条件} D -->|| E[异步刷盘] D -->|| F[保持脏页状态] ``` --- ### **四、关键配置参数** ```sql # my.cnf 关键配置项 innodb_buffer_pool_size = 12G # 必须小于物理内存的80% innodb_buffer_pool_instances = 8 # 建议每个实例1GB左右 innodb_lru_scan_depth = 1024 # LRU扫描深度(每实例后台线程) innodb_change_buffer_max_size = 25 # 变更缓冲区最大占比(默认25%) ``` --- ### **五、高级特性** #### 1. 多缓冲池实例 - 解决全局锁争用问题 - 建议设置:当缓冲池≥1GB时,配置多个实例 ```sql 计算公式: innodb_buffer_pool_instances = MIN( innodb_buffer_pool_size / 1G , 64 ) ``` #### 2. 预读优化(Read-Ahead) - 线性预读:`innodb_read_ahead_threshold`(默认56,连续访问页数阈值) - 随机预读:`innodb_random_read_ahead`(默认OFF,建议保持关闭) #### 3. 刷新策略 ```sql innodb_max_dirty_pages_pct = 75 # 最大脏页比例阈值 innodb_io_capacity = 2000 # SSD建议设为2000-5000 innodb_flush_neighbors = 0 # SSD建议关闭邻页刷新 ``` --- ### **六、监控与调优** #### 1. 核心监控指标 ```sql SHOW ENGINE INNODB STATUS\G -- 重点关注: BUFFER POOL AND MEMORY ---------------------- Buffer pool hit rate # 命中率应>95% Pages made young/not young # 数据活跃度 Dirty pages already flushed # 已刷新的脏页 Pending writes: LRU 0, flush list 0 # 待处理IO # 性能模式查询 SELECT * FROM sys.schema_table_statistics WHERE table_schema NOT IN ('sys','mysql'); ``` #### 2. 热数据预热方案 ```sql # 启动时自动加载 [mysqld] innodb_buffer_pool_load_at_startup = ON innodb_buffer_pool_dump_at_shutdown = ON # 手动触发预热 SET GLOBAL innodb_buffer_pool_dump_now=ON; SET GLOBAL innodb_buffer_pool_load_now=ON; ``` --- ### **七、典型问题处理** #### **场景1:缓冲池命中率低** - 排查步骤: 1. 检查`缓冲池大小`是否足够 2. 分析`全表扫描`查询(EXPLAIN检查type=ALL) 3. 确认是否频繁`重启服务`导致缓存失效 #### **场景2:突发性能下降** - 可能原因: - 脏页比例超过`innodb_max_dirty_pages_pct` - 后台刷盘线程阻塞 - 解决方案: ```sql # 临时提升IO容量 SET GLOBAL innodb_io_capacity=5000; # 手动触发刷盘 SET GLOBAL innodb_max_dirty_pages_pct=50; ``` --- ### **八、最佳实践建议** 1. **容量规划**:专用数据库服务器建议分配70-80%物理内存 2. **版本升级**:MySQL 5.7+支持在线调整缓冲池大小 3. **SSD优化**:配合`innodb_io_capacity`提升刷盘效率 4. **监控警报**:设置命中率<90%、脏页>60%的告警阈值 通过深度优化InnoDB缓冲池,可使OLTP系统的TPS提升3-10倍。建议结合Percona Monitoring等工具进行长期性能追踪。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值