缓存管理是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。当然这还不够完美,主要有四点:

用户线程依然会进入single page flush,而一旦大量线程进入,就会导致严重性能下降:超频繁的fsync,激烈的dblwr竞争,线程切换等等

当redo空间不足时,用户线程也会进入page flush,这在高负载场景下是很常见的,你会发现系统运行一段时间后,性能急剧下降。这是因为redo产生太快,而page flush又跟不上,导致checkpoint无法推进。那么用户线程可能就要过来做fuzzy checkpoint了。那时候性能基本上没法看了。

dblwr成为重要的单点瓶颈。 如果你的服务器不支持原子写的话,必须打开double write buffer。写入Ibdata一段固定区域,这里是有锁包含的,区分为两部分:single page flush和batch flush, 但无论如何,即使拆分了多个page cleaner,最终扩展性还是受限于dblwr

没有专用的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的瓶颈问题,期待一下.

作者:zhaiwx_yinfeng

本文为云栖社区原创内容,未经允许不得转载。

mysql fsync_MySQL - InnoDB特性 - Buffer Pool漫谈相关推荐

  1. MySQL - InnoDB特性 - Buffer Pool漫谈

    转载自  MySQL - InnoDB特性 - Buffer Pool漫谈 缓存管理是DBMS的核心系统,用于管理数据页的访问.刷脏和驱逐:虽然操作系统本身有page cache,但那不是专门为数据库 ...

  2. MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法

    本系列文章目录 展开/收起 MySQL怎么运行的系列(一)mysql体系结构和存储引擎 MySQL怎么运行的系列(二)Innodb缓冲池 buffer pool 和 改良版LRU算法 MySQL怎么运 ...

  3. mysql pool返回值_Mysql成神之路-InnoDB 的 Buffer Pool

    缓存的重要性 我们只需要访问一个页的一条记录,那也需要先把整个页的数据加载到内存中.将整个页加载到内存中后就可以进行读写访问了,在进行完读写访问之后并不着急把该页对应的内存空间释放掉,而是将其缓存起来 ...

  4. InnoDB的Buffer Pool简介

    这篇非常重要!这篇非常重要!这篇非常重要!重要的事情说三遍,这篇是后续事务和锁的基础,一定要看懂这篇,反正我写的已经够白话了,你要再看不懂呢,那你告诉我,我改还不行么-下边是建议正文: 1. 最好使用 ...

  5. 缓冲多少数据_聊点深的:解析MySQL,看看InnoDB 缓冲池(buffer pool) 工作原理

    缓冲池的用处 对于使用 InnoDB 作为存储引擎的表来说,不管是用于存储用户数据的索引,还是各种系统数据,都是以页的形式存放在表空间中的,而所谓的表空间只是 InnoDB 对文件系统上一个或几个实际 ...

  6. 分页缓冲池占用很高怎么解决_聊点深的:解析MySQL,看看InnoDB 缓冲池(buffer pool) 工作原理...

    缓冲池的用处 对于使用 InnoDB 作为存储引擎的表来说,不管是用于存储用户数据的索引,还是各种系统数据,都是以页的形式存放在表空间中的,而所谓的表空间只是 InnoDB 对文件系统上一个或几个实际 ...

  7. MySQL8.0 存储引擎(InnoDB )buffer pool的实现原理

    数据库为了高效读取和存储物理数据,通常都会采用缓存的方式来弥补磁盘IO与CPU运算速度差.InnoDB 作为一个具有高可靠性和高性能的通用存储引擎也不例外,Buffer Pool就是其用来在内存中缓存 ...

  8. [MySQL 源码] 从buffer pool中获取空闲block流程

    当我们将一个page读入内存时,需要先为其分配一个block,从buffer pool中获取.入口函数为buf_LRU_get_free_block 之前在http://mysqllover.com/ ...

  9. MySQL深度剖析之Buffer Pool专题(2021)

    一 为什么需要Buffer Pool 如果我们每一次查询或者更新都需要到磁盘找到对应数据页,每次的都需要从磁盘加载,那么性能必定是很差的.所以将一些从磁盘加载的数据页,放入到内存缓存起来,而不用每次都 ...

最新文章

  1. 去掉字符串连续出现K个0的子串
  2. 309. Best Time to Buy and Sell Stock with Cooldown
  3. html背景图不显示_批量显示多张有序排列的图标,使用精灵图CSS Sprites这种办法...
  4. 硬件创新需要去理解的点(精炼总结)
  5. DDK样例toaster分析(1)
  6. mysql 数据恢复 binlog
  7. 微信公众号开发:账号申请与接入
  8. 如何越过计算机开机密码,怎样跳过电脑开机密码教程
  9. 微信付款到个人银行卡php,微信企业付款到银行卡(下)
  10. linux怎么查硬盘是否故障,怎么检查硬盘是否有问题
  11. Shader 海面/水面
  12. java-锁_自我理解
  13. 王思聪吃翔项目 - 共享充电宝 - 经营、销售分析系统DB设计实践
  14. 脱裤子放屁之用两个栈实现队列、用两个队列实现栈
  15. ElementUI-textarea文本域高度自适应设置的方法
  16. javascript小技巧
  17. android 新闻功能列表,android listview实现新闻列表展示效果
  18. 高桥盾react和boost_React和Boost哪个更好 耐克React和阿迪Boost有什么区别
  19. Recyclerview的简介与使用
  20. 快来给你个人微信公众号认个证吧

热门文章

  1. 服务器 'server_1' 上的 MSDTC 不可用
  2. No module named ‘pyqt5‘解决办法
  3. 二叉树前序、中序、后序遍历(八)
  4. Go一个协程实现加法demo
  5. Android7.0预置带so的apk
  6. Android开发重要参考资料
  7. Java-基础---继承,方法重写,super关键字
  8. python中file和open_Python中的file和open简述
  9. Apache Log4j2 远程代码执行高危漏洞 解决方案
  10. js 中堆和栈的应用与理解