MongoDB 定位 oplog 必须全表扫描吗?

MongoDB oplog (类似于 MySQL binlog) 记录数据库的所有修改操作,除了用于主备同步;oplog 还能玩出很多花样,比如

  1. 全量备份 + 增量备份所有的 oplog,就能实现 MongoDB 恢复到任意时间点的功能
  2. 通过 oplog,除了实现到备节点的同步,也可以额外再往单独的集群同步数据(甚至是异构的数据库),实现容灾、多活等场景,比如阿里云开源的 MongoShake 就能实现基于 oplog 的增量同步。
  3. MongoDB 3.6+ 版本对 oplog 进行了抽象,提供了 Change Stream 的接口,实际上就是能不断订阅数据库的修改,基于这些修改可以触发一些自定义的事件。
  4. ......

总的来说,MongoDB 可以通过 oplog 来跟生态对接,来实现数据的同步、迁移、恢复等能力。而在构建这些能力的时候,有一个通用的需求,就是工具或者应用需要有不断拉取 oplog 的能力;这个过程通常是

  1. 根据上次拉取的位点构建一个 cursor
  2. 不断迭代 cursor 获取新的 oplog

那么问题来了,由于 MongoDB oplog 本身没有索引的,每次定位 oplog 的起点都需要进行全表扫描么?

oplog 的实现细节

{ "ts" : Timestamp(1563950955, 2), "t" : NumberLong(1), "h" : NumberLong("-5936505825938726695"), "v" : 2, "op" : "i", "ns" : "test.coll", "ui" : UUID("020b51b7-15c2-4525-9c35-cd50f4db100d"), "wall" : ISODate("2019-07-24T06:49:15.903Z"), "o" : { "_id" : ObjectId("5d37ff6b204906ac17e28740"), "x" : 0 } }
{ "ts" : Timestamp(1563950955, 3), "t" : NumberLong(1), "h" : NumberLong("-1206874032147642463"), "v" : 2, "op" : "i", "ns" : "test.coll", "ui" : UUID("020b51b7-15c2-4525-9c35-cd50f4db100d"), "wall" : ISODate("2019-07-24T06:49:15.903Z"), "o" : { "_id" : ObjectId("5d37ff6b204906ac17e28741"), "x" : 1 } }
{ "ts" : Timestamp(1563950955, 4), "t" : NumberLong(1), "h" : NumberLong("1059466947856398068"), "v" : 2, "op" : "i", "ns" : "test.coll", "ui" : UUID("020b51b7-15c2-4525-9c35-cd50f4db100d"), "wall" : ISODate("2019-07-24T06:49:15.913Z"), "o" : { "_id" : ObjectId("5d37ff6b204906ac17e28742"), "x" : 2 } }

上面是 MongoDB oplog 的示例,oplog MongoDB 也是一个集合,但与普通集合不一样

  1. oplog 是一个 capped collection,但超过配置大小后,就会删除最老插入的数据
  2. oplog 集合没有 id 字段,ts 可以作为 oplog 的唯一标识; oplog 集合的数据本身是按 ts 顺序组织的
  3. oplog 没有任何索引字段,通常要找到某条 oplog 要走全表扫描

我们在拉取 oplog 时,第一次从头开始拉取,然后每次拉取使用完,会记录最后一条 oplog 的ts字段;如果应用发生重启,这时需要根据上次拉取的 ts 字段,先找到拉取的起点,然后继续遍历。

oplogHack 优化

注:以下实现针对 WiredTiger 存储引擎,需要 MongoDB 3.0+ 版本才能支持

如果 MongoDB 底层使用的是 WiredTiger 存储引擎,在存储 oplog 时,实际上做过优化。MongoDB 会将 ts 字段作为 key,oplog 的内容作为 value,将key-value 存储到 WiredTiger 引擎里,WiredTiger 默认配置使用 btree 存储,所以 oplog 的数据在 WT 里实际上也是按 ts 字段顺序存储的,既然是顺序存储,那就有二分查找优化的空间。

MongoDB find 命令提供了一个选项,专门用于优化 oplog 定位。

大致意思是,如果你find的集合是oplog,查找条件是针对 ts 字段的 gtegteq ,那么 MongoDB 字段会进行优化,通过二分查找快速定位到起点; 备节点同步拉取oplog时,实际上就带了这个选项,这样备节点每次重启,都能根据上次同步的位点,快速找到同步起点,然后持续保持同步。

oplogHack 实现

由于咨询问题的同学对内部实现感兴趣,这里简单的把重点列出来,要深刻理解,还是得深入撸细节。

// src/monogo/db/query/get_executor.cpp
StatusWith<unique_ptr<PlanExecutor>> getExecutorFind(OperationContext* txn,Collection* collection,const NamespaceString& nss,unique_ptr<CanonicalQuery> canonicalQuery,PlanExecutor::YieldPolicy yieldPolicy) {// 构建 find 执行计划时,如果发现有 oplogReplay 选项,则走优化路径if (NULL != collection && canonicalQuery->getQueryRequest().isOplogReplay()) {return getOplogStartHack(txn, collection, std::move(canonicalQuery));}...return getExecutor(txn, collection, std::move(canonicalQuery), PlanExecutor::YIELD_AUTO, options);
}
 StatusWith<unique_ptr<PlanExecutor>> getOplogStartHack(OperationContext* txn,Collection* collection,unique_ptr<CanonicalQuery> cq) {// See if the RecordStore supports the oplogStartHack// 如果底层引擎支持(WT支持,mmapv1不支持),根据查询的ts,找到 startLocconst BSONElement tsElem = extractOplogTsOptime(tsExpr);if (tsElem.type() == bsonTimestamp) {StatusWith<RecordId> goal = oploghack::keyForOptime(tsElem.timestamp());if (goal.isOK()) {// 最终调用 src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp::oplogStartHackstartLoc = collection->getRecordStore()->oplogStartHack(txn, goal.getValue());}}// Build our collection scan...// 构建全表扫描参数时,带上 startLoc,真正执行是会快速定位到这个点CollectionScanParams params;params.collection = collection;params.start = *startLoc;params.direction = CollectionScanParams::FORWARD;params.tailable = cq->getQueryRequest().isTailable();
}


原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/518289.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript-方法

方法的定义 方法就是把函数放在对象里面 var wang {name: 网络,birth: 2020,// 方法age: function () {// 今年 - 出生的年var now_year new Date().getFullYear();return now_year-this.birth} } // 属性 wang.name // 方法&#xff0c;一定要带() kuangshen.age()拆开上面…

Python程序员30行代码素描表白!网友:花里胡哨

总有人说程序员不够浪漫&#xff01;其实我们只是没时间而已&#xff0c;等我们有时间了&#xff0c;还有普通人什么事儿&#xff1f;最近就有一个小伙伴上热搜了&#xff01;原来他用Python给可爱的女朋友画了一幅素描&#xff01;不到30行代码&#xff0c;一起来学学给她一个…

解读NoSQL最新现状和趋势:云NoSQL数据库将成重要增长引擎

NoSQL最早起源于1998年&#xff0c;但从2009年开始&#xff0c;NoSQL真正开始逐渐兴起和发展。回望历史应该说NoSQL数据库的兴起&#xff0c;完全是十年来伴随互联网技术&#xff0c;大数据数据的兴起和发展&#xff0c;NoSQL在面临大数据场景下相对于关系型数据库运用&#xf…

使用EMR-Kafka Connect进行数据迁移

1.背景 流式处理中经常会遇到Kafka与其他系统进行数据同步或者Kafka集群间数据迁移的情景。使用EMR Kafka Connect可以方便快速的实现数据同步或者数据迁移。 Kafka Connect是一种可扩展的、可靠的&#xff0c;用于在Kafka和其他系统之间快速地进行流式数据传输的工具。例如可…

亚信安全发布“安全定义边界”2020发展理念 赋能企业在5G时代的数字化安全运营能力

2020年4月21日&#xff0c;以“信行合一 聚势致远”为主题的亚信安全2020合作伙伴大会正式在云端拉开帷幕&#xff0c;超过1500家生态伙伴相聚云端&#xff0c;在为期3天的大会上共话安全&#xff0c;共商发展。会上&#xff0c;亚信安全正式发布“安全定义边界”2020发展理念&…

JavaScript-Date日期对象

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <script>const now new Date(); // Tue Aug 10 2021 15:32:27 GMT0800 (中国标准时间)now.g…

如何实现input输入框自带清除按钮

最近&#xff0c;项目中需要&#xff0c;在输入框获取焦点是动态显示“”图标。即在输入框中输入内容时&#xff0c;右边显示“”按钮&#xff1b;输入框为空时&#xff0c;“”按钮消失。难点在于获取焦点的同时&#xff0c;获取输入内容。 注意&#xff1a;本例子的样式基于…

python-解码 decode 报错的问题

当解码使用默认的 decode() 拨错时&#xff0c;可以设置 errors 参数的值来解决 print(line) line_de_replace line.decode(errorsreplace).strip() # 用&#xff1f;代替 print("line_de_replace:", line_de_replace) line_de_ignore line.decode(errorsignore)…

字节码技术在模块依赖分析中的应用

背景 近年来&#xff0c;随着手机业务的快速发展&#xff0c;为满足手机端用户诉求和业务功能的迅速增长&#xff0c;移动端的技术架构也从单一的大工程应用&#xff0c;逐步向模块化、组件化方向发展。以高德地图为例&#xff0c;Android 端的代码已突破百万行级别&#xff0…

华为发布基于自进化AI的HiSec Insight安全态势感知系统

2020年4月21日&#xff0c;华为举办“安全新视界&#xff0c;AI知未然”主题线上发布会&#xff0c;邀请第三方研究机构、行业客户和合作伙伴共同探讨安全态势感知系统的演进方向&#xff0c;并见证华为HiSec Insight安全态势感知系统的全新面世。华为HiSec Insight安全态势感知…

“做好大数据测试,我是认真的!”

阿里妹导读&#xff1a;大数据已然是当下的重要课题&#xff0c;大大小小的企业在重视大数据的同时&#xff0c;也渐渐重视大数据质量的问题。阿里巴巴测试开发专家小郅&#xff0c;今天会分享他对数据测试的系统性思考。文章内容架构清晰&#xff0c;内容较长&#xff0c;建议…

从安全到镜像流水线,Docker 最佳实践与反模式一览

作者 | Timothy Mugayi译者 | 弯月&#xff0c;责编 | 夕颜封图 | CSDN付费下载自视觉中国出品 | CSDN&#xff08;ID:CSDNnews&#xff09;在使用Docker的大部分时间里&#xff0c;我们并不关心其内部的工作原理。仅凭启动一个Docker容器并且让应用程序运行良好&#xff0c;并…

ChaosBlade 发布对 C++ 应用混沌实验的支持

前言 为满足 C 应用系统故障演练&#xff0c;阿里妈妈安全生产团队开源了 C 混沌实验执行器&#xff0c;填补了 C 应用混沌工程实验的空白&#xff0c;其遵循《混沌实验模型》&#xff0c;可通过 ChaosBlade 工具直接执行。项目详情点击这里&#xff01; 。 本文重点介绍该执…

TortoiseGitPlink提示输入密码解决方法

文章目录一、现象二 、解决方法2.1. 打开TortoiseGit 下的puttygen工具2.2. 点击load&#xff0c;加载私钥2.3. 生成一个新的私钥2.4. 项目拉取2.5. 配置新的私钥一、现象 二 、解决方法 2.1. 打开TortoiseGit 下的puttygen工具 双击D:\software\TortoiseGit\bin下面的puttyg…

引领高并发直播场景进入毫秒时代,阿里云发布超低延时直播服务

近日&#xff0c;阿里云上线超低延时直播服务RTS&#xff08;Real-time Streaming&#xff09;&#xff0c;该服务在视频直播产品的基础上&#xff0c;进行全链路延时监控、传输协议改造等底层技术优化&#xff0c;支持千万级并发场景下的毫秒级延迟直播能力&#xff0c;保障低…

JavaScript-面向对象 class 继承

class继承 class 关键字是在ES6引入的 ES6之前的写法&#xff1a; function Student(name) {this.name name } // 给Student新增一个方法 Student.prototype.hello function () {alert(Hello) }ES6的写法&#xff1a; // 定义一个 学生的 类 class Student1{constructor(…

我26岁,月薪一万,刚实现“黄焖鸡自由”(苦笑)

今天是CSDN微信公众号千万粉丝达成的日子&#xff0c;因此&#xff0c;“千万粉丝狂欢节”来了&#xff01;第一弹超值福利来袭&#xff0c;前方高能&#xff1a;「粉丝节限定版一卡通」重磅上线&#xff01;可看该大牛老师全部课程&#xff01;课程涵盖热门的Java、Python和AI…

Android侧滑原来可以这么优雅

前言 侧滑手势在Android App应用得非常广泛&#xff0c;常见的使用场景包括&#xff1a;滑动抽屉、侧滑删除、侧滑返回、下拉刷新以及侧滑封面等。由于这些使用场景实在是太通用了&#xff0c;各路大神们八仙过海各显神通&#xff0c;每种侧滑场景都开源出了很多非常实用的框架…

TortoiseGit状态图标不能正常显示的解决办法

文章目录一. 运行环境一、方案11.1. 右键点击桌面空白处&#xff0c;打开TortoiseGit的Settings1.2. 修改Icon Overlays的Status cache1.3. 重启电脑&#xff0c;你就会发现你的小乌龟箭头出来了。二、方案2一. 运行环境 版本说明Windows 10 64bit操作系统TortoiseGit-2.12.0.…

平头哥广发英雄帖,公开首款CPU“玄铁”仿真代码

“在自研芯片的路上&#xff0c;阿里走出了万里长征的第一步。” 7月25日&#xff0c;阿里云峰会上海站&#xff0c;压轴出场的平头哥&#xff0c;交出了时隔10月的首份答卷&#xff1a;玄铁910&#xff08;XuanTie910&#xff09;&#xff0c;目前业界性能最强的RISC-V处理器…