一条命令搞垮MongoDB实例

一条命令搞垮MongoDB实例

背景

Part1:写在最前

在副本集架构中,我们会经常通过rs.add(),rs.remove()命令来调整后台数据库架构,在本案例中,我们异常的触发到了一个MongoDB的BUG,并尽快的找到了官方的人进行咨询。在生产环境中,我们做实例迁移,将研发自行维护的MongoDB副本集迁移至DBA管理,由于硬件和版本都不符合规范,因此我们对集群先进行了升级处理,又使用了rs.add()和rs.remove()来完成数据库的迁移工作。

Part2:背景

在研发自行维护的数据库版本为2.6版本,我们先将数据库升级至3.4版本,并利用3.4版本的特性实现0 downtime开启认证。在研发的数据库原有架构中,存在离线节点,即hidden和no-vote节点。也正是因为这一特性,触发了MongoDB宕机。

实战

Part1:整体架构

原有集群为7节点副本集架构,其中2台为hidden节点,并且配置了no-vote参数。

Part2:迁移原理

我们利用新的机器使用rs.add()加入到原有副本集,在原有副本集的基础上添加了新的节点,待同步完成后,rs.remove()掉老的研发机器,完成实例迁移。

Part3:错误日志

在使用rs.remove时,我们提前写好了迁移文档,由于rs.remove()的速度很快,我们采取了直接rs.remove()多个节点的复制粘贴方式,这个也可能是后续导致crash的原因之一。

rs.remove()

2018-04-17T14:54:23.793+0800 I NETWORK  [conn163572] received client metadata from 192.168.1.100:16400 conn163572: { driver: { name: "PyMongo", version: "3.5.1" }, os: { type: "Linux", name: "CentOS 6.4 Final", architecture: "x86_64", version: "2.6.32-279.23.1.mi5.el6.x86_64" }, platform: "CPython 2.7.6.final.0" }
2018-04-17T14:54:23.811+0800 I NETWORK  [thread1] connection accepted from 192.168.1.101:57568 #163573 (73 connections now open)
2018-04-17T14:54:23.811+0800 I NETWORK  [conn163573] received client metadata from 192.168.1.101:57568 conn163573: { driver: { name: "PyMongo", version: "3.5.1" }, os: { type: "Linux", name: "CentOS 6.3 Final", architecture: "x86_64", version: "2.6.32-279.23.1.mi5.el6.x86_64" }, platform: "CPython 2.7.6.final.0" }
2018-04-17T14:54:23.818+0800 I -        [replication-25230] Invariant failure i < _members.size() src/mongo/db/repl/repl_set_config.cpp 620
2018-04-17T14:54:23.818+0800 I -        [replication-25230] 

***aborting after invariant() failure

2018-04-17T14:54:23.822+0800 I NETWORK  [thread1] connection accepted from 192.168.1.102:32210 #163574 (74 connections now open)
2018-04-17T14:54:23.822+0800 I NETWORK  [conn163574] received client metadata from 192.168.1.102:32210 conn163574: { driver: { name: "PyMongo", version: "3.5.1" }, os: { type: "Linux", name: "CentOS 6.3 Final", architecture: "x86_64", version: "2.6.32-279.23.1.mi5.el6.x86_64" }, platform: "CPython 2.7.6.final.0" }
2018-04-17T14:54:23.822+0800 I NETWORK  [thread1] connection accepted from 192.168.1.101:57569 #163575 (75 connections now open)
2018-04-17T14:54:23.823+0800 I NETWORK  [thread1] connection accepted from 192.168.1.103:50661 #163576 (76 connections now open)
2018-04-17T14:54:23.824+0800 I NETWORK  [conn163576] received client metadata from 192.168.1.103:50661 conn163576: { driver: { name: "PyMongo", version: "3.5.1" }, os: { type: "Linux", name: "CentOS 6.3 Final", architecture: "x86_64", version: "2.6.32-279.23.1.mi5.el6.x86_64" }, platform: "CPython 2.7.6.final.0" }
2018-04-17T14:54:23.830+0800 I NETWORK  [thread1] connection accepted from 192.168.1.101:57570 #163577 (77 connections now open)
2018-04-17T14:54:23.830+0800 I NETWORK  [conn163577] received client metadata from 192.168.1.101:57570 conn163577: { driver: { name: "PyMongo", version: "3.5.1" }, os: { type: "Linux", name: "CentOS 6.3 Final", architecture: "x86_64", version: "2.6.32-279.23.1.mi5.el6.x86_64" }, platform: "CPython 2.7.6.final.0" }
2018-04-17T14:54:23.832+0800 I NETWORK  [thread1] connection accepted from 192.168.1.104:41163 #163578 (78 connections now open)
2018-04-17T14:54:23.838+0800 F -        [replication-25230] Got signal: 6 (Aborted).

 0x7ffc3f0a41d1 0x7ffc3f0a3159 0x7ffc3f0a363d 0x7ffc3c0bf500 0x7ffc3bd4f8a5 0x7ffc3bd51085 0x7ffc3e2d7a8e 0x7ffc3ea5883c 0x7ffc3ea58999 0x7ffc3eb19b9d 0x7ffc3eaa2676 0x7ffc3e9c83e9 0x7ffc3e9b0032 0x7ffc3ea41bf7 0x7ffc3e3812f1 0x7ffc3ee25a5a 0x7ffc3ee28e53 0x7ffc3ee2932b 0x7ffc3f0185bc 0x7ffc3f01906c 0x7ffc3f019a56 0x7ffc3fdc7a00 0x7ffc3c0b7851 0x7ffc3be0511d
----- BEGIN BACKTRACE -----
{"backtrace":[{"b":"7FFC3DA22000","o":"16821D1","s":"_ZN5mongo15printStackTraceERSo"},{"b":"7FFC3DA22000","o":"1681159"},{"b":"7FFC3DA22000","o":"168163D"},{"b":"7FFC3C0B0000","o":"F500"},{"b":"7FFC3BD1D000","o":"328A5","s":"gsignal"},{"b":"7FFC3BD1D000","o":"34085","s":"abort"},{"b":"7FFC3DA22000","o":"8B5A8E","s":"_ZN5mongo17invariantOKFailedEPKcRKNS_6StatusES1_j"},{"b":"7FFC3DA22000","o":"103683C"},{"b":"7FFC3DA22000","o":"1036999"},{"b":"7FFC3DA22000","o":"10F7B9D","s":"_ZNK5mongo4repl23TopologyCoordinatorImpl22shouldChangeSyncSourceERKNS_11HostAndPortERKNS0_6OpTimeERKNS_3rpc15ReplSetMetadataEN5boost8optionalINS8_18OplogQueryMetadataEEENS_6Date_tE"},{"b":"7FFC3DA22000","o":"1080676","s":"_ZN5mongo4repl26ReplicationCoordinatorImpl22shouldChangeSyncSourceERKNS_11HostAndPortERKNS_3rpc15ReplSetMetadataEN5boost8optionalINS5_18OplogQueryMetadataEEE"},{"b":"7FFC3DA22000","o":"FA63E9","s":"_ZN5mongo4repl31DataReplicatorExternalStateImpl18shouldStopFetchingERKNS_11HostAndPortERKNS_3rpc15ReplSetMetadataEN5boost8optionalINS5_18OplogQueryMetadataEEE"},{"b":"7FFC3DA22000","o":"F8E032"},{"b":"7FFC3DA22000","o":"101FBF7","s":"_ZN5mongo4repl12OplogFetcher9_callbackERKNS_10StatusWithINS_7Fetcher13QueryResponseEEEPNS_14BSONObjBuilderE"},{"b":"7FFC3DA22000","o":"95F2F1","s":"_ZN5mongo7Fetcher9_callbackERKNS_8executor12TaskExecutor25RemoteCommandCallbackArgsEPKc"},{"b":"7FFC3DA22000","o":"1403A5A"},{"b":"7FFC3DA22000","o":"1406E53","s":"_ZN5mongo8executor22ThreadPoolTaskExecutor11runCallbackESt10shared_ptrINS1_13CallbackStateEE"},{"b":"7FFC3DA22000","o":"140732B"},{"b":"7FFC3DA22000","o":"15F65BC","s":"_ZN5mongo10ThreadPool10_doOneTaskEPSt11unique_lockISt5mutexE"},{"b":"7FFC3DA22000","o":"15F706C","s":"_ZN5mongo10ThreadPool13_consumeTasksEv"},{"b":"7FFC3DA22000","o":"15F7A56","s":"_ZN5mongo10ThreadPool17_workerThreadBodyEPS0_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},{"b":"7FFC3DA22000","o":"23A5A00"},{"b":"7FFC3C0B0000","o":"7851"},{"b":"7FFC3BD1D000","o":"E811D","s":"clone"}],"processInfo":{ "mongodbVersion" : "3.4.9-2.9", "gitVersion" : "dcdd0758e067949b27cfdf61c641905e619756e6", "compiledModules" : [], "uname" : { "sysname" : "Linux", "release" : "2.6.32-279.23.1.mi5.el6.x86_64", "version" : "#1 SMP Mon Sep 2 12:00:41 CST 2013", "machine" : "x86_64" }, "somap" : [ { "b" : "7FFC3DA22000", "elfType" : 3, "buildId" : "BE2829B1404DE963963BBCCA55C6EBBFE34CE20F" }, { "b" : "7FFFA8CFF000", "elfType" : 3, "buildId" : "A6539A72BE0493D91090D15510B7866310CBEA50" }, { "b" : "7FC5C55EA000", "path" : "/lib64/libz.so.1", "elfType" : 3, "buildId" : "D0ABBCCAC542E41D33A638138FEC450AC08A1CF2" }, { "b" : "7FC5C37D9000", "path" : "/lib64/libbz2.so.1", "elfType" : 3, "buildId" : "732F8FD5054C4FA43CF0CD4CC8C5FF02CEA3CC54" }, { "b" : "7FC5BCDBF000", "path" : "/usr/lib64/libsasl2.so.2", "elfType" : 3, "buildId" : "C447C77E41A336BA9AEE12D08FBF5D15948D7468" }, { "b" : "7FC5BFF53000", "path" : "/usr/lib64/libssl.so.10", "elfType" : 3, "buildId" : "318EAB33420B000D542F09B91B716BACAB1AD546" }, { "b" : "7FC5C2773000", "path" : "/usr/lib64/libcrypto.so.10", "elfType" : 3, "buildId" : "3A8D65B9A373C0AFAF106F3A979835B16DBEFF1A" }, { "b" : "7FC5C416B000", "path" : "/lib64/librt.so.1", "elfType" : 3, "buildId" : "5E9DDD9EE40AD0D4DDD032CE1086E402B7FA955A" }, { "b" : "7FC5C5367000", "path" : "/lib64/libdl.so.2", "elfType" : 3, "buildId" : "15B0822C819020F18BBF0E0C0286373155E03BE2" }, { "b" : "7FC5C40E3000", "path" : "/lib64/libm.so.6", "elfType" : 3, "buildId" : "A26BC945B5765B1258DB01FFEFB0C4F53F3961D7" }, { "b" : "7FC5C1ACD000", "path" : "/lib64/libgcc_s.so.1", "elfType" : 3, "buildId" : "CE152B8676517F23E7F54AD6408330979BE41443" }, { "b" : "7FC5C44B0000", "path" : "/lib64/libpthread.so.0", "elfType" : 3, "buildId" : "14853815DD64F2B830B8DCCB3A958A3804E13EFC" }, { "b" : "7FC5C451D000", "path" : "/lib64/libc.so.6", "elfType" : 3, "buildId" : "F2BBDD778ABFECFBA0C59BBCBA94D1151DDF96E4" }, { "b" : "7FC5C6800000", "path" : "/lib64/ld-linux-x86-64.so.2", "elfType" : 3, "buildId" : "D6BD776B36DAC438642CF84B282956738727901D" }, { "b" : "7FC5C2703000", "path" : "/lib64/libresolv.so.2", "elfType" : 3, "buildId" : "31545FEA4F1F72061992E79A1DF461EC719942E8" }, { "b" : "7FC5C04CC000", "path" : "/lib64/libcrypt.so.1", "elfType" : 3, "buildId" : "5F5EB7F30B61E0DAF6BBF8A367C388A54B7010EA" }, { "b" : "7FC5BEA88000", "path" : "/lib64/libgssapi_krb5.so.2", "elfType" : 3, "buildId" : "76A3DEEB6876CBED69A57D3EBC1E2AFBCA84EC76" }, { "b" : "7FC5BEBA2000", "path" : "/lib64/libkrb5.so.3", "elfType" : 3, "buildId" : "605701A8AE551604303523B4F0D3A7E98CF9E153" }, { "b" : "7FC5C059E000", "path" : "/lib64/libcom_err.so.2", "elfType" : 3, "buildId" : "4623A78918C882770E81AE7B5EE9DDF8DD2B6674" }, { "b" : "7FC5BEB72000", "path" : "/lib64/libk5crypto.so.3", "elfType" : 3, "buildId" : "190D45F6743DEF9DF8169D65801D4575B01825BD" }, { "b" : "7FC5BF510000", "path" : "/lib64/libfreebl3.so", "elfType" : 3, "buildId" : "68195872ECFB188389D29AAF01031A976FD18168" }, { "b" : "7FC5BEB05000", "path" : "/lib64/libkrb5support.so.0", "elfType" : 3, "buildId" : "DAE2A7E4E8B37D43EF6839FF5D8E012AFCF21A69" }, { "b" : "7FC5BF902000", "path" : "/lib64/libkeyutils.so.1", "elfType" : 3, "buildId" : "8A8734DC37305D8CC2EF8F8C3E5EA03171DB07EC" }, { "b" : "7FC5C16E3000", "path" : "/lib64/libselinux.so.1", "elfType" : 3, "buildId" : "A287DC6B86A9823038F057105CE64671E0B392EC" } ] }}
 mongod(_ZN5mongo15printStackTraceERSo+0x41) [0x7ffc3f0a41d1]
 mongod(+0x1681159) [0x7ffc3f0a3159]
 mongod(+0x168163D) [0x7ffc3f0a363d]
 libpthread.so.0(+0xF500) [0x7ffc3c0bf500]
 libc.so.6(gsignal+0x35) [0x7ffc3bd4f8a5]
 libc.so.6(abort+0x175) [0x7ffc3bd51085]
 mongod(_ZN5mongo17invariantOKFailedEPKcRKNS_6StatusES1_j+0x0) [0x7ffc3e2d7a8e]
 mongod(+0x103683C) [0x7ffc3ea5883c]
 mongod(+0x1036999) [0x7ffc3ea58999]
 mongod(_ZNK5mongo4repl23TopologyCoordinatorImpl22shouldChangeSyncSourceERKNS_11HostAndPortERKNS0_6OpTimeERKNS_3rpc15ReplSetMetadataEN5boost8optionalINS8_18OplogQueryMetadataEEENS_6Date_tE+0x32D) [0x7ffc3eb19b9d]
 mongod(_ZN5mongo4repl26ReplicationCoordinatorImpl22shouldChangeSyncSourceERKNS_11HostAndPortERKNS_3rpc15ReplSetMetadataEN5boost8optionalINS5_18OplogQueryMetadataEEE+0xB6) [0x7ffc3eaa2676]
 mongod(_ZN5mongo4repl31DataReplicatorExternalStateImpl18shouldStopFetchingERKNS_11HostAndPortERKNS_3rpc15ReplSetMetadataEN5boost8optionalINS5_18OplogQueryMetadataEEE+0x59) [0x7ffc3e9c83e9]
 mongod(+0xF8E032) [0x7ffc3e9b0032]
 mongod(_ZN5mongo4repl12OplogFetcher9_callbackERKNS_10StatusWithINS_7Fetcher13QueryResponseEEEPNS_14BSONObjBuilderE+0x1E57) [0x7ffc3ea41bf7]
 mongod(_ZN5mongo7Fetcher9_callbackERKNS_8executor12TaskExecutor25RemoteCommandCallbackArgsEPKc+0x621) [0x7ffc3e3812f1]
 mongod(+0x1403A5A) [0x7ffc3ee25a5a]
 mongod(_ZN5mongo8executor22ThreadPoolTaskExecutor11runCallbackESt10shared_ptrINS1_13CallbackStateEE+0x1B3) [0x7ffc3ee28e53]
 mongod(+0x140732B) [0x7ffc3ee2932b]
 mongod(_ZN5mongo10ThreadPool10_doOneTaskEPSt11unique_lockISt5mutexE+0x14C) [0x7ffc3f0185bc]
 mongod(_ZN5mongo10ThreadPool13_consumeTasksEv+0xBC) [0x7ffc3f01906c]
 mongod(_ZN5mongo10ThreadPool17_workerThreadBodyEPS0_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x96) [0x7ffc3f019a56]
 mongod(+0x23A5A00) [0x7ffc3fdc7a00]
 libpthread.so.0(+0x7851) [0x7ffc3c0b7851]
 libc.so.6(clone+0x6D) [0x7ffc3be0511d]
-----  END BACKTRACE  -----

Part4:问题分析

我们可以看到,在错误日志中存在如下内容:

Invariant failure i < _members.size() src/mongo/db/repl/repl_set_config.cpp 620

我们可以看到,在错误日志中存在如下内容:

Invariant failure i < _members.size() src/mongo/db/repl/repl_set_config.cpp 620

通过追寻源码,我们定位到该处逻辑:

透过invariant关键字,我们向上追寻,可以找到如下内容:

看完代码逻辑,我们认为报错的原因是由于批量rs.remove()引起,由于批量rs.remove(),代码逻辑中可以看出有一个判断:

const MemberConfig& ReplSetConfig::getMemberAt(size_t i) const

{ invariant(i < _members.size()); return _members[i]; }

例如,一个5节点的副本集,那么他的_id索引值为0,1,2,3,4。此时_members.size是5。 4 must <5逻辑是正确的。

但当我们使用rs.remove()命令删除超过1个节点成员时,例如同时删除_id=3和_id=4的,那么此时副本集就只有3个成员,_members.size变为3

但是i值却依旧因为某些原因停留在4,4<3这个逻辑不对,导致了被删除节点abort退出crash。当然这个推论目前我们没有确切的证据。

Part5:Mongo官方人员答复

同时,我们搜索到了相关的mongoDB jira,留言了我们的疑问,官方的jira中也是其他网友遇到的问题。他们的情况比我们的要更明显一些,是由于no-vote节点rs.remove导致的

笔者案例中也确实存在no-vote节点。目前官方给出的答复计划在4.1版本中进行修复。

官方jira连接

https://jira.mongodb.org/browse/SERVER-28079

Part6:规避方法

1.     将非投票节点升级为投票节点;

2.     请提前做好备份,以备不时之需。

——总结——

通过本文,我们了解到rs.remove()潜在可能导致mongoDB crash的场景,由于时间有限,且crash掉的机器本就是我们计划rs.remove()掉的节点,因此在笔者复现无果后,决定暂时放弃继续跟进这个issue。如果有网友遇到过类似的问题,且找到了根本原因和复现方式,可在博文下留言,笔者感激不尽!~由于笔者的水平有限,编写时间也很仓促,文中难免会出现一些错误或者不准确的地方,不妥之处恳请读者批评指正。喜欢笔者的文章,右上角点一波关注,谢谢~

原文地址:http://blog.51cto.com/suifu/2113394

时间: 2024-10-08 03:47:14

一条命令搞垮MongoDB实例的相关文章

Dockerfile命令介绍及实例

Dockerfile命令介绍及实例 当你在使用 Docker构建镜像的时候,每一个命令都会在前一个命令的基础上形成一个新层.这些基础镜像可以用于创建新的容器.本篇文章将手把手教您如何从基础镜像,一步一步,一层一层的从Dockerfile构建容器的过程. 基础镜像可以用于创建Docker容器.镜像可以非常基础,仅仅包含操作系统:也可以非常丰富,包含灵巧的应用栈,随时可 以发布.当你在使用 Docker构建镜像的时候,每一个命令都会在前一个命令的基础上形成一个新层.这些基础镜像可以用于创建新的容器.

linux之50条命令详解

1. tar tar命令文件压缩与解压 tar命令可以为linux的文件和目录创建档案.利用tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件.tar最初被用来在磁带上创建档案,现在,用户可以在任何设备上创建档案.利用tar命令,可以把一大堆的文件和目录全部打包成一个文件,这对于备份文件或将几个文件组合成为一个文件以便于网络传输是非常有用的. 首先要弄清两个概念:打包和压缩.打包是指将一大堆文件或目录变成一个总的文件:压缩则是将一个大的文件通过一些压

设计模式(12)----- 命令设计模式(升级----一个开关控制多条命令)

我们先来看张类图 RemoteControl类修改一下 public class RemoteControl {     Command[] onCommands; Command[] offCommands; public RemoteControl() { onCommands = new Command[7];          offCommands = new Command[7]; Command noCommand = new NoCommand(); for (int i = 0

嗖的一下!只要一条命令,K8s监控数据一键写入时序数据库

这里的“快速”有多快呢?一条命令就能搞定!本文就介绍如何使用helm一键完成k8s监控数据到阿里云InfluxDB®的存储链路. 关于helm 对于helm的安装和使用,网上有很多资料,这里不赘述.有一点需要注意,虽然近期helm 3已经发布,但短期内不是所有的helm chart都兼容helm 3,比如社区的这个issue. 本文依然使用helm 2来安装. 准备 这里假设用户已经在阿里云购买了InfluxDB®实例,并且创建了账号以及数据库,具体流程请参考官方文档.假设使用的数据库为k8s,

shell练习(2)--awk统计ip访问量(一条命令)

对下面的1.log 文件进行统计, 要求: 统计出每个IP的访问量有多少? 提示,先awk过滤出ip,然后进行排序,统计重复数. 只用一条命令即可 awk '{STAT[$1]++};END{for(A in STAT) print STAT[A], A}' 1.log|sort -nr|head -10 1.log   的大致格式: 112.111.12.248 - [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com "/seccode.php?u

【重点】初窥Linux 之 我最常用的20多条命令

玩过Linux的人都会知道,Linux中的命令的确是非常多,但是玩过Linux的人也从来不会因为Linux的命令如此之多而烦恼,因为我们只需要掌握我们最常用的命令就可以了.当然你也可以在使用时去找一下man,他会帮你解决不少的问题.然而每个人玩Linux的目的都不同,所以他们常用的命令也就差异非常大,而我主要是用Linux进行C/C++和shell程序编写的,所以常用到的命令可以就会跟一个管理Linux系统的人有所不同.因为不想在使用是总是东查西找,所以在此总结一下,方便一下以后的查看.不多说,

Ubuntu常用200条命令

   查看软件xxx安装内容:dpkg -L xxx 查找软件库中的软件:apt-cache search 正则表达式 查找软件库中的软件:aptitude search 软件包 查找文件属于哪个包:dpkg -S filename 查找文件属于哪个包:apt-file search filename 查询软件xxx依赖哪些包:apt-cache depends xxx 查询软件xxx被哪些包依赖:apt-cache rdepends xxx 增加一个光盘源:sudo apt-cdrom add

Linux 最常用的20条命令

1.cd命令 这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如: [plain] view plain copy print? cd /root/Docements # 切换到目录/root/Docements cd ./path          # 切换到当前目录下的path目录中,"."表示当前目录 cd ../path         # 切换到上层目录中的path目录中,"..&q

NETSH WINSOCK RESET这条命令的含义和作用?

简单来说netsh winsock reset命令含义是重置 Winsock 文件夹.假设一台机器上的Winsock协议配置有问题的话将会导致网络连接等问题,就须要用netsh winsock reset命令来重置Winsock文件夹借以恢复网络. winsock是windows网络编程接口,从Windows XP SP2開始内置了一条命令使用netsh可以对该接口进行修复. netsh是一个可以通过命令行操作差点儿全部网络相关设置的接口.比方设置IP,DNS,网卡,无线网络等.netsh wi