MySQL - InnoDB特性 - Buffer Pool漫谈

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 缓存管理是DBMS的核心系统,用于管理数据页的访问、刷脏和驱逐;虽然操作系统本身有page cache,但那不是专门为数据库设计的,所以大多数数据库系统都是自己来管理缓存。由于几乎所有的数据页访问都涉及到Buffer Pool,因此buffer pool的并发访问控制尤为重要,可能会影响到吞吐量和响应时间,本文主要回顾一下MySQL的buffer Pool最近几个版本的发展(若有遗漏,欢迎评论补充), 感受下最近几年这一块的进步MySQL5.5之前只能设置一个buffer pool, 通过innodb_buffer_pool_size来控制, 刷脏由master线程承担,扩展性差。

缓存管理是DBMS的核心系统,用于管理数据页的访问、刷脏和驱逐;虽然操作系统本身有page cache,但那不是专门为数据库设计的,所以大多数数据库系统都是自己来管理缓存。由于几乎所有的数据页访问都涉及到Buffer Pool,因此buffer pool的并发访问控制尤为重要,可能会影响到吞吐量和响应时间,本文主要回顾一下MySQL的buffer Pool最近几个版本的发展(若有遗漏,欢迎评论补充), 感受下最近几年这一块的进步

MySQL5.5之前

只能设置一个buffer pool, 通过innodb_buffer_pool_size来控制, 刷脏由master线程承担,扩展性差。

MySQL 5.5

引入参数innodb_buffer_pool_instances,将buffer pool拆分成多个instance,从而减少对buffer pool的访问控制,这时候的刷脏还是由Master线程来承担。

MySQL 5.6

引入了buffer Pool page Id转储和导入特性,也就是说可以随时把内存中的page no存下来到文件里,在重启时会自动把这些Page加载到内存中,使内存保持warm状态. 此外该版本第一次引入了page cleaner,将flush list/lru上的刷脏驱逐工作转移到单独线程,减少了master线程的负担

MySQL 5.7

这个版本发布了一个重要特性:online buffer pool resize. 当然是否是online需要打一个问号,因为在resize的过程中需要拿很多全局大锁,在高负载场景下很容易导致实例Hang住(81615)。
和之前不同,buffer pool被分成多个instance,每个instance又由多个chunk组成,每个chunk的大小受到参数innodb_buffer_pool_chunk_size控制,默认128MB, buffer pool resize都是以chunk为单位增加或减少的。
另外一个需要注意的点是:你配置的Buffer Pool Size可能比你实际使用的内存要大,尤其对于大Bp而言,这是因为内部做了对齐处理, buffer pool size必须以 innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances来做向上对齐(80350)

我们知道通常数据文件的IO都被设置成O_DIRECT, 但每次修改后依然需要去做fsync,来持久化元数据信息,而对于某些文件系统而言是没必要做fsync的,因此加入了新选项O_DIRECT_NO_FSYNC,这个需求来自于facebook. 他们也对此做了特殊处理:除非文件size变化,否则不做fsync。(最近在buglist上对这个参数是否安全的讨论也很有意思,官方文档做了新的说明,感兴趣的可以看看 [94912:O_DIRECT_NO_FSYNC possible write hole
](https://bugs.mysql.com/bug.php?id=94912)

再一个重要功能是终于引入了multiple page cleaner, 可以多个后台线程并发刷脏页,提供了更好的刷脏性能,有效避免用户线程进入single page flush。当然这还不够完美,主要有四点:

  1. 用户线程依然会进入single page flush,而一旦大量线程进入,就会导致严重性能下降:超频繁的fsync,激烈的dblwr竞争,线程切换等等
  2. 当redo空间不足时,用户线程也会进入page flush,这在高负载场景下是很常见的,你会发现系统运行一段时间后,性能急剧下降。这是因为redo产生太快,而page flush又跟不上,导致checkpoint无法推进。那么用户线程可能就要过来做fuzzy checkpoint了。那时候性能基本上没法看了。
  3. dblwr成为重要的单点瓶颈。 如果你的服务器不支持原子写的话,必须打开double write buffer。写入Ibdata一段固定区域,这里是有锁包含的,区分为两部分:single page flush和batch flush, 但无论如何,即使拆分了多个page cleaner,最终扩展性还是受限于dblwr
  4. 没有专用的lru evict线程,都是Page cleaner键值的。举个简单的例子,当buffer pool占满,同时又有很多脏页时,Page cleaner可能忙于刷脏,而用户线程则得不到free page,从而陷入single page flush

如果你对上述几个问题极不满意,可以尝试percona server, 他们向来擅长优化Io bound场景的性能,并且上述几个问题都解决了,尤其是dblwr,他们做了多分区的改进。

MySQL 8.0

增加了一个功能,可以在实例宕机时,core文件里不去掉buffer pool, 这大大减少了core文件的大小。要知道,很多时候实例挂是因为文件损坏,不停的core重启会很快把磁盘占满,你可以通过设置参数innodb_buffer_pool_in_core_file来控制。

另外8.0最重要的一个改进就是:终于把全局大锁buffer pool mutex拆分了,各个链表由其专用的mutex保护,大大提升了访问扩展性。实际上这是由percona贡献给上游的,而percona在5.5版本就实现了这个特性(WL#8423: InnoDB: Remove the buffer pool mutex 以及 bug#75534)。

原来的一个大mutex被拆分成多个为free_list, LRU_list, zip_free, 和zip_hash单独使用mutex:

 - LRU_list_mutex for the LRU_list;
  - zip_free mutex for the zip_free arrays;
  - zip_hash mutex for the zip_hash hash and in_zip_hash flag;
  - free_list_mutex for the free_list and withdraw list.
  - flush_state_mutex for init_flush, n_flush, no_flush arrays.

由于log system采用lock-free的方式重新实现,flush_order_mutex也被移除了,带来的后果是flush list上部分page可能不是有序的,进而导致checkpoint lsn和以前不同,不再是某个log record的边界,而是可能在某个日志的中间,给崩溃恢复带来了一定的复杂度(需要回溯日志)

log_free_check也发生了变化,当超出同步点时,用户线程不再自己去做preflush,而是通知后台线程去做,自己在那等待(log_request_checkpoint), log_checkpointer线程会去考虑log_consider_sync_flush,这时候如果你打开了参数innodb_flush_sync的话, 那么flush操作将由page cleaner线程来完成,此时page cleaner会忽略io capacity的限制,进入激烈刷脏

8.0还增加了一个新的参数叫innodb_fsync_threshold,,例如创建文件时,会设置文件size,如果服务器有多个运行的实例,可能会对其他正常运行的实例产生明显的冲击。为了解决这个问题,从8.0.13开始,引入了这个阈值,代码里在函数os_file_set_size注入,这个函数通常在创建或truncate文件之类的操作时调用,表示每写到这么多个字节时,要fsync一次,避免对系统产生冲击。这个补丁由facebook贡献给上游。

其他

当然也有些辅助结构来快速查询buffer pool:

  • adaptive hash index: 直接把叶子节点上的记录索引了,在满足某些条件时,可以直接定位到叶子节点上,无需从根节点开始扫描,减少读的page个数
  • page hash: 每个buffer pool instance上都通过辅助的page hash来快速访问其中存储的page,读加s锁,写入新page加x锁。page hash采用分区的结构,默认为16,有一个参数innodb_page_hash_locks,但很遗憾,目前代码里是debug only的,如果你想配置这个参数,需要稍微修改下代码,把参数定义从debug宏下移出来
  • change buffer: 当二级索引页不在时,可以把操作缓存到ibdata里的一个btree(ibuf)中,下次需要读入这个page时,再做merge;另外后台master线程会也会尝试merge ibuf。

最后,听说官方正在努力解决double write buffer的瓶颈问题,期待一下.

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5天前
|
存储 关系型数据库 MySQL
MySQL存储引擎详述:InnoDB为何胜出?
MySQL 是最流行的开源关系型数据库之一,其存储引擎设计是其高效灵活的关键。InnoDB 作为默认存储引擎,支持事务、行级锁和外键约束,适用于高并发读写和数据完整性要求高的场景;而 MyISAM 不支持事务,适合读密集且对事务要求不高的应用。根据不同需求选择合适的存储引擎至关重要,官方推荐大多数场景使用 InnoDB。
43 7
|
15天前
|
存储 关系型数据库 MySQL
Mysql索引:深入理解InnoDb聚集索引与MyisAm非聚集索引
通过本文的介绍,希望您能深入理解InnoDB聚集索引与MyISAM非聚集索引的概念、结构和应用场景,从而在实际工作中灵活运用这些知识,优化数据库性能。
76 7
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
148 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
21天前
|
存储 关系型数据库 MySQL
MySQL引擎InnoDB和MyISAM的区别?
InnoDB是MySQL默认的事务型存储引擎,支持事务、行级锁、MVCC、在线热备份等特性,主索引为聚簇索引,适用于高并发、高可靠性的场景。MyISAM设计简单,支持压缩表、空间索引,但不支持事务和行级锁,适合读多写少、不要求事务的场景。
51 9
|
1月前
|
存储 安全 关系型数据库
InnoDB引擎特性
InnoDB事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。MySQL5.5.5之后,InnoDB作为默认存储引擎,InnoDB主要特性有: InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句中提供了一个类似Oracle的非锁定读。 InnoDB是为处理巨大数据量的最大性能设计。它的CPU效率可能是任何其他基于磁盘关系的数据库引擎所不能匹敌的。 InnoDB存储引擎完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的段、区和页
MySQL的InnoDB存储引擎逻辑存储结构与Oracle相似,包括表空间、段、区和页。表空间由段和页组成,段包括数据段、索引段等。区是1MB的连续空间,页是16KB的最小物理存储单位。InnoDB是面向行的存储引擎,每个页最多可存放7992行记录。
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的表空间
InnoDB是MySQL默认的存储引擎,主要由存储结构、内存结构和线程结构组成。其存储结构分为逻辑和物理两部分,逻辑存储结构包括表空间、段、区和页。表空间是InnoDB逻辑结构的最高层,所有数据都存放在其中。默认情况下,InnoDB有一个共享表空间ibdata1,用于存放撤销信息、系统事务信息等。启用参数`innodb_file_per_table`后,每张表的数据可以单独存放在一个表空间内,但撤销信息等仍存放在共享表空间中。
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL的InnoDB存储引擎
InnoDB是MySQL的默认存储引擎,广泛应用于互联网公司。它支持事务、行级锁、外键和高效处理大量数据。InnoDB的主要特性包括解决不可重复读和幻读问题、高并发度、B+树索引等。其存储结构分为逻辑和物理两部分,内存结构类似Oracle的SGA和PGA,线程结构包括主线程、I/O线程和其他辅助线程。
【赵渝强老师】MySQL的InnoDB存储引擎
|
6月前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
2月前
|
存储 缓存 关系型数据库
详细解析MySQL中的innodb和myisam
总之,InnoDB和MyISAM各有千秋,选择合适的存储引擎应基于对应用程序特性的深入理解,以及对性能、数据完整性和可扩展性的综合考量。随着技术发展,InnoDB因其全面的功能和日益优化的性能,逐渐成为更广泛场景下的首选。然而,在特定条件下,MyISAM依然保留其独特的价值。
174 0

相关产品

  • 云数据库 RDS MySQL 版