【MySQL】InnoDB 内存管理机制 --- Buffer Pool
InnoDB Buffer Pool
- 是一块连续的内存,用来存储访问过的数据页面
- innodb_buffer_pool_size 参数用来定义 innodb 的 buffer pool 的大小
- 是 MySQL 中拥有最大的内存的模块
- Innodb 中,数据的访问是按照页/块(默认为16KB)的方式从数据文件中读取到 buffer pool中,然后在内存中用同样大小的内存空间做一个映射
为了提高访问速度(也就是尽可能多地把数据文件中的页/块放到 buffer pool 中),MySQL 预先就分配/准备了许多这样的空间,为的就是与MySQL数据文件中的页做交换,来把数据文件中的页放到事先准备好的内存中。
buffer pool 按照最少使用算法(LRU),来管理 buffer pool ,去搜了一下这个算法:
[ LRU(Least recently used),缓存淘汰算法。比较简单的一个算法,就是根据“近期”的数据访问记录来对buffer中的数据进行淘汰。核心思想:“如果某个数据最近被访问过,则将来被访问的概率更高”。
最常见的是使用链表保存缓存数据,这也是 innodb buffer pool 的管理方式。因此,最常访问的放在链表头,最不常访问的放在链表尾。
【命中率】
当存在热点数据的时候,LRU的效果很好;但是偶然性或者周期性的访问会导致LRU的命中率急剧下降。]
当 buffer pool 满了的时候,就用新的数据代替 buffer pool 末尾的数据。
root@localhost][(none)][02:40:28]> show engine innodb status\
InnoDB为缓冲区和控制结构保留了额外的内存,因此总分配的空间大约比指定的缓冲池大小大10%。
Buffer Pool 有两个区域,一个是 sublist_of_new_block 区域(热数据),一个是 sublist_of_old_clocks 区域(不经常访问的)。当访问的时候,如果没有相应数据则从磁盘中先读入数据到 sublist of old blocks 区域,然后移动到 sublist of new blocks 区域(实际上所谓的 热数据区域和 old 数据区域都是在 LRU list 里面,只是 sublist 0f new blocks 在链表的前面,sublist of old blocks 在链表的尾部)。
PS:
Pages made young:从 old 区移动到 new 区有多少个页
Pages made not young:因为 innodb_old_blocks_time 的设置而导致页没有从 old 部分启动到 new 部分的操作。
Buffer pool hit rate:表示缓冲池的命中率,通常这个值不应该小于95%,如果小于95%,则应该看看是不是由于全表扫描而导致 LRU 列表有污染。
同时,show engine innodb status 显示的不是当前的实时状态。
为了避免某些全表扫描的数据进入 sublist of new blocks 区域,从5.5.x 开始,innodb_old_blocks_pct 参数可以控制进入 sublist of old blocks 区域的百分比,默认是37%(即 sublist of old blocks 占整个 LRU list 的百分比,如上图所示:189598/514065=36.88%,接近37%)。---当全表扫描或者 dump 时,可以将 innodb_old_blocks_pct 设置的小些。
这个过程还会设计 innodb_old_blocks_time 参数,比如 sublist of old blocks 中的某个数据块被访问到了,他就会等待 innodb_old_blocks_time (毫秒),然后再移动到 sublist of new blocks 中。一般不会去动这个参数
在5.7.4 之前,如果想要更改 innodb_buffer_pool_size 的大小,只能 kill 掉进程才行,但是5.7.5开始,不需要停止进程就可以动态更改 innodb_buffer_pool_size 的大小。
同时,如果 innodb_buffer_pool_size 的大小超过1G,则需要通过调整 innodb_buffer_pool_instances=N(即开启多个内存缓冲池,每个缓冲池的大小相同,把需要缓冲的数据 hash 到不同的缓冲池中,这样就可以进行并行的内存读写),把 buffer pool 分成若干个 instance 可以提高 MySQL 处理请求的并发能力,因为 buffer pool 通过链表管理页,同时为了保护页,需要在存取的时候对链表加锁,因此多线程下,并发去读写 buffer pool 需要锁的竞争和等待。
因此,修改为多个 instance ,每个 instance 管理自己的内存和链表,可以提升请求的并发能力。
Buffer Pool 实现原理
server启动后也会启动所有的内嵌引擎,Innodb 启动后会通过 buf_pool_init 初始化所有的子系统(从命名来看貌似只是初始化buffer pool的,不确定是否里面有调用其他的函数来初始化其他的系统)。
InnoDB用一块内存区做 IO 缓存池,该缓存池不仅用来缓存 InnoDB 的索引块,而且也能用来缓存 InnoDB 的数据块,这于 MyISAM 不同。
Buffer Pool 逻辑上由 freelist、flush list 和 LRU list 组成。free list 是空闲缓存块列表,由下面说的 - FREE链表 来管理;flush list 是需要刷新到磁盘的缓存块列表,由下面所说的 flush_list链表 来管理;LRU list 是 InnoDB 正在使用的缓存块,也是 Bffer Pool的核心。
在代码中,Buffer Pool 用 buf_pool_t 结构体来描述,也是管理 buffer_pool 的核心工具,包含四个部分:
- FREE链表:存储这个实例中所有空闲的页面
- flush_list链表:存储所有被修改过且需要刷到文件中的页面
- mutex:保护实例,因为同一时刻,只能被一个线程访问
- chunks:存储第一个页面的物理地址(因为 buffer_pool 中的页面都是放在一块连续的内存中,即顺序存储,所以知道了第一个页面的地址指针,就可以通过这个指针访问所有的其他页面)
上面说的 FREE链表 和 lush_list链表 又是用来管理的 buf_page_t 结构体的,而 buf_page_t 结构体又被 buf_block_t 所管理。buf_page_t 和 buf_block_t 是一一对应的,都对应 Buffer Pool 中的一个 Page ,只是 buf_page_t 是逻辑的,而 buf_block_t 包含一部分物理的概念,比如这个页面的首地址指针 frame等。
初始化一个 Buffer Pool 的实例空间的函数是 buf_chunk_init。一个 Buffer Pool 实例空间按数据结构来看分为两部分:buf_block_t(buffer pool中页面控制头结构信息,每一个控制头信息管理一物理页面,这些控制头信息的存储占用了部分空间,所以 innodb_buffer_pool_size 总是比 innodb_buffer_pool_bytes_data 大。);另外一部分就是存储 page 的,由 buf_page_t 来管理。
Buffer Pool 初始化过程:Buffer Pool 页面(buf_page_t)在这个实例池中从后向前分配 page,每次分配一个页面,同时控制结构(buf_block_t)从前向后分配来和刚刚分配的页面一一对应(也就是上文说的 buf_block_t 与 buf_page_t 一一对应)。这样前后同时分配也会导致一个问题:因为 block 和 page 是成对的,所以很大可能也很正常地就会“剩下”一些空间(不足以再分配一对 block 与 page)。
buf_pool_t 结构体用来管理整个 buffer pool 实例,而 buf_block_t 用来管理页(buf_page_t),buf_block_t 主要包括一下四个部分:
其对应的页面的 frame
其所对应的 buf_page_t 的信息(所属表空间的ID号、页面号等)
保护这个页面的互斥量mutex()
访问页面时对这个页面上的 lock(read/write)等
以上,初始化页面完成后,这些页面的状态还是未使用(buf_block_not_used),因此将页面加入到 -FREE链表 中,以供使用。至此,缓冲池的一个实例就初始化完成了,其余实例初始化过程相同。
对于整个 Buffer Pool 而言,各个实例之间是完全独立的,相互之间没有任何关系,单独申请、单独管理、单独刷盘。
在具体使用中,针对同的页面,当一条 SQL 从客户端发往服务端时,会通过一个 HASH 算法,来映射到一个具体的实例中。
以上,就是整个 Buffer Pool 多实例的管理机制,通过多实例,可以减少系统运行过程中不同页面之间一些操作的相互影响,从而很好地解决了由于页面之间的资源争抢导致的性能低下问题。
【MySQL】InnoDB 内存管理机制 --- Buffer Pool的更多相关文章
- MySQL内存管理机制浅析
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 目录 一.placement new的定义 二.pl ...
- Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制
Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制 http://w ...
- 【大白话系统】MySQL 学习总结 之 缓冲池(Buffer Pool) 如何支撑高并发和动态调整
如果大家对我的 [大白话系列]MySQL 学习总结系列 感兴趣的话,可以点击关注一波. 一.上节回顾 在上节< 缓冲池(Buffer Pool) 的设计原理和管理机制>中,介绍了缓冲池整体 ...
- MySQL -- Innodb中的change buffer
change buffer是一种特殊的数据结构,当要修改的辅助索引页不在buffer pool中时,用来cache对辅助索引页的修改.对辅助索引页的操作可能是insert.update和delete操 ...
- java内存管理机制剖析(一)
最近利用工作之余学习研究了一下java的内存管理机制,在这里记录总结一下. 1-1.java内存区域 当java程序运行时,java虚拟机会将内存划分为若干个不同的数据区域,这些内存区域创建和销毁的时 ...
- 深入理解Java虚拟机(自动内存管理机制)
文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...
- 【Cocos2d-x 3.x】内存管理机制与源码分析
侯捷先生说过这么一句话 : 源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...
- Java虚拟机内存管理机制
自动内存管理机制 Java虚拟机(JVM)在执行Java程序过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区 ...
- OC 内存管理机制总结
OC 内存管理机制总结 一:OC内存管理机制目前分为两块,其一自动内存管理机制,其二手动内存管理机制: 1.首先我们从自动内存管理机制讲起: 1)什么是自动内存管理机制,自动内存管理机制就是程序中所创 ...
随机推荐
- js_js流程控制
1.表达式.语句 2.流程控制 顺序 分支 循环 分支 循环结构都有一个条件 循环结构:重复做一件事 3元运算符 switch语句(用来做相等性判断--优先考虑) 注意: 1.switch ...
- docker上配置mysql主从复制
1.在docker上启动2台mysql容器:(这里3306为主,3307为从) docker run -d -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 - ...
- 4. Scala程序流程控制
4.1 程序流程控制说明 在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句,顺序控制,粉质控制,循环控制 温馨提示:Scala语言中控制结构和Java语言中的 ...
- mysql数据库的查询,添加,删除,还原,备份
18章数据mariadb数据库 1.setup 配置网卡centos6.52.nmtui 网卡图形配置界面3.yum install mariadb mariadb-server4.systemctl ...
- 17.结构体(typedef)
1.结构体 a.结构体类型定义b.结构体变量定义c.结构体变量的初始化d.typedef改类型名e.点运算符和指针法操作结构体f.结构体也是一种数据类型,复合类型,自定义类型 2.结构体变量的定义 ( ...
- JMS笔记(三)
最近重看activemq,对消息的传送确认机制有了进一步认识 1. mq在确认consumer收到消息后才会删除消息,因此consumer接收消息后应该进行ack"确认",java ...
- C#开启异步 线程的四种方式
一.异步委托开启线程public static void Main(string[] args){ Action<int,int> a=add; a.BeginInvoke(3,4,nul ...
- log4j日志输出框架
什么是log4j框架呢? log4j是一个日志输出框架,用于输出日志的.比如MyBatis的日志就是通过log4j输出的,主流框架都是log4j输出的,Spring框架 也可以通过log4j输出日志! ...
- 学号 20175201张驰 《Java程序设计》第7周学习总结
学号 20175201张驰 <Java程序设计>第7周学习总结 教材学习内容总结 第八章 String类能有效地处理字符序列信息,它的常用方法有: public int length()可 ...
- 【Linux】-NO.160.Linux.1 -【升级Centos7】
Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...