其他分享
首页 > 其他分享> > buffer pool 的内部原理和结构

buffer pool 的内部原理和结构

作者:互联网

InnoDB architecture diagram showing in-memory and on-disk structures.

行记录     

  


变长字段长度列表:存储变长字段的长度,如varchar、text、blob

null值列表:记录各列是否为null  1:null  0:非null

隐藏列 ROW_ID: 没有创建主键 并且没有唯一索引的时候会默认创建 rowId,,否则不创建

    trx_id:事务的id

    roll_ptr:回滚的id

记录头信息:5个字节

    delete_mark :删除标志

    min_rec_mark: B+树每层非叶子节点中最小的记录会记录本值

    n owned:一个槽中索引最大的行会存储此值,记录这个槽中有多少条记录

    heap_no:记录在页的位置

    record_type: 0:普通记录、1:非叶子节点、2:最小记录、3:最大的记录

    next_record:下一条记录的地址,在一个数据页中记录的是单向列表,下一条记录 不是按照插入顺序记录的 是按照键值的大小排序的。

行记录的格式分为:compect 、dynamic、compress、redundant

各个格式之间的区别

redundant:5.0以前的版本

compect:对于数据溢出,一页存不下的行,可存储前768的数据,后面用20个字节指向溢出页的地址

dynamic:会把所有的字段都存储到溢出页,只记录溢出页的地址

compress;采用压缩算法对页面数据进行压缩,对于溢出数据同dynamic的处理方式

 

 

 File header: 38个字节,存储的是页面的编号、上一页 下一页、存储验证码,各种类型的页面通用的。

 File trailer: 8个字节    前四个字节存储和fileheader 一致的验证码,后四个字节存储修改时对应的日志位置。

page head: 56个字节 ,存储该页面又多少行记录、多少槽、第一条记录的地址是多少

user records:存储的是用户数据,存储的是一个链表,当一行记录被删除了,delete_mark被标记成1,从该链表中删除,增加到可复用的链表中,而不是回收这块空间,因为回收空间会引起页面的分裂重新排序浪费性能

infimum:+ supremum:26个字节  内容是0  本页数据中的最小值

supremum:本页数据中的最大值 内容是1

page directory:记录每个槽中最大记录的偏移地址,为了解决一个页面通过链表查询数据慢的情况,引入了槽的概念,使用槽先进性二分查找,找到具体的槽之后 进行链表遍历,变得链表最大长度为8,类似于hashmap,

 

 

 

free space:未被占用的空间

一个页用16k的大小

 

 

 

在屋里内存上是一块连续的空间,写入的时候是顺序io,包含64个页,也就是一个区有1个M的空间

每256个区被划分成一组,表空间的第一个组用于存储一些整体属性,每组开始的两个页面用于存储256个区的一些属性

可分为叶节点段,非叶子节点段,回滚段,用于全表扫描可剩更少的内存

innobd的磁盘空间分布

独立表空间

用于存储.idb文件,如果innodb_file_per_table 为ON则存储在表空间  否则 存储在通用表空间

系统表空间

存储了双写缓冲区、数据字典的系统表等

共享表空间

临时表空间

双写缓冲区(doublewrite buffer)

buffer pool中也有一份,2个区,也就是2M。innnodb是按照页尾单位写入磁盘的,每个页16kb,但是磁盘写入的单位 每个扇区一般是4k,所以写入一页要分4次写入,如果在写入磁盘的过程中发生了宕机情况就会造成数据页损坏;

等到下次重启的时候,因为redolog是存储的更改逻辑,需要结合原数据进行数据合并后得到正确的结果,单数数据页损毁原数据不在,所以这种情况不能通过redolog进行修复。

即引入了双写缓存区, 先写在磁盘的双写缓冲区里,在写入独立表空间。如果表空间的的数据页损毁 可通过双写缓冲区进行恢复;

如果双写缓冲区也损毁 则通过redolog 进行恢复,因为此时表空间的原始数据没有损毁;

因为需要两次io 所以开启了双写缓冲区 会增加性能的消耗 一般在5%~10%之间。

开启双写缓冲区参数:innodb_doublewrite

数据字典

SYS_TABLES  整个InnoDB存储引擎中所有的表的信息

SYS_COLUMNS  整个InnoDB存储引擎中所有的列的信息

SYS_INDEXES  整个InnoDB存储引擎中所有的索引的信息

SYS_FIELDS  整个InnoDB存储引擎中所有的索引对应的列的信息

SYS_FOREIGN  整个InnoDB存储引擎中所有的外键的信息

SYS_FOREIGN_COLS  整个InnoDB存储引擎中所有的外键对应列的信息

SYS_TABLESPACES 整个InnoDB存储引擎中所有的表空间信息

SYS_DATAFILES  整个InnoDB存储引擎中所有的表空间对应文件系统的文件

change buffer/insert buffer

是bufferpool中的一块空间,默认占25%,磁盘中持久化放在系统表空间里

 

 

 是针对二级索引更改的优化,是更改逻辑的缓存。不着急进行io写入,等数据进行访问、空闲时刻、正常关机的情况下 进行merge,

 

redolog

undolog

buffer pool 的结构

是mysql 启动时像os申请的一块空间

存储数据、change buffer、redolog

 

show  status   like "%Innodb_buffer_pool_pages%";

 

 

 Innodb_buffer_pool_pages_data:占用的数据页

Innodb_buffer_pool_pages_dirty:脏页

Innodb_buffer_pool_pages_flushed:被刷的脏页

Innodb_buffer_pool_pages_free:空闲页

Innodb_buffer_pool_pages_misc:其他系统数据占用的页

Innodb_buffer_pool_pages_total:buffer pool的总页数

buffer pool的内存大小

show variables like "%innodb_buffer_pool_size%";

展示的为字节数,是128M,在使用单独的服务器时,官方建议设置成内存的80%,但是还有一些额外的内存可能会占用到90%,所以一般是60%~75%左右,这个值由DBA根据系统业务高峰期 内存占用率具体设置

buffer pool的free list

 

 

 

内存会分成一个个的页大小的空间,并增加对应的控制块(这个控制块并不占用buffer pool的申请的内存)

控制块中包括该页所属的表空间编号、页号、缓存页在Buffer Pool中的地址、链表节点信息、一些锁信息以及LSN信息,当然还有一些别的控制信息。

没有被使用的页的控制块组成的双向列表称为 free list;

当需要寻找寻找一页数据页看是否在缓存中时  适应表空间号+页号当做key 在hash列表中可以找到对应的页,如果没有需要去磁盘中加载

buffer pool的flush list

脏页对应控制块组成的双向列表称为 flush list

简单的LRU list的算法规则

用内存就需要用到内存淘汰的机制,

 LRU :least recently used   每次访问被访问的数据就添加到列表的头部。慢慢的不经常的访问的数据就会被过滤到尾部,淘汰时先从尾部淘汰

预读

INNODB 根据计算机的局部性原理 会预读数据

线性预读:当访问的页超过 56(innodb_read_ahead_threshold)就会把整个区读入缓存

局部预读:当一个区中访问的页超过13个 无论些是不是连续的 就会把整个区读入缓存 默认该功能是关闭的 innodb_random_read_ahead

预读和全表扫描的情况下简单的LRU list的产生的后果

全表扫描数据量大 势必会淘汰一部分之前的内存,其中会包含热数据

预读的数据会放在优先访问的位置,使原来的热数据后移如果预读的数据不会被使用 则大大降低了缓存的命中

buffer pool的LRU改进点

将LRU list 分为两部分 前部分为热数据 成为 yong区,后面为冷数据 成为old区;
innodb_old_blocks_pct  默认是37 也就是old区占比3/8 

新缓存进来的页放入old区

设置old区页面访问的间隔,SHOW VARIABLES LIKE 'innodb_old_blocks_time';  默认是1s 也就是说old区的页面第一次访问和最后一次访问的时间间隔不到一秒 会默认是全表扫描的页面 不加入yang区;

对于yong区的数据 后面四分之一的数据被击中才需要移到前面

刷脏页

多个buffer pool

show variables like "%innodb_buffer_pool_instances%"; 默认是1,设置多个buffer pool的实例可以增加并发的性能,最小是1  最大的64,如果每个实例内存分配不到1个G则强制为1;

内存分配innodb_buffer_pool_size/innodb_buffer_pool_instances

chunk

5.7.5之后的版本可以在系统运行时设置buffer pool的大小;

为了不要把原内存的数据重新复制到新的空间 引入了chunk的概念,默认是128M innodb_buffer_pool_chunk_size;

以chunk为单位向系统申请空间

 

 

SHOW ENGINE INNODB STATUS\G buffer pool的系统状态

 

 Total memory allocated:代表Buffer Pool向操作系统申请的连续内存空间大小,包括全部控制块、缓存页、以及碎片的大小。

Dictionary memory allocated:为数据字典信息分配的内存空间大小,注意这个内存空间和Buffer Pool没啥关系,不包括在Total memory allocated中。

Buffer pool size:代表该Buffer Pool可以容纳多少缓存页,注意,单位是页!

Free buffers:代表当前Buffer Pool还有多少空闲缓存页,也就是free链表中还有多少个节点。

Database pages:代表LRU链表中的页的数量,包含young和old两个区域的节点数量。

Old database pages:代表LRU链表old区域的节点数量。

Modified db pages:代表脏页数量,也就是flush链表中节点的数量。

Pending reads:正在等待从磁盘上加载到Buffer Pool中的页面数量。当准备从磁盘中加载某个页面时,会先为这个页面在Buffer Pool中分配一个缓存页以及它对应的控制块,然后把这个控制块添加到LRU的old区域的头部,但是这个时候真正的磁盘页并没有被加载进来,Pending reads的值会跟着加1。

Pending writes LRU:即将从LRU链表中刷新到磁盘中的页面数量。

Pending writes flush list:即将从flush链表中刷新到磁盘中的页面数量。

Pending writes single page:即将以单个页面的形式刷新到磁盘中的页面数量。

Pages made young:代表LRU链表中曾经从old区域移动到young区域头部的节点数量。

Page made not young:在将innodb_old_blocks_time设置的值大于0时,首次访问或者后续访问某个处在old区域的节点时由于不符合时间间隔的限制而不能将其移动到young区域头部时,Page made not young的值会加1。

youngs/s:代表每秒从old区域被移动到young区域头部的节点数量。

non-youngs/s:代表每秒由于不满足时间限制而不能从old区域移动到young区域头部的节点数量。

Pages read、created、written:代表读取,创建,写入了多少页。后边跟着读取、创建、写入的速率。Buffer pool hit rate:表示在过去某段时间,平均访问1000次页面,有多少次该页面已经被缓存到Buffer Pool了。

young-making rate:表示在过去某段时间,平均访问1000次页面,有多少次访问使页面移动到young区域的头部了。

not (young-making rate):表示在过去某段时间,平均访问1000次页面,有多少次访问没有使页面移动到young区域的头部。

LRU len:代表LRU链表中节点的数量。

unzip_LRU:代表unzip_LRU链表中节点的数量。

I/O sum:最近50s读取磁盘页的总数。

I/O cur:现在正在读取的磁盘页数量。

I/O unzip sum:最近50s解压的页面数量。

I/O unzip cur:正在解压的页面数量。

自适应hash

 

 

 

标签:存储,buffer,链表,LRU,原理,pool,页面
来源: https://www.cnblogs.com/xiatc/p/16382983.html