MongoDB目前的高可用架构主要有主从、复制集、以及分片,单纯的主从技术几乎被淘汰,整个稳定性以及可靠性方面复制集要比主从好,所以现在更多的会去使用复制集。在接下来的实践过程中,我们将通过多实例的方法实现复制集。以及会解析搭建过程中遇到的困难问题。
一、基础环境与规划
操作系统:CentOS 6.7
MongoDB版本:3.4.5
实例部署情况:
主机IP | 数据目录 | 日志文件 | 端口 |
127.0.0.1 | /data/mongoDB/data/m17 | /data/mongoDB/logs/mongo17.txt | 28017 |
127.0.0.1 | /data/mongoDB/data/m18 | /data/mongoDB/logs/mongo18.txt | 28018 |
127.0.0.1 | /data/mongoDB/data/m19 | data/mongoDB/logs/mongo19.txt | 28019 |
由于在同一台主机上面部署,所以就不需要考虑防火墙的配置与管理。大多数生产环境都有专业的硬件防火墙(思科、华为)等厂商的硬件防火墙设备,部分的公有云也是有一些防火墙的产品,所以Iptables在生产环境中应该能起到锦上添花的作用,在整个过程中不考虑这一块。
二、副本集原理与优化
2.1 副本集原理
复制集(Replica Set),就是有自动故障恢复功能的主从集群。主从结构和复制集最明显的区别是副本集没有固定的主节点,当节点故障时,能选举新的主节点,大大的提升了整个系统中数据存储的稳定性;整个集群选举出一个主节点,当主节点不能正常工作时,会选举出另一个节点为主节点,
复制集总会有一个活跃节点(Primary)和一个或者多个备份节点(Secondary),副本集中还可以有一个角色是仲裁者(Arbiter),它并不保存数据。仲裁节点使用最小的资源并且不要求硬件设备,不能将Arbiter部署在同一个数据集节点中,可以部署在其他应用服务器或者监视服务器中,也可部署在单独的虚拟机中。为了确保复制集中有奇数的投票成员(包括primary),需要添加仲裁节点做为投票,否则primary不能运行时不会自动切换primary。
在比较早的版本例如MongoDB2.6中,复制集中参与选举的数据节点(包括primary)只能有7个 可以通过更改数据节点属性的方法将复制集的数据节点增加到12个,但是其余的5个为非投票成员(Non-Voting Members),非投票成员是副本集中数据的备份副本,不参与投票,但可以被投票或成为主节点。当我们的复制集超过11个时,可以使用传统的主从方法 数量不限制。
2.2 复制集的特点
复制集的特点
数据一致性 使得多个进程/服务器在某个方面保持相同 异步同步(受磁盘、网络、数据大小影响)
主是唯一 只有1台主能进行读写,其余的只能读,同时主不是固定的 ,不像MySQL具有双主架构,
大多数原则 集群存活节点小于或等于二分之一时集群不可写 只可读
Secondary节点不支持写入 MySQL从库的readonly对具有super权限的账户无效
相比传统的主从结构 复制集可以自动容灾
不支持类似MYSQL只从中只同步部分库的功能
副本集之间的复制是通过oplog日志现实的.备份节点通过查询这个集合就可以知道需要进行复制的操作
oplog是节点中local库中的一个固定的集合,在默认情况下oplog初始化大小为空闲磁盘的5%.oplog是capped collection,所以当oplog的空间被占满时,会覆盖最初写入的日志.
通过改变oplog文档的大小直接改变local所占磁盘空间的大小.可以在配置文件中设置oplogSize参数来指定oplog文档的大小,例如oplogSize=1024单位默认为M 每个local文档在磁盘空间的空间都为2G,设置不足2G的,初始化依然为2G大小,例如上面oplogSize=1024,但创建的local.01大小依然为2G.
如果备份节点不幸挂掉,由于复制过程中是先写数据,再写oplog,这样重新启动时,可能会重复复制操作.但mongodb在设计过程中已经考虑过这个问题.当 oplog中同一个操作执行多次的时候,只执行一次.
如果备节点的同步速度远远跟不上主节点的oplog写入的数据,并且主节点的oplog被覆盖.这样,可能就无法同步那些被覆盖的数据(出现这种情况,暂时还无法解决,只能通过备份主节点的数据,然后再重新同步).
每个成员通过心跳去查看其他节点的状态,每隔2秒钟就有一次心跳检测.
当主节点宕机之后,各个节点通过选举的方式来选择下一个主节点
2.3 复制集的实现步骤
规划端口、数据目录、日志目录等可以将其定制成配置文件;
为了安全需要准备其验证 (auth 验证和keyFile验证)
auth验证与keyFile验证的区别:auth更多的是实现单机版或者单实例的验证,这是MongoDB常见的安全加固方式之一,开启验证,对不同的库和用户做授权管理,而keyFile主要是用来集群之间不同示例之间的验证,主要有以下特点
keyFile特点:
基于base 64编码集 仅能识别[a-z A-Z + /]等内容,(传说中的 没具体的测试 )
长度最好小于 1000byte
权限问题 允许的最大的权限是600 所以在安装、配置、启动等环节需要注意所有者和所属组。
报错解决: mongod -f conf/29017.cnf #启动 about to fork child process, waiting until server is ready for connections. forked process: 2681 ERROR: child process failed, exited with error number 1 查看日志: 2017-06-01T00:10:39.307+0800 I CONTROL [main] ***** SERVER RESTARTED ***** 2017-06-01T00:10:39.490+0800 I ACCESS [main] permissions on /datamongo/key/.keyFile are too open
发现权限太大,导致不能正常启动,将keyFile的权限更改为600解决。
keyFile文件中时忽略空格、制表符、换行符的 以下内容可以等同
This name docker thisnamedocker
生成keyFile的方法推荐
openssl rand -base 64 N(字节数)
[root@localhost log]# openssl rand -base64 7 8ZNRiPFguw== [root@localhost log]# openssl rand -base64 10 IAcXv1pLK67/qw== [root@localhost log]# openssl rand -base64 12 LhhGR4GPk0dlTsLz [root@localhost log]# openssl rand -base64 512 VgC2wexhxefk3F1P1fnSNJcsp/wwnG3bugoccgLLupvLSSZGRa73PMl4ju+35uWf 45WAMiTZ2emIp2Wg6qdQLD3n2OdhZ6zF49VtpOal8Pok6hfVvq+Kr6FuEwI6Vrcu fa/XnnUCr69WIjILRkqIgfJZE3N+J3QExZBWFX28zoBlEoyjusEIQfP3Fod+XiIF EWENFlvAKNUFLts13ad9g3PornXvFsyqf1AH8rf1y+I9VbiHDHYNMpNBXtfk+Sh+ E8mG4IH2/FfSvLsn4fdYSZ3ZnD2Tfogk9Jhk6zdqO+drm0Yf6WL4cxMAHhKWdbps FAyjmis3sltWloshwqt4q+xtAo4JSYnT4Bo9MF8tyIb4ZZ2S6xIEjUV+FBELYGJO AVz6F39bHU0qeuWNL8wMHb8YCXaNzrY/a9OFP3ZaaeGz6fUH6ZZJe3T5OE2IB+eF 3vQZrSF/0bBG3hM5E6ziTIp9+HF4c1+Ltq5bMdLaKioEvc3kAFq0q34JlFxjC4/m aXasERqcvznLWb+3zXYbJiPpqxlOevEToXOGgmdkzAUrz5+g8IihPeOizO5iugt4 wwgki2ktnmU1l+wPqHPDUdW2/Hpvgdd5aHweDyu7Mc1OFAcvg53abxca2qi5g3Iu 1lVI12FDvSjRFO7bmM34rKxIgFuaiH4kQUmP+unLLSo= [root@localhost log]# openssl rand -base64 512 >.keyFile [root@localhost log]#
根据上面内容识别方法生成的文件中的“=”号是不能被识别的,要对其特殊处理,
3、启动副本集
在启动时,我们可以给mongd带好多的参数,但是这样比较麻烦,每次启动都要制定很多的参数,建议我们写配置文件;
#MOngoDB config port=27017 #启动监听端口 dbpath=/data/mongoDB/data/m17 #数据存储目录 logpath=/data/mongoDB/logs/mongo17.txt #日志文件目录 logappend=true #日志以追加的方式写入 pidfilepath=/datamongo/data/m17/27017.pid fork=true #以后台运行开启 oplogSize=1024 #初始化oplog的大小为1024M replSet=BOOL #副本集名称为BOOL 很重要的参数 必须统一 keyFile=/datamongo/key/.keyFile #keyFile验证文件的位置 setParameter=enableLocalhostAuthBypass=1 #避免在没有创建用户之前的 开启验证的权限问题
setParameter=enableLocalhostAuthBypass=1 该参数设置的特点
MongoDB实例中,没有任何用户时,才能生效
仅允许本机(localhost)登录,不能使用IP登录(包括127.0.0.1)
在实例创建用创建的第一个用户后失效
实例创建的第一个用户 必须属于admin库 并且该用户必须具有创建其他用户的权限
4、初始化副本集
随意进入其中的一个服务,进入admin库对其初始化,
use admin var conf=({_id:"BOOL", members:[ {"_id":0,host:"127.0.0.1:27017",priority:1}, {"_id":0,host:"127.0.0.1:27018",priority:2}, {"_id":0,host:"127.0.0.1:27019",priority:3} ] }) rs.initiate(conf) 执行OK
注意:
priority是个可选的参数,该参数可以决定该副本集中的节点成为primary节点的优先级,数字越大,优先级越高,在我们不同的主机之间存在性能差异时,我们可以合理的使用该参数,当不想让某一个节点永远不能成为primary节点时,就可以将priority参数设置成0
附件:
初始化脚本
#/bin/bash ################################describtion######################## #date 2017-07-08 #author peng #mail:1461535061@qq.com HOST_IP=127.0.0.1 DATA_DIR=/data/mongoDB/data/ LOGS_DIR=/data/mongoDB/logs/ MONGOD_PATH= /home/mongodb/mongodb/mongodb-3.4.5/bin/ NA=DB2 mkdir -p ${DATA_DIR}m17 ${DATA_DIR}m18 ${DATA_DIR}m19 ${LOGS_DIR} ${MONGOD_PATH}mongod --dbpath ${DATA_DIR}m17 --logpath ${LOGS_DIR}logs1 --port 28017 --smallfiles --replSet ${NA} --fork ${MONGOD_PATH}mongod --dbpath ${DATA_DIR}m18 --logpath ${LOGS_DIR}logs2 --port 28018 --smallfiles --replSet ${NA} --fork ${MONGOD_PATH}mongod --dbpath ${DATA_DIR}m19 --logpath ${LOGS_DIR}logs3 --port 28019 --smallfiles --replSet ${NA} --fork ${MONGOD_PATH}mongo --port 28017 <<EOF use admin var db2config={ _id:"DB2", members:[ {_id:0,host:"${HOST_IP}:28017"}, {_id:1,host:"${HOST_IP}:28018"}, {_id:2,host:"${HOST_IP}:28019"} ] } rs.initiate(db2config);
注意事项:
在我们复制集设置了keyFile验证后,我们初始化之后,在priamary节点想查看一下都有那些库,发现权限不够,这时我们就考虑创建用户
mongo 127.0.0.1:29017/admin MongoDB shell version v3.4.5 connecting to: mongodb://127.0.0.1:29017/admin MongoDB server version: 3.4.5 BOOL:PRIMARY> show dbs 2017-06-01T01:27:04.487+0800 E QUERY [thread1] Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }", "code" : 13, "codeName" : "Unauthorized" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1 shellHelper.show@src/mongo/shell/utils.js:769:19 shellHelper@src/mongo/shell/utils.js:659:15 @(shellhelp2):1:1 这时我们可以创建一个用户,多次测试 复制集在未创建用户时,将setParameter=enableLocalhostAuthBypass=1 参数注释后重启,直接可以到admin库创建用户 db.createUser( ... {user:"root", ... pwd:"123123", ... roles:[ ... {role:"root",db:"admin"} ... ] ... } ... ) Successfully added user: { "user" : "root", "roles" : [ { "role" : "root", "db" : "admin" } ] }
参考文档
http://blog.csdn.net/leftfist/article/details/39583585
http://blog.csdn.net/kk185800961/article/details/45791903
本文出自 “坚持梦想” 博客,转载请与作者联系!
原文地址:http://dreamlinux.blog.51cto.com/9079323/1945705