Mongo 进阶 - WT 引擎:Page 生命周期 | Java 全栈知识体系

通过前文我们了解到数据以 page 为单位加载到 cache; 有必要系统的分析一页 page 的生命周期、状态以及相关参数的配置,这对后续 MongoDB 的性能调优和故障问题的定位和解决有帮助。@pdai

  为什么要了解 Page 生命周期


  通过前文我们了解到数据以 page 为单位加载到 cache、cache 里面又会生成各种不同类型的 page 及为不同类型的 page 分配不同大小的内存、eviction 触发机制和 reconcile 动作都发生在 page 上、page 大小持续增加时会被分割成多个小 page,所有这些操作都是围绕一个 page 来完成的。

  因此,有必要系统的分析一页 page 的生命周期、状态以及相关参数的配置,这对后续 MongoDB 的性能调优和故障问题的定位和解决有帮助。

  Page 的生命周期


  Page 的典型生命周期如下图所示:

  • 第一步:pages 从磁盘读到内存;
  • 第二步:pages 在内存中被修改;
  • 第三步:被修改的脏 pages 在内存被 reconcile,完成后将 discard 这些 pages。
  • 第四步:pages 被选中,加入淘汰队列,等待被 evict 线程淘汰出内存;
  • 第五步:evict 线程会将“干净“的 pages 直接从内存丢弃(因为相对于磁盘 page 来说没做任何修改),将经过 reconcile 处理后的磁盘映像写到磁盘再丢弃“脏的”pages。

  pages 的状态是在不断变化的,因此,对于读操作来说,它首先会检查 pages 的状态是否为 WT_REF_MEM​,然后设置一个 hazard 指针指向要读的 pages,如果刷新后,pages 的状态仍为 WT_REF_MEM,读操作才能继续处理。

  与此同时,evict 线程想要淘汰 pages 时,它会先锁住 pages,即将 pages 的状态设为 WT_REF_LOCKED​,然后检查 pages 上是否有读操作设置的 hazard 指针,如有,说明还有线程正在读这个 page 则停止 evict,重新将 page 的状态设置为 WT_REF_MEM​;如果没有,则 pages 被淘汰出去。

  Page 的各种状态


  针对一页 page 的每一种状态,详细描述如下:

  • WT_REF_DISK: 初始状态,page 在磁盘上的状态,必须被读到内存后才能使用,当 page 被 evict 后,状态也会被设置为这个。
  • WT_REF_DELETED: page 在磁盘上,但是已经从内存 B-Tree 上删除,当我们不在需要读某个 leaf page 时,可以将其删除。
  • WT_REF_LIMBO: page 的映像已经被加载到内存,但 page 上还有额外的修改数据在 lookasidetable 上没有被加载到内存。
  • WT_REF_LOOKASIDE: page 在磁盘上,但是在 lookasidetable 也有与此 page 相关的修改内容,在 page 可读之前,也需要加载这部分内容。

  当对一个 page 进行 reconcile 时,如果系统中还有之前的读操作正在访问此 page 上修改的数据,则会将这些数据保存到 lookasidetable;当 page 再被读时,可以利用 lookasidetable 中的数据重新构建内存 page。

  • WT_REF_LOCKED: 当 page 被 evict 时,会将 page 锁住,其它线程不可访问。
  • WT_REF_MEM: page 已经从磁盘读到内存,并且能正常访问。
  • WT_REF_READING: page 正在被某个线程从磁盘读到内存,其它的读线程等待它被读完,不需要重复去读。
  • WT_REF_SPLIT: 当 page 变得过大时,会被 split,状态设为 WT_REF_SPLIT,原来指向的 page 不再被使用。

  Page 的大小参数


  无论将数据从磁盘读到内存,还是从内存写到磁盘,都是以 page 为单位调度的,但是在磁盘上一个 page 到底多大?是否是最小分割单元?以及内存里面的各种 page 的大小对存储引擎的性能是否有影响?本节将围绕这些问题,分析与 page 大小相关的参数是如何影响存储引擎性能的。 总的来说,涉及到的关键参数和默认值如下表所示:

参数名称 默认配置值 含义
allocation_size 4KB 磁盘上最小分配单元
memory_page_max 5MB 内存中允许的最大 page 值
internal_page_max 4KB 磁盘上允许的最大 internal page 值
leaf_page_max 32KB 磁盘上允许的最大 leaf page 值
internal_key_max 1/10*internal_page internal page 上允许的最大 key 值
leaf_key_max 1/10*leaf_page leaf page 上允许的最大 key 值
leaf_key_value 1/2*leaf_page leaf page 上允许的最大 value 值
split_pct 75% reconciled 的 page 的分割百分比

  详细说明如下:

  • allocation_size

  MongoDB 磁盘文件的最小分配单元(由 WiredTiger 自带的块管理模块来分配),一个 page 的可以由一个或多个这样的单元组成;默认值是 4KB,与主机操作系统虚拟内存页的大小相当,大多数场景下不需要修改这个值。

  • memory_page_max

  WiredTigerCache 里面一个内存 page 随着不断插入修改等操作,允许增长达到的最大值,默认值为 5MB。当一个内存 page 达到这个最大值时,将会被 split 成较小的内存 pages 且通过 reconcile 将这些 pages 写到磁盘 pages,一旦完成写到磁盘,这些内存 pages 将从内存移除。

  需要注意的是:split 和 reconcile 这两个动作都需要获得 page 的排它锁,导致应用程序在此 page 上的其它写操作会等待,因此设置一个合理的最大值,对系统的性能也很关键。

  如果值太大,虽然 spilt 和 reconcile 发生的机率减少,但一旦发生这样的动作,持有排它锁的时间会较长,导致应用程序的插入或修改操作延迟增大;

  如果值太小,虽然单次持有排它锁的时间会较短,但是会导致 spilt 和 reconcile 发生的机率增加。

  • internal_page_max

  磁盘上 internalpage 的最大值,默认为 4KB。随着 reconcile 进行,internalpage 超过这个值时,会被 split 成多个 pages。

  这个值的大小会影响磁盘上 B-Tree 的深度和 internalpage 上 key 的数量,如果太大,则 internalpage 上的 key 的数量会很多,通过遍历定位到正确 leaf page 的时间会增加;如果太小,则 B-Tree 的深度会增加,也会影响定位到正确 leaf page 的时间。

  • leaf_page_max

  磁盘上 leaf page 的最大值,默认为 32KB。随着 reconcile 进行,leaf page 超过这个值时,会被 split 成多个 pages。

  这个值的大小会影响磁盘的 I/O 性能,因为我们在从磁盘读取数据时,总是期望一次 I/O 能多读取一点数据,所以希望把这个参数调大;但是太大,又会造成读写放大,因为读出来的很多数据可能后续都用不上。

  • internal_key_max

  internalpage 上允许的最大 key 值,默认大小为 internalpage 初始值的 1/10,如果超过这个值,将会额外存储。导致读取 key 时需要额外的磁盘 I/O。

  • leaf_key_max

  leaf page 上允许的最大 key 值,默认大小为 leaf page 初始值的 1/10,如果超过这个值,将会额外存储。导致读取 key 时需要额外的磁盘 I/O。

  • leaf_value_max

  leaf page 上允许的最大 value 值(保存真正的集合数据),默认大小为 leaf page 初始值的 1/2,如果超过这个值,将会额外存储。导致读取 value 时需要额外的磁盘 I/O。

  • split_pct

  内存里面将要被 reconciled 的 page 大小与 internal_page_max 或 leaf_page_max 值的百分比,默认值为 75%,如果内存里面被 reconciled 的 page 能够装进一个单独的磁盘 page 上,则不会发生 spilt,否则按照该百分比值*最大允许的 page 值分割新 page 的大小。

  Page 无锁及压缩


  https://blog.csdn.net/weixin_45583158/article/details/100143033

  参考文章


  • 文章来源在新窗口打开
  • 作者:郭远威
  • MongoDB 中文社区委员,长沙分会主席;《大数据存储 MongoDB 实战指南》作者资深大数据架构师,通信行业业务架构与数据迁移专家
  • 文章来源在新窗口打开
  • 袁荣喜,学霸君工程师,2015 年加入学霸君,负责学霸君的网络实时传输和分布式系统的架构设计和实现,专注于基础技术领域,在网络传输、数据库内核、分布式系统和并发编程方面有一定了解
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖 • 5 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 182 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 675 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 503 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    167 引用 • 597 回帖
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    228 引用 • 476 回帖
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    693 引用 • 537 回帖
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 6 关注
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    42 引用 • 130 回帖 • 252 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 2 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    115 引用 • 318 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    180 引用 • 3878 回帖
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 519 关注
  • 反馈

    Communication channel for makers and users.

    120 引用 • 906 回帖 • 280 关注
  • WebSocket

    WebSocket 是 HTML5 中定义的一种新协议,它实现了浏览器与服务器之间的全双工通信(full-duplex)。

    48 引用 • 206 回帖 • 285 关注
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    954 引用 • 944 回帖
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 820 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    29 引用 • 202 回帖 • 28 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 248 回帖
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 5 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1742 回帖 • 2 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖 • 14 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    142 引用 • 442 回帖
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2040 回帖
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 385 关注