调节磁碟和CPU的矛盾 - InnoDB的Buffer Pool

快取的重要性

我们知道不论是聚簇索引或是二级索引,资料都是储存在表格空间,而表格空间其实只是个抽象概念,实际上就是几个档案存放在磁碟里。
我们都知道资料在磁碟上的速度很慢,根本就跟不上很快的CPU,那这样要怎麽处理呢?
因此当使用者请求资料的时候,会直接将其对应页的所有资料存放在记忆体中(就算只有一笔资料),且不会急着释放这些资料,以当下次有请求的时候可以直接利用,这就是InnoDB的Buffer Pool的重要性。

InnoDB的Buffer Pool简介

mysql server在启动的时候就会直接先申请一片连续的记忆体当作Buffer Pool(预设为128mb)。
这也是可以调整的,透过系统变数innodb_buffer_pool_size。注意的是低於5mb就会直接当作是5mb

[server]
innodb_buffer_pool_size = 268435456

Buffer Pool是由一堆控制区块和缓冲页组成的,每个控制区块与缓冲页是一一对应的。
在填充足够多的控制区块与缓冲页之後,剩下的空间可能不足以再填充一个完整的控制区块与缓冲页,这些空间又叫做碎片。

InnoDB一样使用很多个链结串列来管理Buffer Pool

Free链结串列内每一个节点代表一个空的缓冲页,当页面载入到Buffer Pool时就会从Free链结串列里面找寻空的缓冲页。

为了快速定位某个页是否被载入到Buffer Pool,会以表格空间号+页号作为key,缓冲页控制区块位址为value来制作杂凑表。

在Buffer Pool中被修改後的页称为脏页,脏页不是立即更新的,而是会先加到flush链结串列,待之後再更新回磁碟中。

LRU(Leasr Recently Used)链结串列:
当Buffer Pool已经满的时候,我们当然就是要移除中些旧的页面以加入新的页面,而要移除的就是那些很少在用的页面罗。
具体的做法就是当存取某个页的时候,一开始一定会先加到LRU链结串列,将其放在头部。
如之後又存取的时候也会将其对应的节点移到头部,也就是说在尾部的节点对应的就是一直没用到的页面。
因此如果要移除旧的页面就优先从LRU的尾部移除就可以解决这问题啦!!

再补充LRU依照使用频率在画分成两个区块:young区块(使用频率很高) 跟 old区块(使用频率很低)
为了避免同时载入很多使用频率低的页面时误将使用频率高的页面从Buffer Pool移除。

可以透过以下变数查看old区块大小

mysql> show variables like 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+
1 row in set (0.02 sec)

这是指old区块在LRU中占37%的意思。

多个Buffer Pool

当Pool太大且并发存取量特别高的时候可能单一Pool效能会不好,这时可以考虑多个Pool,

[server]
innodb_buffer_pool_instances = 2

<<:  Day20 Metricbeat(一)

>>:  Day 28 实作 admin_bp (1)

关於伪元素 ( Pseudo-elements )

伪元素有以下: ::after (:after) ::backdrop ::before (:bef...

成为工具人应有的工具包-24 SearchMyFiles

SearchMyFiles 今天来认识这个看名字判断应该是找自己的档案的工具? 可是这功能不是从 w...

文书编辑器_vi

前面提到 我在python上面可以很快的去控制GPIO 可是C呢? 在这Linux的环境下,没有ID...

Day12 天气API小实作2

继续昨天的进度,首先,因为我们用了pickerview所以要扩充UI功能,写在第十一行後。 写完之後...

[Day02] TS: 泛型(Generics)能干嘛?

「泛型(Generics)」是 TypeScript 中很常会使用到的功能,泛型的概念简单来说,就是...