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 \G
BUFFER POOL AND MEMORY
Total large memory allocated 137428992 Dictionary memory allocated 1169885 Buffer pool size 8191 缓冲池的总页数 1页16K 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
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列表中的热点数据不被刷出