MongoDB添加secondary节点的两种方法
前段时间维护的一个事业群的其中一条业务线的开发找到运维,提出来了一个MongoDB的优化问题,那段时间MongoDB正在从op管理移交给db进行维护,整个部门都对MongoDB的运维经验缺乏,MongoDB的优化更是一个未知的挑战。当op找到我,核心系统的公共服务平台用来进行短信服务的MongoDB集群想进行一次优化,我当仁不能让的承担了这项我都觉得可能搞不定的任务。
开发找到我提出了两点儿问题,并寻求运维团队解决这个问题,不过最终在我的理性的思考和他感性的思维碰撞下,最终我还是以胜利者的姿态胜出。我成功说服了他,并解答了他一些疑问,得到了满意的答复后再也没找我了。当然这里肯定不会就凭几句话,任你理论再怎么丰富,态度如何暧昧,不拿点儿真实数据,做点儿什么,怎么能说服经验丰富的开发认定的事儿。沟通了大半天,占据了我白天的工作时间,不过他提出来的问题还是很值得讨论。
根据开发的逻辑,是想横向扩充secondary节点,把其他要求不高的业务放到secondary节点上,减轻primary节点的压力,达到部分读写分离,使得主要业务优先保障。我觉得这个出发点是好的,但并没有就此作出回应,其一是他没有认识到这个他认为的有延迟并不是数据库集群的问题(这里不详细讲述排查的过程,下一篇文章会讲些MongoDB的写入与业务逻辑),其二是我们确实缺乏有效的资源硬件去进行扩充节点。
不同的业务场景应用不同的架构策略,扩充secondary节点有时候不能解决问题,尤其是那些实时性很高的业务,但有时候扩充secondary节点确实有效,比如硬件升级后需要做的服务迁移,需要在线扩充secondary节点来满足业务需要的更高的硬件要求。
MongoDB的secondary节点的扩充,我总结起来有两种方式:1、rs.add()直接扩充 2、一致性备份后进行扩充(个人叫法)
1、rs.add("HOST_NAME:PORT")
具体的实现方式是登陆扩充节点的机器,编辑好配置文件,并建立相应的目录和权限,启动MongoDB实例就可以了。
需要注意的一点儿是这种扩充方式要保证同步源的数据量级,即保证在同步完数据前MongoDB的oplog不会被覆盖,这点儿类似与MySQL的redo log日志,如果被覆盖那么同步的数据出现不一致,导致同步失败。
需要注意的另一点是同步数据的过程中,当集群数据达到一定量级时,同步数据的大小很大就会对网络造成一定的压力,可能对业务的核心交换机造成影响,因此需要用TC工具对同步流量做限速处理。这个限速需要考虑同步源可能不会是primary,也可能是同样角色的secondary节点,令外限速同步势必会增大同步时间,这个会增大oplog被覆盖的概率,具体限速值还是要经过计算才能把握好。
2、一致性快照快速添加secondary节点(自我命名,欢迎各位交流)
a)primary节点上进行一致性快照备份
b)secondary节点上进行一致性快照恢复,仅仅对数据部分进行恢复,暂时不要对oplog进行恢复
c)初始化oplog.rs集合,并恢复oplog记录
d)初始化local数据库的其他两个集合db.replset.election,db.system.replset
e)修改数据库配置并重启数据库(这一步操作前实例不开启认证模式、复制集的配置),rs.add("HOST_NAME:PORT")将secondary添加进集群并观察同步状态、校验数据的完整和一致性
实践的详细实践过程如下(仅供参考交流,生产环境慎用):
1、primary上进行一致性快照备份
#primary节点或者其他secondary节点备份数据
[root@--- mongodb]# /opt/app/mongodb/bin/mongodump -uroot -ppwd4mysql --authenticationDatabase=admin --port= --oplog -o /tmp/dump_mongo/
--20T15::47.028+ writing admin.system.users to
--20T15::47.030+ done dumping admin.system.users ( document)
--20T15::47.030+ writing admin.system.version to
--20T15::47.031+ done dumping admin.system.version ( documents)
--20T15::47.032+ writing super_hero.user_address to
--20T15::47.032+ writing super_hero.user_info to
--20T15::47.033+ done dumping super_hero.user_address ( document)
--20T15::47.033+ done dumping super_hero.user_info ( document)
--20T15::47.034+ writing captured oplog to
--20T15::47.036+ dumped oplog entry #查看备份的文件
[root@--- mongodb]# ls -lh /tmp/dump_mongo/
total 12K
drwxr-xr-x root root .0K Aug : admin
-rw-r--r-- root root Aug : oplog.bson
drwxr-xr-x root root .0K Aug : super_hero #传递备份到准备添加为secondary的节点上
[root@--- tmp]# scp -r -P22222 /tmp/dump_mongo/ liyingxiao@172.16.3.189:/tmp
2、secondary节点一致性快照恢复
#auth=true
#replSet = repl_mongo
#clusterAuthMode=keyFile
#keyFile=/opt/app/mongodb/keyfile/mongodb.key ##恢复数据
[root@--- test]# /opt/app/mongodb/bin/mongorestore --oplogReplay --port= /tmp/dump_mongo/
--20T15::32.161+ preparing collections to restore from
--20T15::32.193+ reading metadata for super_hero.user_info from /tmp/dump_mongo/super_hero/user_info.metadata.json
--20T15::32.194+ reading metadata for super_hero.user_address from /tmp/dump_mongo/super_hero/user_address.metadata.json
--20T15::32.222+ restoring super_hero.user_address from /tmp/dump_mongo/super_hero/user_address.bson
--20T15::32.300+ restoring super_hero.user_info from /tmp/dump_mongo/super_hero/user_info.bson
--20T15::32.867+ no indexes to restore
--20T15::32.867+ finished restoring super_hero.user_address ( document)
--20T15::32.881+ no indexes to restore
--20T15::32.881+ finished restoring super_hero.user_info ( document)
--20T15::32.881+ restoring users from /tmp/dump_mongo/admin/system.users.bson
--20T15::32.993+ replaying oplog
--20T15::32.997+ done
3、初始化oplog.rs集合,并恢复oplog记录
创建oplog.rs集合并初始化大小
use local
db.createCollection("oplog.rs",{"capped":true,"size":})
恢复一致性备份的oplog.rs集合的数据到secondary节点
[root@--- test]# /opt/app/mongodb/bin/mongorestore -d local -c oplog.rs --port= /tmp/dump_mongo/oplog.bson
--20T16::49.848+ checking for collection data in /tmp/dump_mongo/oplog.bson
--20T16::49.852+ restoring local.oplog.rs from /tmp/dump_mongo/oplog.bson
--20T16::49.925+ no indexes to restore
--20T16::49.925+ finished restoring local.oplog.rs ( document)
--20T16::49.925+ done
4、初始化db.replset.election,db.system.replset集合,其中replset.election需要查询主节点数据并将这些数据存储到secondary节点,或者两个结合自行save到secondary节点。另集合system.replset加入复制集后可自动识别primary节点内容(这里我采取自行同步数据)
#primary节点
repl_mongo:PRIMARY> db.replset.election.find()
{ "_id" : ObjectId("5b7a6ee5de7a24b82a686139"), "term" : NumberLong(), "candidateIndex" : NumberLong() }
#secondary节点
db.replset.election.save({ "_id" : ObjectId("5b7a6ee5de7a24b82a686139"), "term" : NumberLong(), "candidateIndex" : NumberLong() })
5、修改数据库配置并重启,添加secondary节点到复制集群中
#auth=true
#replSet = repl_mongo
#clusterAuthMode=keyFile
#keyFile=/opt/app/mongodb/keyfile/mongodb.key [root@--- test]# /opt/app/mongodb/bin/mongod --shutdown -f /opt/app/mongodb/mongo.conf
killing process with pid:
[root@--- test]# vim /opt/app/mongodb/mongo.conf #注释去掉并重启
[root@--- test]# /opt/app/mongodb/bin/mongod -f /opt/app/mongodb/mongo.conf
about to fork child process, waiting until server is ready for connections.
forked process:
child process started successfully, parent exiting #添加secondary节点
repl_mongo:PRIMARY> rs.add({"_id":,"host":"172.16.3.189:27017"})
{
"ok" : ,
"operationTime" : Timestamp(, ),
"$clusterTime" : {
"clusterTime" : Timestamp(, ),
"signature" : {
"hash" : BinData(,"Tt9nzhoVYdUtGFZnc1Kg1exl0Hc="),
"keyId" : NumberLong("")
}
}
}
6、登录添加的secondary节点,验证复制集状态,数据完整和一致性。
[root@--- test]# /opt/app/mongodb/bin/mongo -uroot -ppwd4mysql --authenticationDatabase=admin --port=
重点介绍第二种省时省心但费力费操作的添加secondary节点的方法,实践过程中数据库实例前期去掉认证和复制集参数,是方便我们下面的一些需要用户权限的操作,避免建立管理员账号,后续加入集群后自行同步了primary节点的账号。重启后登录secondary节点验证服务的可用性和数据一致性时,使用集群的管理账号进入,否则会报认证的错误。
总结如上两种扩充方式,对于方式1的扩充简单省事,需要保证oplog不被覆盖和评估同步流量的影响问题,是我们通常进行横向复制集添加secondary节点的方法。对于第二种方式,操作繁琐但不用担心oplog被覆盖,且操作期间不会过多担忧网络流量的问题,仅仅考虑网络传输的流量影响。第一种方式操作时间周期长,不可控的影响范围大费时费精力,第二种方式操作时间短,操作的步骤多,容易出现其他问题。
MongoDB添加secondary节点的两种方法的更多相关文章
- WebGL中添加天空盒的两种方法
天空盒 的添加可以让模型所在的场景非常漂亮,而其原理也是非常简单的,相信看完下面代码就可以明白了. 说到天空盒的两种方法,倒不如说是两种写法,分别用了纹理加载的两个方法:loadTexture和loa ...
- DataGridView动态添加新行的两种方法
简单介绍如何为DataGridView控件动态添加新行的两种方 法: 方法一: int index=this.dataGridView1.Rows.Add();this.dataGridView1.R ...
- windows 7中添加新硬件的两种方法(本地回环网卡)
最近在windows7上使用VMwareWorkstation7玩一些实验,遇到需要配置不同网络的问题. 因为在windows2003server上习惯使用要本地回环网卡了,那就想着在Windows7 ...
- 为WebService添加身份验证的两种方法
方法一:SoapHeader 辅助类:MySoapHeader //SoapHeader 添加引用 using System.Web.Services.Protocols; #region 配置登录标 ...
- Linux添加系统环境变量的两种方法
方法一 export PATH=/usr/local/bin:$PATH 这种方法的PATH 在终端关闭 后就会消失.所以还是建议通过编辑/etc/profile来改PATH 方法二 # vim /e ...
- Windows添加启动项的两种方法
方案1直接将脚本放到启动文件夹里面 C:\Users\XXX\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 方案2 Win ...
- idea添加svn项目的两种方法
1.是直接用svn客户端检出后,在idea直接打开其项目. 2.直接在idea里面拉取svn的项目
- Linux添加系统调用的两种方法
前言 系统调用的基本原理 系统调用其实就是函数调用,只不过调用的是内核态的函数,但是我们知道,用户态是不能随意调用内核态的函数的,所以采用软中断的方式从用户态陷入到内核态.在内核中通过软中断0X80, ...
- unity3d为对象添加脚本的两种方法
首先添加一个物体,然后新建一个C#脚本.接下去有两种方法把C#脚本与物体绑定. 1.在类声明上方添加如下代码: [AddComponentMenu("a/b")] 这句话表示在该物 ...
随机推荐
- 如何优化UI布局?
Android系统中填充布局是一个开销巨大的过程,每一个额外的嵌套布局和包含的View,都直接影响到应用程序的性能和响应能力.为了使应用程序流畅地运行和快速地响应,重要的是尽可能地保持布局的简单和避免 ...
- Java的四种引用——强引用、软引用、弱引用、虚引用
目录 强引用 软引用 弱引用 虚引用 强引用 拥有强引用的对象永远不会被GC,可以根据引用的get方法获取到被引用对象 软引用 在内存充足的额时候,拥有软引用的对象不会被GC:即将内存溢出的时候,会对 ...
- VMware Workstation安装Red hat7.0联网问题总结
1.在red hat7当中iconfig命令是被取消了的,开发者用ip addr命令取代了ifconfig命令. 当然也是可以用ifconfig命令的 (前提是你安装的linux是可以联网的): 1) ...
- PHP如何搭建百度Ueditor富文本编辑器
本文为大家分享了PHP搭建百度Ueditor富文本编辑器的方法,供大家参考,具体内容如下 下载UEditor 官网:下载地址 将下载好的文件解压到thinkphp项目中,本文是解压到PUBLIC目录下 ...
- git教程——工作流程
Git 工作流程 本章节我们将为大家介绍 Git 的工作流程. 一般工作流程如下: 克隆 Git 资源作为工作目录. 在克隆的资源上添加或修改文件. 如果其他人修改了,你可以更新资源. 在提交前查看修 ...
- Spring SpringMVC SpringBoot SpringCloud概念、关系及区别
一.正面解读: Spring主要是基于IOC反转Beans管理Bean类,主要依存于SSH框架(Struts+Spring+Hibernate)这个MVC框架,所以定位很明确,Struts主要负责表示 ...
- VS Code 常用插件
1.Chinese (Simplified) Language Pack for Visual Studio Code VS Code软件汉化 2.Auto Close Ta ...
- LeetCode笔记:39. Combination Sum
题目描述 给定一个无重复的正整数数组 candidates 和一个正整数 target, 求所有和为 target 的 candidates 中数的组合中.其中相同数的不同顺序组合算做同一种组合,ca ...
- 格式化数据保留两位小数,输入格式为 :xxx,xx,,,,x,,(x为浮点数)
/** * 格式化字符串 */ static String dataFormat(String data){ String formatedData = ""; // 浮点数正则表 ...
- Java线程中的同步
1.对象与锁 每一个Object类及其子类的实例都拥有一个锁.其中,标量类型int,float等不是对象类型,但是标量类型可以通过其包装类来作为锁.单独的成员变量是不能被标明为同步的.锁只能用在使用了 ...