22

WiredTiger存储引擎之六:Cache分配规则与Page的淘汰机制

 3 years ago
source link: https://mongoing.com/archives/75389
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

M3YveaJ.jpg!mobile

前言

WiredTiger存储引擎系列文章将从逻辑正确、内容完整的角度全面介绍WiredTiger存储引擎。本篇作为WiredTiger存储引擎介绍系列文章第六篇,也是本系列文章的最后一篇。

前面的内容您可以点击下方标题进行阅读:

本篇包含以下内容:

  • WiredTiger存储引擎的Cache分配规则
  • 内存Page的淘汰机制

1.2 Cache的分配机制

WiredTiger启动的时候会向操作系统申请一部分内存给自己使用,这部分内存我们称为Internal Cache,如果主机上只运行MongoDB相关的服务进程,则剩下的内存可以作为文件系统的缓存(File System Cache)并由操作系统负责管理,如下图所示:

6vmiAbN.jpg!mobile

图:Cache的分配规则

MongoDB启动时,首先从整个主机内存中切一大块出来分给WiredTiger的Internal Cache,用于构建B-Tree中的各种page以及基于这些page的增删改查等操作。

从MongoDB3.4版本开始,默认的Internal Cache大小由下面的规则决定:比较50% of (RAM – 1 GB)和256MB的大小,取其中较大者。例如,假设主机内存为10GB,则Internal Cache取值为50% of (10GB – 1 GB),等于4.5GB;

如果主机内存为1.2GB,则Internal Cache取值为256MB。

然后,会从主机内存再额外划一小块给MongoDB创建索引专用,默认最大值为500MB,这个规则适用于所有索引的构建,包括多个索引同时构建时。

最后,会将主机剩余的内存(排除其它进程的使用)作为文件系统缓存,供MongoDB使用,这样MongoDB可将压缩的磁盘文件也缓存到内存中,从而减少磁盘I/O。

为了节省磁盘空间,集合和索引在磁盘上的数据是被压缩的,默认情况下集合采取的是块压缩算法,索引采取的是前缀压缩算法。因此,同一份数据在磁盘、文件系统缓存和Internal Cache三个位置的格式是不一样的,如下描述:

  • 所有数据在File System Cache中的格式和在磁盘上的格式是一致的,将数据先加载到文件系统缓存,不但可以减少磁盘I/O次数,还能减少内存的占用;
  • 索引数据加载到WiredTiger的Internal Cache后,格式与磁盘上的格式不一样,但仍能利用其前缀压缩的特性(即去掉索引字段上重复的前缀)减少对内存的占用;
  •  集合数据加载到WiredTiger的Internal Cache后,其数据必须解压后才能被后续各种操作使用,因此格式与磁盘上和File System Cache都不一样。

1.3 Page淘汰机制

当cache里面的“脏页”达到一定比例或cache使用量达到一定比例时就会触发相应的evict page线程来将pages(包含干净的pages和脏pages)按一定的算法(LRU队列)淘汰出去,以便腾挪出内存空间,保障后面新的插入或修改等操作。

触发page eviction条件由如下几种参数控制,如下表所示:

参数名称

默认配置值 含义

eviction_target

80%

当Cache的使用量达到80%时触发work thread淘汰page

eviction_trigger

90%

当Cache的使用量达到90%时触发application thread和work thread淘汰page

eviction_dirty_target

5%

当“脏数据”所占Cache比例达到5%时触发work thread淘汰page

eviction_dirty_trigger 20%

当“脏数据”所占Cache比例达到20%时触发application thread和work thread淘汰page

第一种情况:当cache的使用量占比达到参数eviction_ target设定值时(默认为80%),会触发后台线程执行page eviction;

如果使用量继续增长达到eviction_trigger参数设定值时(默认为90%),应用线程支撑的读写操作等请求将被阻塞,应用线程也参与到页面的淘汰中,加速淘汰内存中pages。

第二种情况:当cache里面的“脏数据”达到参数eviction_dirty_target设定值时(默认为5%),会触发后台线程执行page eviction;

如果“脏数据”继续增长达到参数eviction_dirty_trigger设定值(默认为20%),同时会触发应用线程来执行page eviction。

还有一种特性情况:当在page上不断进行插入或更新时,如果页上内容占用内存空间的大小大于系统设定的最大值(memory_page_max),则会强制触发page eviction动作。

先通过将此大的page拆分为多个小的page,再通过reconcile将这些小的pages保存到磁盘上,一旦reconcile写入磁盘完成,这些pages就能从cache中淘汰出去,从而为后面更多的写入操作腾出空间。

默认情况下WiredTiger只使用一个后台线程来完成page eviction,为了提升eviction的性能,我们可以通过参数threads_min和threads_max来设定evict server启动的后台线程数。

通过设定合理值,加速页面淘汰,避免淘汰不及时导致应用线程也被迫加入到淘汰任务中来,造成应用线程对其它正常请求操作的阻塞。

淘汰一个page时,会先锁住这个page,再检查这个page上是否有其它线程还在使用(判断是否有hazard point指针指向它),如有则不会evict这个page。

6VZ7Rz.png!mobile 专栏作者:郭远威

资深大数据解决方案咨询顾问与架构师,MongoDB中文社区委员,长沙分会主席,多年通信行业大数据研发、规划、咨询经验;《大数据存储MongoDB实战指南》作者;阿里云云计算ACP认证专家。

也许您还感兴趣——


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK