缓存管理是DBMS的核心系统,用于管理数据页的访问、刷脏和驱逐;虽然操做系统自己有page cache,但那不是专门为数据库设计的,因此大多数数据库系统都是本身来管理缓存。因为几乎全部的数据页访问都涉及到Buffer Pool,所以buffer pool的并发访问控制尤其重要,可能会影响到吞吐量和响应时间,本文主要回顾一下MySQL的buffer Pool最近几个版本的发展(如有遗漏,欢迎评论补充), 感觉下最近几年这一块的进步php
只能设置一个buffer pool, 经过innodb_buffer_pool_size来控制, 刷脏由master线程承担,扩展性差。mysql
引入参数innodb_buffer_pool_instances,将buffer pool拆分红多个instance,从而减小对buffer pool的访问控制,这时候的刷脏仍是由Master线程来承担。sql
引入了buffer Pool page Id转储和导入特性,也就是说能够随时把内存中的page no存下来到文件里,在重启时会自动把这些Page加载到内存中,使内存保持warm状态. 此外该版本第一次引入了page cleaner,将flush list/lru上的刷脏驱逐工做转移到单独线程,减小了master线程的负担数据库
这个版本发布了一个重要特性: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。固然这还不够完美,主要有四点:服务器
若是你对上述几个问题极不满意,能够尝试percona server, 他们向来擅长优化Io bound场景的性能,而且上述几个问题都解决了,尤为是dblwr,他们作了多分区的改进。并发
增长了一个功能,能够在实例宕机时,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)。ide
原来的一个大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:
最后,据说官方正在努力解决double write buffer的瓶颈问题,期待一下.
本文为云栖社区原创内容,未经容许不得转载。