0%

Innodb缓冲池

Innodb缓冲池

Innodb存储引擎是基于磁盘存储的,将其中的记录按照页的方式进行管理,由于CPU速度和磁盘速度相差太多,所以基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能

缓冲池就是一块内存区域,通过内存的速度来弥补磁盘速度慢对于数据库性能的影响,在数据库进行读取页的操作,先从磁盘读到的页放在缓存池中,下一次读到相同页时,首先判断该页是否在缓冲池中,如果在,则直接读取该页,否则再去读取磁盘上的页;对数据库进行修改页操作时,首先会修改在缓冲池中的页,然后在以一定的频率刷新到磁盘,通过一种Checkpoint的机制刷新回到磁盘

LRU列表

缓冲池是使用LRU来进行实现的,但是最新访问的页不是放在LRU列表的首部,而是放在midpoint的位置,midpoint之前的列表称为new列表,之后的列表称为old列表

在数据库刚启动的时候,LRU列表是空的,所有的页都存在Free列表中,当需要从缓冲池中分页时,首先从Free列表中查找是否有可用的空闲页,若有则将该页从Free列表中删除,放到LRU列表中;如果没有空闲页,则从LRU列表中淘汰LRU末尾的页,将内存空间分配给新的页

当页从LRU列表的old部分加入到new部分时,此时发生的操作为page made young,而因为innodb_old_blocks_time的设置导致页没有从old部分移到new部分的操作称为page not made young

Checkpoint机制

在Update或者delete改变了缓冲池页中的记录,此时缓冲池中的页的版本要比磁盘的新,数据库需要将新版本的页从缓冲池刷新到磁盘,但是如果每次一个页发生变化,就将新页的版本刷新到磁盘,那么开销太大了,而且如果热点数据集中在某几个页的话,那么数据库的性能将变得非常差,同时,如果在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么数据就无法恢复了

为了避免数据丢失的问题,当前事务数据库系统普遍采用了Write Ahead Log策略,即当事务提交时,先写重做日志,在修改页,当出现发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复

Checkpoint作用

  • 缩短数据库的恢复时间
  • 缓冲池不够用时,将脏页刷新到磁盘
  • 重做日志不可用时,刷新脏页

当数据库发生宕机时,数据库不需要重做所有的日志,因为checkpoint之前的页都已经刷新回磁盘,数据库只需对checkpoint后的重做日志进行恢复

当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行checkpoint,将脏页的新版本刷回磁盘

缓冲池状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 使用show engine innodb status 查看BUFFER POOL AND MEMORY 部分的数据可以监控到当前缓冲池的状态
show engine innodb status \G

----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137428992
Dictionary memory allocated 1169885
Buffer pool size 8191 缓冲池的总页数 116K
Free buffers 1024 Free列表的页数
Database pages 7057 LRU列表的页数
Old database pages 2585 在旧区域存放的页数
Modified db pages 397 脏页的数量,缓冲池中的数据修改之后还没有通过checkpoint机制刷新回磁盘的页
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 974712674, not young 300236312913 显示LRU列表中页移动到新区域的页数和没有移动到新区域的页数
12.67 youngs/s, 17.85 non-youngs/s 每秒移动到新区域的页数,每秒没有移动到新区域的页数
Pages read 82636365416, created 3980108, written 98719374
4.79 reads/s, 0.27 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000 缓冲池的命中率, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 7057, unzip_LRU len: 0
I/O sum[2268]:cur[0], unzip sum[0]:cur[0]

也可以通过information_schema数据库中的innodb_buffer_pool_stats表和innodb_buffer_page_lru表来观察缓冲池的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
select * from information_schema.innodb_buffer_pool_stats \G
*************************** 1. row ***************************
POOL_ID: 0
POOL_SIZE: 8191
FREE_BUFFERS: 1024
DATABASE_PAGES: 7048
OLD_DATABASE_PAGES: 2581
MODIFIED_DATABASE_PAGES: 432
PENDING_DECOMPRESS: 0
PENDING_READS: 0
PENDING_FLUSH_LRU: 0
PENDING_FLUSH_LIST: 0
PAGES_MADE_YOUNG: 974713203
PAGES_NOT_MADE_YOUNG: 300236843670
PAGES_MADE_YOUNG_RATE: 3.3327778703549407
PAGES_MADE_NOT_YOUNG_RATE: 8.831861356440593
NUMBER_PAGES_READ: 82636555958
NUMBER_PAGES_CREATED: 3980142
NUMBER_PAGES_WRITTEN: 98719415
PAGES_READ_RATE: 1.3331111481419762
PAGES_CREATE_RATE: 0.33327778703549404
PAGES_WRITTEN_RATE: 0
NUMBER_PAGES_GET: 593888334602
HIT_RATE: 1000
YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
NUMBER_PAGES_READ_AHEAD: 936526790
NUMBER_READ_AHEAD_EVICTED: 13356538
READ_AHEAD_RATE: 0
READ_AHEAD_EVICTED_RATE: 0
LRU_IO_TOTAL: 220
LRU_IO_CURRENT: 0
UNCOMPRESS_TOTAL: 0
UNCOMPRESS_CURRENT: 0

-- 每个LRU列表中每个页的具体信息
select * from information_schema.innodb_buffer_page_lru where space=1 \G
*************************** 1. row ***************************
POOL_ID: 0
LRU_POSITION: 5729
SPACE: 1
PAGE_NUMBER: 3
PAGE_TYPE: INDEX
FLUSH_TYPE: 0
FIX_COUNT: 0
IS_HASHED: NO
NEWEST_MODIFICATION: 0
OLDEST_MODIFICATION: 0
ACCESS_TIME: 179797437
TABLE_NAME: `mysql`.`innodb_table_stats`
INDEX_NAME: PRIMARY
NUMBER_RECORDS: 160
DATA_SIZE: 10900
COMPRESSED_SIZE: 0
COMPRESSED: NO
IO_FIX: IO_NONE
IS_OLD: NO
FREE_PAGE_CLOCK: 1036344415

缓冲池的配置

  • innodb_buffer_pool_size 缓冲池大小
  • innodb_buffer_pool_instances 缓冲池实例个数
  • innodb_old_blocks_pct 最新读取到的页放在缓冲池中的位置,缓冲池是使用LRU来进行实现的,但是最新访问的页不是放在LRU列表的首部,而是放在midpoint的位置,由该配置设置midpoint位置,默认是37,表示LRU尾部的37%的位置,midpoint之前的列表称为new列表,之后的列表称为old列表
  • innodb_old_blocks_time 表示页读取到mid位置后需要等待多久才会被加入到LRU列表的热端,用这种方式尽可能的使LRU列表中的热点数据不被刷出