欢迎大家关注我的 WX 公众号【小生末学】,相关技术文章会优先在公众号上发布~
原文地址在我的博客:https://blog.chenxiaosheng.com/posts/2022-06-11/mongodb-flowcontrol-practice.html
MongoDB 4.2 引入了一个「流量控制」的新特性。该流控机制旨在保持副本集多数提交延迟小于或等于配置的最大值。此最大延迟的默认值为 10 秒。一旦多数提交的复制延迟达到配置的最大值的阈值百分比,流控制机制就会开始限制主节点上的写入。
当该特性开启时,MongoDB 会在给定的周期内(目前实现是 1 秒),分配一定数量的「流控票据」,MongoDB 的数据库库写操作需要通过获取「流控票据」来获取全局 IX 锁。当此给定周期内的票据分发完比后,相关操作需要等待下一个周期(下一秒)的票据刷新分发。部份 MongoDB 内部操作可能会忽略该流控机制,以确保 MongoDB 的正常运行。
接下来我们从算法、配置、源码等几个方面结合来了解一下该流控制机制的实现(本文以 MongoDB 4.2.20 版本的文档及源码为参考)。
环境要求
- 因为是 4.2 才引入的,所以要求 MongoDB 版本大于等于 4.2.0,并且 featureCompatibility 也要匹配相应的版本;
- 流控机制只在可以接受写入的节点生效(通过指 replica sets 中的 primary 节点);
- 当然,流控开关也是要打开的,默认打开。可以通过 enableFlowControl 进行开关;
- Read Concern Majority 必须启用,可以参考 replication.enableMajorityReadConcern 启用;
当以上机制不满足时(亦可理解为流控机制关闭时),MongoDB 总是返回默认的最大数量 _kMaxTickets = 1000 * 1000 * 1000
。
流控机制
流控制机制允许每秒获取指定数量的全局 IX 锁。除明确规避流控机制的操作外,全局 IX 锁获取必须首先获取「流控票据」然后才能获取锁。当此给定周期内的票据分发完比后,相关操作需要等待下一个周期(下一秒)的票据刷新分发。MongoDB 通过一个独立的机制每秒刷新一次票数。
// src/mongo/db/storage/flow_control.cpp
FlowControl::FlowControl(ServiceContext* service, repl::ReplicationCoordinator* replCoord)
...
_jobAnchor = service->getPeriodicRunner()