WiredTiger系列2:Eviction详解

article/2025/8/16 20:11:54

Eviction

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

这个流程中存在两个淘汰队列分别为待淘汰的填充队列(evict_fill_queue)和当前淘汰队列(evict_current_queue),evict会不断地将符合淘汰条件的page交替待淘汰queue,然后会从淘汰队列中将page淘汰出内存。待淘汰queue和当前淘汰queue角色会进行切换。

Evict有两种触发方式,一种是WiredTiger内部线程触发,另一种为用户操作(search/insert等)触发,这里我们将两者分别称为内部evict与外部evict,本文主要介绍内部evict。

首先来了解一下cache所管理的空间。
WT cache管理的空间就是内存page的内存空间,page的内存分为几部分:

  1. 从磁盘上读取到的已经刷盘的数据,即前文描述的dsk内存缓存。
  2. Page在内存中新增的修改事务数据。
  3. Page基本的数据结构所有的内存空间。

WT维护了每个page的内存总量,总的内存使用量mem_size,以及增删改造成的脏页数据总量dirty_mem_size。每次对页进行载入、增删改、分裂和销毁时对上面的数据做原子增加或者减少计数,这样可以精确计算到当前系统中WT引擎内存占用量。

那么结合cache所管理的空间,这里简要介绍page eviction相关的几个参数:

参数名称默认配置值含义
eviction_target80当cache使用量达到该百分比时触发内部evict,能够淘汰clean page
eviction_trigger90当cache使用量达到该百分比时触发内部或外部evict,能够淘汰clean page
eviction_dirty_target5当cache“脏”数据量达到该百分比时触发内部evict,只能淘汰dirty page
eviction_dirty_trigger20当cache“脏”数据量达到该百分比时触发内部或外部evict,只能淘汰dirty page
memory_page_max5MB内存中page允许的最大数据量,但并不是严格控制的

外部evict

当用户操作(insert/search等)开始某事务时将调用cache check(__wt_cache_eviction_check)函数判断是否触发全局的evict(可以理解为触发内部evict),此时需要满足的条件是cache使用量达到eviction_trigger或者cache dirty数据量达到evict_dirty_trigger

此外,每次需要读取内存page时,可能会对page当前的数据量进行判断,当超过memory_page_max时,如果满足in-memory split的条件时,进行在内存上完成的page split,否则直接在该用户线程上对该page进行evict。

内部evict

内部evict包括page的选取(evict pass)以及page的淘汰(evict page)两个完整流程。

基本思路是一个线程阶段性的去扫描各个btree,并把btree可以进行淘汰的数据page添加到一个lru queue中,每个btree每次扫描最多选取一定数量的page,每个btree扫描结束后记录下btree内当前访问所在的位置,作为下次该btree阶段性扫描的起始位置,并在整个扫描结束后记录下当前扫描的btree对象,作为下次阶段性扫描的起始位置。然后对queue中的数据页按照访问热度排序,当queue中有足够多的page后,各个淘汰线程按照淘汰优先级对queue中的数据页进行淘汰,整个过程是周期性重复。

从线程工作内容来说,内部evict的线程可以分为server线程与worker线程,server线程负责扫描内存中的btree,将符合条件的page加入lru queue,并且在evict很繁忙的时候也会参与page的淘汰;worker线程负责执行page的淘汰,包括内存page的写盘(reconcile)、结构更新等。

server线程与worker线程事实上为一组evict线程,线程通过抢占锁的形式转变为server线程,同一时间只会有一个server线程和多个worker线程。
server-worker线程模型

evict pass策略

前面介绍过evict pass是一个阶段性扫描的过程,整个过程分为扫描阶段、评分排序阶段和evict调度阶段。扫描阶段是通过扫描内存中btree,检查btree在内存中的page对象是否可以进行淘汰。扫描步骤如下:

  1. 根据上次evict pass最后扫描的btree和它对应扫描的位置作为本次evict pass的起始位置,如果当前扫描的btree被其他事务线程设成独占访问方式,跳过当前btree扫描下个btree对象。
  2. 进行btree遍历扫描,如果page满足淘汰条件,将page的ref对象添加到evict queue中,淘汰条件为:
    1. 根据前述触发条件判断clean page/dirty page是否能够淘汰
    2. 如果page是数据页,page当前最新的修改事务必须早以evict pass事务。
    3. 如果page是btree内部索引页,page当前最新的修改事务必须早以evict pass事务且当前处于evict queue中的索引页对象不多于一定数量。
    4. 当前btree不处于正建立checkpoint状态
  3. 如果本次evict pass当前的btree有超过100个page在evict queue中或者btree处于正在建立checkpoint时,结束这个btree的扫描,切换到下一个btree继续扫描。
  4. 如果evict queue填充满时或者本次扫描遍历了所有btree,结束本次evict pass。
    评分排序阶段是在evict pass后进行的,当queue中有page时,会根据每个page当前的访问次数、page类型和淘汰失败次数等计算一个淘汰评分,然后按照评分从小打到进行快排,排序完成后,会根据queue中最大分数和最小分数计算一个淘汰边界,queue中所有大于淘汰边界的page不列为淘汰对象。

**WT为了让internal page尽量保存在内存中,在评分的时候internal page的分值会加上1000分,让internal page免受淘汰。**事实上,从源码反映出,当internal page的子page仍然alive时,是不允许被淘汰的。

evict page

evict page其实就是将evict queue中的page数据先写入到磁盘文件中,然后将内存中的page对象销毁回收。

page的写过程在WT中称为reconcile。由前文已知,in-memory page与 on-disk extent是不同的数据组织结构,两者的上限在实际场景中也不相同,in-memory page的默认上限memory_page_max是5MB,而on-disk extent的默认上限根据类型不同而不同,leaf extent的默认上限leaf_page_max是32KB,internal extent的默认上限internal_page_max是4KB。如果page的内存空间在reconcile时超过75%的memory_page_max,那么需要page做split操作(为了与in-memory split区分开,这里我们称为on-disk split)。

整个写过程步骤如下:

  1. 以row array为轴,扫描整个row array(即dsk内存缓冲区)、update list array和insert skiplist array,将每个需要写盘的k/v转换成cell_t对象,并将其依次存入一个缓冲区(chunk)中,该chunk最终将作为extent写入磁盘,因此缓冲区头部会预留page header与block header的空间。
  2. 判断这个缓冲区是否超出了对应类型的on-disk extent上限,如果超过了,进行on-disk split操作,简单来说可以理解为3~6步
  3. 根据page对象中的wt_page_header的信息将它对应的信息写入到chunk头位置。
  4. 选择当前btree文件的空闲块中大小最合适的块,裁选出所需大小的块(如果没有这样的空闲块,那么向文件末尾写入),得到将写入btree文件的偏移地址,计算chunk,也即extent的checksum
  5. 根据extent的信息填充block_header,将整个extent写入到btree的文件当中并返回extent address。
  6. 将该chunk加入到一个链表中,并维护该chunk写盘的address cookie
  7. 重复步骤1~6,直到所有需要写盘的k/v cell_t都完成写盘操作

下图描述了某page完成reconcile后发生的变化:

reconile示意图

如上图所示,在page完成reconcile后,由于进行了on-disk split,原page一分为三,原extent由于不再被使用,能够进行回收(磁盘块的管理与checkpoint相关,这里不详细描述)。

每个新page对应盘上新的extent,而新extent的addr与key并没有直接更新到父节点,而是通过off-page addr以及instantiated key的形式保留在内存,并设置父节点为脏节点,当父节点被evict从而reconcile时,再随着父节点写到盘上。当内存用量小时,每个page在reconcile时的chunk能够保留在内存,作为__wt_page的dsk内存缓冲区。

参考文献
袁荣喜.WiredTiger文档.
郭远威.WiredTiger存储引擎系列文章.
阿里云.WiredTiger page逐出.


http://chatgpt.dhexx.cn/article/aiLdx7sK.shtml

相关文章

onload事件

onload事件&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script type"text/javascript">//onload事件的方法function onloadFun(){alert(静态注…

onUnload事件

1. 首先JavaScript会使我们有能力创建动态页面然后JavaScript是可以被侦测到事件行为的然而在网页中的每一个元素都将可以来产生某些可以触发JavaScript的函数的事件就可以打个比方说我们在用户中里面点击某个按钮时的产生的某一个onClick 事件来触发某个函数之后就在事件中在H…

script标签的onload事件的触发时机

onload事件在资源被加载完成后会被触发。对于script标签&#xff0c;在外部js文件被加载后代码会被立即执行。那么&#xff0c;外部js文件中的代码和该script标签的onload回调函数&#xff0c;它们的执行顺序是怎样的呢&#xff1f;没有找到官方的说明文档&#xff0c;所以自己…

load事件

javaScript中最常用到的一个事件就是load。当页面完全加载后&#xff08;包括所有图像、javaScript文件、css文件等外部资源&#xff09;&#xff0c;就会触发window上边的load事件。 window&#xff1a; window.addEventListener(load, function(e) {console.log(页面完全加…

onload 和 onunload 事件

onload 和 onunload 事件会在用户进入或离开页面时被触发。onload 事件可用于检测访问者的浏览器类型和浏览器版本&#xff0c;并基于这些信息来加载网页的正确版本。onload 和 onunload 事件可用于处理 cookie。 onmousedown,onmouseup 以及 onclick 构成了鼠标点击事件的所有…

window的onload事件的用法

1.最简单的用法 注&#xff1a;奇葩&#xff0c;我没用过 2.在JS语句调用&#xff08;正确使用姿势&#xff09; 或使用jquery onload 事件会在页面或图像加载完成后立即发生。 3.window.onload()的加载问题 由于HTML加载时由上往下的&#xff0c;在HTML加载的时候&#…

JS中window.onload事件详解

window.onload出现的原因&#xff1f;  我们都知道页面的代码顺序是从上往下进行加载&#xff0c;很多时候我们要对页面中的某一个模块进行操作&#xff0c;这时候我们常常使用javascript代码来进行操作。为了能够保证操作的模块或对象在js代码之前就加载了&#xff0c;我们不…

浏览器的onload事件

如下代码&#xff0c;因为代码从上到下执行&#xff0c;btn节点还未创建好就去获取会报错 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge&q…

JavaScript的window.onload事件的理解

window.onload()的作用 window.onload() 方法用于在网页加载完毕后立刻执行的操作&#xff0c;即当 HTML 文档加载完毕后&#xff0c;立刻执行某个方法。window.onload() 通常用于 元素&#xff0c;在页面完全载入后(包括图片、css文件等等)执行脚本代码。 只有一个要执行的函…

I2C协议——I2C框图和I2C通信过程

1.软件模拟和硬件模拟的概念 所谓软件模拟&#xff0c;即直接使用 CPU 内核按照 I2C 协议的要求控制 GPIO 输出高低电平。如控制产生 I2C 的起始信号时&#xff0c;先控制作为 SCL 线的 GPIO 引脚输出高电平&#xff0c;然后控制作为 SDA 线的 GPIO 引脚在此期间完成由高电平至…

通信协议——I2C协议/IIC协议解析

目录 I2C协议概述 I2C通信原理 I2C通信时序 I2C协议概述 同步通信 半双工&#xff08;分时&#xff09; 串行传输 电平信号 特点&#xff1a;①有两根传输线&#xff08;时钟线SCL、双向数据线SDA&#xff09; ②主从模式&#xff1a;通信双方为主设备&#xff08;Master&…

I2C基础

I2C基础 1 基本介绍2 特点3 硬件连接4 通信4.1 控制器4.2 协议 5 SPI VS I2C 1 基本介绍 IC (Inter-Integrated Circuit)。内部集成电路。拥有两根线&#xff0c;一根数据线SDA和一根时钟线SCL。 这两条线都是漏极开路或者集电极开路结构&#xff0c;使用时需要外加上拉电阻&a…

I2C总线协议

1. 简介 I2C (Inter-Integrated Circuit&#xff09;&#xff0c;是一种串行通信总线&#xff0c;用于连接微控制器及其外围设备&#xff0c;实现主控制器和从器件间的主从双向通信&#xff0c;是一种同步半双工通信(两端时钟频率一致&#xff0c;双向通信&#xff0c;但不能同…

I2C协议最细致的讲解

I2C通讯协议(Inter—lntegrated Circuit)是由Phiilps公司开发的&#xff0c;由于它引脚少&#xff0c;硬件实现简单&#xff0c;可扩展性强&#xff0c;不需要USART、CAN等通讯协议的外部收发设备&#xff0c;现在被广泛地使用在系统内多个集成电路(IC)间的通讯。 I2C物理层的特…

沧小海详解面试的必答题——I2C协议

目录 第一部分&#xff1a;I2C协议的概述 第二部分&#xff1a;I2C协议的阐述 第三部分&#xff1a;AT24C04简述 第四部分&#xff1a;基于verilog的程序设计&#xff08;暂无&#xff09; 对于大多从事FPGA行业的应届生来说&#xff0c;在面试过程中很可能会被问到关于I2C…

51单片机模拟I2C协议

什么是I2C 首先需要知道什么是I2C协议。I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息&#xff08;摘自百度百科&#xff09;。I2C主要有两条线&#xff0c;一条SDA数据线&#xff0c;一条SCL时钟线。由…

I2C协议原理讲解

一、物理层&#xff1a; 1、I2C通讯设备之间的常用连接方式&#xff1a; 2、特点&#xff1a; (1) 它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个I2C通讯总线中&#xff0c; 可连接多个I2C通讯设备&#xff0c;支持多个通讯主机及多个通讯从机。 (2) 一个…

一文搞懂I2C协议-硬件基础

I2C是什么 I2C总线是由飞利浦在80年代初设计的&#xff0c;以允许位于同一电路板上的组件之间能够轻松通信。其大大简化了电路的设计&#xff0c;早期的电视机中很多地方用到了I2C这种通信方式。飞利浦半导体于2006年迁移到了NXP。I2C名称翻译为“ Inter IC”。有时&#xff0…

I2C协议+实现源码

文章目录 摘要I2C通信协议简介补充空闲状态start和stop信号应答信号数据有效性规定数据传输延时 I2C协议的实现源码硬件说明头文件sys.h 主函数初始化I2C产生开始和停止信号等待应答信号产生或不产生应答I2C写操作I2C读操作 对24C02操作24C02的时序图头文件初始化IIC接口写数据…

学习笔记8-I2C协议

目录 一、关于I2C二、硬件结构三、I2C协议3.1、I2C的三种状态3.2、数据有效性3.3、应答信号3.4、总线时序3.5、读写时序3.5.1、读3.5.2、写 3.6、死锁3.7、仲裁 四、软件I2C&硬件I2C五、AT24C02六、代码编写6.1、I2C初始化6.2、开始信号6.3、ACK/NACK信号6.4、发送1byte数据…