一个案例总结 MongoDB 与 Redis 主从同步问题
一个小 Case 总结 MongoDB 与 Redis 的主从同步问题。
作者:徐文梁,爱可生 DBA 成员,一个执着于技术的数据库工程师,主要负责数据库日常运维工作。擅长 MySQL,Redis 及其他常见数据库也有涉猎;喜欢垂钓,看书,看风景,结交新朋友。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 1500 字,预计阅读需要 5 分钟。
问题背景
现场 MongoDB 版本为 4.4.14,PSS 架构。发现一个从节点的状态不正常,一直处于 STARTUP2 的状态,查看 optime 是 1970,因此无法同步数据也无法提供服务。现场同事将另一台从节点的 data 直接暴力 scp 到了不正常的那台,data 中包含的 oplog 也同步过去了,但同步完重启后,不正常的那台还是在 STARTUP2,optime 也还是 1970。
问题分析
了解现场的情况,直接 scp 从节点的 data 会导致数据不一致,这种情况下同步异常是符合预期的,现场数据量不大(20G 不到),因此可以通过逻辑初始化方式进行主从修复。
让现场同事进行如下操作:先 kill 异常从实例,然后把 data 目录清空,最后重新启动实例。做完这些,告诉现场同事只需要耐心等待就可以了,因为数据量不大,理论上一段时间后即可恢复同步正常,但是结局啪啪打脸了,一段时间后现场同事反馈还是同步失败。
此时只能通过查看日志进行解决了,让现场同事提供对应时间段的 mongo 日志,通过查看日志,发现如下信息:
{"t":{"$date":"2023-08-22T19:01:15.574+08:00"},"s":"I", "c":"INITSYNC", "id":21192, "ctx":"ReplCoordExtern-10","msg":"Initial sync status and statistics","attr":{"status":"failed","statistics":{"failedInitialSyncAttempts":10,"maxFailedInitialSyncAttempts":10,"initialSyncStart":{"$date":"2023-08-22T09:51:56.710Z"},"totalInitialSyncElapsedMillis":4158864,"initialSyncAttempts":[{"durationMillis":418787,"status":"OplogStartMissing: error fetching oplog during initial sync :: caused by :: Our last optime fetched: { ts: Timestamp(1692698292, 26), t: 44 }. source's GTE: { ts: Timestamp(1692698294, 42), t: 44 }","syncSource":"master:27017","rollBackId":8,"operationsRetried":0,"totalTimeUnreachableMillis":0},{"durationMillis":409866,"status":"OplogStartMissing: error fetching oplog during initial sync :: caused by :: Our last optime fetched: { ts: Timestamp(1692698692, 62), t: 44 }. source's GTE: { ts: Timestamp(1692698709, 12), t: 44 }","syncSource":"master:27017","rollBackId":8,"operationsRetried":0,"totalTimeUnreachableMillis":0},{"durationMillis":429278,"status":"OplogStartMissing: error fetching oplog during initial sync :: caused by :: Our last optime fetched: { ts: Timestamp(1692699126, 26), t: 44 }. source's GTE: { ts: Timestamp(1692699137, 18), t: 44 }","syncSource":"master:27017","rollBackId":8,"operationsRetried":0,"totalTimeUnreachableMillis":0},{"durationMillis":427610,"status":"OplogStartMissing: error fetching oplog during initial sync :: caused by :: Our last optime fetched: { ts: Timestamp(1692699549, 44), t: 44 }. source's GTE: { ts: Timestamp(1692699570, 87), t: 44 }",
通过上面信息,可以定位问题。从库从主库读取 oplog 位点时,主库目前的最小位点大于从库所需要读取的位点,因此导致同步失败,一般这种情况有两种可能:
- 全量数据数据量较大,同步时间较长,导致 oplog 之前的位点被覆盖。
- 该段时间内的修改操作较多,导致 oplog 之前的位点被覆盖。
问题处理
无论是上面哪种情况,都可以通过调整 oplog 大小进行解决。让现场同事先临时调大一倍 oplog 的值,然后重新进行同步,一段时间后现场同事反馈主从同步已经恢复。实际生产中 oplog 大小的设置参考
问题思考
问题解决了,但是透过这个小案例,我们是否能收获更多呢?答案是肯定的。
思考如下几个问题:
问题一:除了通过逻辑初始化方式进行主从修复,是否还有其他方式呢?
问题二:MongoDB 使用逻辑初始化方式进行主从修复,与 Redis 的主从修复相比有何异同?
问题一
对于问题一,常见的我们可以选择以下三种方式:
-
通过关闭异常实例,清空数据目录,然后启动 mongo,mongo 会自动进行初始化,从主实例同步数据,即 case 中使用的方式,该种方式操作简单,最安全,推荐。
-
对集群中正常节点进行 LVM 快照,然后复制数据到异常实例,启动异常实例。该方式 也不会阻塞源端读写,操作相对第一种方式稍显复杂。
-
对集群中正常节点执行
db.fsyncLock()
操作加锁后通过 cp 或 scp 等方式将数据目录拷贝到异常实例,然后对正常实例执行db.fsyncUnlock()
操作释放锁,然后启动异常实例。该操作会阻塞源端写操作,不推荐。
问题二
对于 MongoDB 使用逻辑初始化方式和 Redis 进行主从修复时,都是分为 全量数据 + 增量同步 两个阶段。
第一阶段
MongoDB 会克隆除 local 数据库之外的所有数据库。为了进行克隆,mongod 扫描每个源数据库中的各个集合,并将所有数据插入到这些集合各自的副本中。当初始化同步完成后,目标成员会从 STARTUP2 状态转为 SECONDARY 状态。
Redis 从实例会连接主实例,发送 psync
或者 sync
命令(不同版本有差别),主实例收到命令后,会通过执行 bgsave
命令生成 RDB 快照文件。
第二阶段
MongoDB 从节点成员在初始化同步之后会获取在数据复制期间新增的 oplog 记录,oplog 是循环写的,如果过小,可能会被覆盖,从而导致同步失败。oplog 大小可以通过 db.getReplicationInfo()
命令查看。
mgset-919:PRIMARY>db .getReplicationInfo() { "logSizeMB" : 512, "usedMB" : 0.01, "timeDiff" : 228185, "timeDiffHours" : 63.38, "tFirst" :"Thu Jul 27 2023 16:45:11 GMT+0800(CST)", "tLast" :"sun Jul 30 2023 08:08:16 GMT+0800(CST)", "now":"Tue Aug 29 2023 16:44:53 GMT+0800 (CST)" ……
可通过
db.adminCommand({replSetResizeOplog: 1, size: (200* 1024)})
命令在线修改,单位为 MB。
Redis 主实例在 bgsave
执行完成后,会向从实例发送快照文件。在此期间写操作命令会记录在缓冲区内,对应的参数是 client-output-buffer-limit
,表示大小限制是 512M,持续性限制是当客户端缓冲区大小持续 120 秒超过 128M,则关闭 SLAVE 客户端连接。如果设置过小,也会导致同步失败。可以通过 config get client-output-buffer-limit
命令查看。
#redis-cli -h 127.0.0.1 -p xxxx 127.0.0.1:xxxx> config get client-output-buffer-limit 1) "client-output-buffer-limit" 2) "noraml 524288000 0 0 slave 536870912 134217728 120 pubsub 33554432 8388608 60"
可通过
config set client-output-buffer-limit ”slave 1073741824 268435456 120"
在线设置,单位为比特。
PS:Redis 从 2.8 版本开始支持断点续传。该技术依赖增量复制缓冲区,称为 repl_backlog_buffer
,是一个定长的环形数组。如果数组内容写满了,则会从头开始覆盖之前的内容,未被覆盖的情况下,从节点与主节点能够在网络连接断开重连后,只从中断处继续进行复制,而不必重新同步。对应的参数为 repl-backlog-size
,如果网络环境较差,可以适当增大该参数值。
问题总结
通过 case,我们将 MongoDB 和 Redis 主从复制原理、修复方式以及常见问题完整的串联起来了,是不是收获不小呢?
留下一个小问题,client-output-buffer-limit
对应的缓冲区和 repl-backlog-size
对应的缓冲区有啥区别呢?
更多技术文章,请访问:https://opensource.actionsky.com/
关于 SQLE
爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。
SQLE 获取
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器
OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器 @Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。 其中@Provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先节点提供的变量。 说明: 从API version 9开始,这两个装饰器支持在ArkTS卡片中使用。 概述 @Provide/@Consume装饰的状态变量有以下特性: ● @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。 ● 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同...
- 下一篇
被报警大量骚扰?来看看治理方法论
一、监控降噪背景 五月六月以来,蚂蚁开启监控治理主题,推进监控进一步完善,做到既能即时响应告警——五分钟响应三十分钟处理完毕,又能过滤降噪,避免处理疲劳。除了响应公司治理主题之外,小组内部告警的噪音也是一直积累的问题,这是由于随着项目和小组的发展,不可避免的使得配置的监控越来越多,累积的不健康监控增加,导致人均处理告警持续增加。因此,于六月份启动组内监控治理,同时记录治理心得。 二、为什么降噪治理很有必要? 1.避免告警疲劳,提高效率:监控报警在一个小组或项目成立的初期,往往会使人十分紧张,随着其中夹杂噪音增多,处理人员便会逐渐告警疲劳,对监控告警越来越不重视,从而导致对线上告警敬畏减少,真正有效的告警被淹没在了噪声中。同时增加了大量不必要的工作量,疲于应付报警,降低效率。·2.节省资源,同时保持系统稳定:线上监控系统通常会持续地对系统进行监控,如果监控报警太频繁,会占用大量的系统资源,导致系统性能下降,也会影响系统的稳定性。因此,降噪可以节省系统资源,提高系统的性能。 三、告警治理 3.1 如何查看噪音? 利用集团的极光报警数据看板可以非常简单的看到噪音数和故障数等数据,以及五分钟发...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7设置SWAP分区,小内存服务器的救世主
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Hadoop3单机部署,实现最简伪集群
- Mario游戏-低调大师作品
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Red5直播服务器,属于Java语言的直播服务器