目录html
单节点的 MongoDB
在数据的安全和冗余方面是比较低的,在生产环境中,咱们为 MongoDB
配置副本集,这样能够提升数据的高可用性和安全性。linux
副本集 :是一组 Mongod
维护相同数据集的实例。副本集能够包含多个数据承载点和多个仲裁点。在承载数据的节点中,仅有一个节点被视为主节点,其余节点称为次节点。git
副本集的节点角色:github
主节点接收全部的数据写入操做,主节点记录数据的全部更改,即oplog
。mongodb
将一个额外的mongod
实例添加到副本集做为 仲裁节点。仲裁节点不维护数据集。仲裁节点的目的是经过响应其余副本集成员的心跳和选举请求来维护副本集中的选举。由于它们不存储数据集,因此仲裁节点能够是提供副本集仲裁功能的好方法,其资源成本比具备数据集的全功能副本集成员更低。若是您的副本集具备偶数个成员,请添加仲裁者以免脑裂出现。shell
在主节点未与配置中的其它成员通讯超过 10s(默认为10s)的话,则符合条件的次节点将推选本身为主节点。数据库
在选举成功完成以前,副本集没法处理写入操做。api
electionTimeoutMillis
默认值为10000(10s) ,咱们能够根据本身的项目状况来升高或者下降该值,咱们在更改该值的时候须要考虑到网络延迟等因素。安全
默认状况下,副本集在选取新的主节点的等待时间不超过12秒(主要用于将原有主节点标记为不可用,并选举出新的主节点),bash
为了保持次节点与主节点的数据同步,MongoDB 使用两种方式进行数据的同步:
初始同步, 用于同步主节点的全部数据
初始同步将全部的数据从副本集的一个成员复制到另一个成员
增量同步,在初始同步后不断复制新的数据
在初始同步后不断复制数据,次节点从主节点中同步复制 Oplog,并在异步过程当中应用这些操做
副本集在部署前须要肯定成员数据,副本集最多能有50个节点,可是只能有7个节点拥有被选举权,副本集须要具备奇数个投票成员,若是有偶数个的话,能够添加一个 仲裁者,来保证有奇数个成员,避免脑裂状况发生,
尽可能使用 主机名 来寻找对应的节点,而不是使用 ip 地址,避免 ip 改变致使配置须要更改。
部署须要更改 /etc/hosts 文件,将主机名和 ip 地址对应好,不该该使用ip。
使用统一的端口。
建立数据储存的位置和配置文件的位置。
肯定好副本集的名称
搭建架构选择
三节点,一个主节点,一个次节点,一个仲裁节点
基本环境: 系统 CentOS 7 MongoDB 版本 4.0.8 3个节点 fymongodb001 内网IP:172.18.186.161 公网ip: 47.112.129.2 # 主节点 fymongodb002 内网IP: 172.18.186.162 公网ip: 47.112.131.231 # 次节点 fymongodb003 内网IP: 172.18.186.163 公网ip: 47.112.98.64 # 仲裁节点 副本集名称: fymongodb
三个节点都须要执行
# 下载mongodb cat <<EOF >>/etc/hosts 172.18.186.161 fymongodb001 172.18.186.162 fymongodb002 172.18.186.163 fymongodb003 EOF cd /tmp && wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.8.tgz tar -zxf mongodb-linux-x86_64-4.0.8.tgz mv mongodb-linux-x86_64-4.0.8 /opt/mongodb mkdir /opt/mongodb/{data,logs} useradd mongodb # 咱们这里使用的配置文件 是YAML 格式的 wget https://raw.githubusercontent.com/tobewithyou1996/LinuxGuide/master/MongoDB/mongodb_rep.yaml -P /opt/mongodb/ chown -R mongodb:mongodb /opt/mongodb/ cat <<EOF >>/usr/lib/systemd/system/mongodb.service [Unit] Description= mongodb service manager [Service] # Other directives omitted # (file size) LimitFSIZE=infinity # (cpu time) LimitCPU=infinity # (virtual memory size) LimitAS=infinity # (locked-in-memory size) LimitMEMLOCK=infinity # (open files) LimitNOFILE=64000 # (processes/threads) LimitNPROC=64000 Type=forking User=mongodb Group=mongodb PIDFile=/opt/mongodb/logs/mongod.pid ExecStart= /opt/mongodb/bin/mongod -f /opt/mongodb/mongodb_rep.yaml ExecStop= /opt/mongodb/bin/mongod --shutdown --dbpath /opt/mongodb/data Restart=always [Install] WantedBy=multi-user.target EOF # 添加环境变量 echo "export PATH=$PATH:/opt/mongodb/bin" >>/etc/profile source /etc/profile # 启动 systemctl start mongodb
主节点操做
# 主节点操做 [root@fymongodb001 tmp]# mongo MongoDB shell version v4.0.8 connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb Implicit session: session { "id" : UUID("77f60167-1d37-4796-bf2a-60cfdc4b0526") } MongoDB server version: 4.0.8 > use admin # 切换到 admin 数据库 switched to db admin # 初始化副本集,副本集名称为 fymongodb ,第一个成员为本身自己。 > rs.initiate({_id:'fymongodb',members: [{ _id: 0 , host: "fymongodb001:27017"}]}) { "ok" : 1 } fymongodb:SECONDARY> # 接着回车,直到显示这个节点为Primary主节点 fymongodb:PRIMARY> # 接着添加 次节点 fymongodb002 # 添加次节点 fymongodb:PRIMARY> rs.add('fymongodb002:27017') { "ok" : 1, "operationTime" : Timestamp(1555663440, 1), "$clusterTime" : { "clusterTime" : Timestamp(1555663440, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } # 添加仲裁节点 fymongodb:PRIMARY> rs.addArb("fymongodb003:27017") { "ok" : 1, "operationTime" : Timestamp(1555663631, 1), "$clusterTime" : { "clusterTime" : Timestamp(1555663631, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } # 查看当前配置 fymongodb:PRIMARY> rs.conf() { "_id" : "fymongodb", "version" : 3, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "fymongodb001:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "fymongodb002:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "fymongodb003:27017", "arbiterOnly" : true, "buildIndexes" : true, "hidden" : false, "priority" : 0, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("5cb98534cd9d16ff3f4fffdc") } } # rs.status() 查看各个节点的身份
当咱们完成上面的操做的时,咱们主节点更改的数据已是会自动同步到次节点的。
次节点操做
fymongodb002
次节点(Secondary)设置容许读写操做。
[root@fymongodb002 ~]# mongo MongoDB shell version v4.0.8 connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb Implicit session: session { "id" : UUID("f353edd5-d79a-4947-9844-7f9bde98a949") } MongoDB server version: 4.0.8 fymongodb:SECONDARY> fymongodb:SECONDARY> show dbs; # 咱们发现没法读写 2019-04-19T17:04:40.852+0800 E QUERY [js] Error: listDatabases failed:{ "operationTime" : Timestamp(1555664675, 1), "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk", "$clusterTime" : { "clusterTime" : Timestamp(1555664675, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } : fymongodb:SECONDARY> rs.slaveOk() # 容许 次节点 进行读取 fymongodb:SECONDARY> show dbs; # 咱们就能够查看到次节点的数据了。 admin 0.000GB config 0.000GB djx 0.000GB local 0.000GB fymongodb:SECONDARY> use djx; switched to db djx fymongodb:SECONDARY> show collections; # 从主节点同步过来的数据。 djx lsp
测试数据的同步,咱们在主节点建立一个集合test
并添加一条数据 'age':38
,咱们能够看到次节点也同步了该数据。
测试一
模拟主节点 fymongodb001
宕机了,而后查看次节点 fymongodb002
是否会被选举成为主节点。
咱们能够看到 fymongodb002
选举为主节点.
测试二
当 fymongodb002
选举为主节点后,fymongodb001
恢复了,fymongodb001
会做为次节点加入。
测试三
测试在次节点(Secondary)进行数据删除。是删除不了的。
fymongodb:SECONDARY> db.test.drop() 2019-04-19T21:48:38.140+0800 E QUERY [js] Error: drop failed: { "operationTime" : Timestamp(1555681711, 1), "ok" : 0, "errmsg" : "not master", "code" : 10107, "codeName" : "NotMaster", "$clusterTime" : { "clusterTime" : Timestamp(1555681711, 1), "signature" : { "hash" : BinData(0,"I+dFkOHcdqW+La7xvy8JFij+5CY="), "keyId" : NumberLong("6681517989155569665") } } } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 DBCollection.prototype.drop@src/mongo/shell/collection.js:707:1 @(shell):1:1
副本集配置用户和密码,登陆主节点,添加admin
用户。
> use admin switched to db admin > db.createUser({ user: "admin", pwd: "9toc7tpji8", roles: [{ role: "root", db: "admin" }] }) Successfully added user: { "user" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] }
在主节点生成 keyflie
并复制到其它两个节点
# 生成 keyFile openssl rand -base64 90 -out /opt/mongodb/keyfile #并复制到其它两个节点 scp /opt/mongodb/keyfile fymongodb002:/opt/mongodb/ scp /opt/mongodb/keyfile fymongodb003:/opt/mongodb/
更改三个节点的 keyFile
文件权限和全部者
chmod 600 /opt/mongodb/keyfile # 必定要更改为 600 权限,否正会报错 chown mongodb:mongodb /opt/mongodb/keyfile # 更改文件全部者
更改三个节点的 mongodb_rep.yaml
配置文件,将 security
的参数 authorization
设置为 enabled
,并配置
keyFile
的路径。
security: authorization: "enabled" keyFile: '/opt/mongodb/keyfile' clusterAuthMode: "keyFile"
而后依次重启 fymongodb001
、 fymongodb002
、 fymongodb003
。
# fymongodb001 systemctl restart mongodb # fymongodb002 systemctl restart mongodb # fymongodb003 systemctl restart mongodb
登录 fymongodb001
,咱们使用 db.auth()
进行登录验证。
fymongodb:PRIMARY> show dbs; fymongodb:PRIMARY> use admin switched to db admin fymongodb:PRIMARY> db.auth('admin','9toc7tpji8') 1 fymongodb:PRIMARY> show dbs; admin 0.000GB config 0.000GB local 0.000GB
副本集当作单节点启动须要更改配置文件,主要的配置文件有如下几点:
replSet=fymongodb
而后咱们执行维护完后,关闭节点
use admin db.shutdownServer()
而后还原原来的配置,而后做为副本集成员加入副本集。
若是咱们想让某个节点成为主节点,或者是当主节点 down 了后,你想指定某个节点 优先级更高地成为 次节点。
cfg = rs.conf() cfg.members[0].priority = 0.5 cfg.members[1].priority = 0.5 cfg.members[2].priority = 1 rs.reconfig(cfg)
# 使用备份数据进行启动 mongod --dbpath /data/db # 删除 local 数据库 use local db.dropDatabase() # 指定副本集名称并以备份数据 启动 mongod --dbpath /data/db --replSet <replName> # 启动副本集 rs.initiate( { _id : <replName>, members: [ { _id : 0, host : <host:port> } ] })
当副本集的数据量比较大的时候,咱们添加新的节点的时候,若是使用初始化同步的话,会给主节点形成比较大的压力。咱们有如下选择:
暂停当前副本集中的一个次节点,而后将 次节点的数据(data)复制到要新添加的节点的数据目录。而后再将两个节点启动。(建议先测试)
若是要复制数据文件,请确保您的副本包含
local
数据库的内容。
指定同步节点 rs.syncFrom(hostportstr)
,指定同步节点为次节点,默认的是同步节点 是主节点。
可是该设置在从新启动节点,或者同步指定的新节点的链接被关闭了,是会失效的。(建议先测试)
若是咱们决定仍是从主节点进行同步数据。
延迟节点在此未记录,详细见官方文档。
# 副本集初始化 rs.initiate( { _id : "rs0", members: [ { _id: 0, host: "mongodb0.example.net:27017" }, { _id: 1, host: "mongodb1.example.net:27017" }, { _id: 2, host: "mongodb2.example.net:27017" } ] }) # 副本集添加成员 rs.add('mongodb3.example.net:27017') # 副本集添加仲裁节点 rs.addArb('mongodb4.example.net:27017') # 移除节点 rs.remove('hostportstr') # 查看当前的配置 rs.conf() # 查看各个节点状态和身份 rs.status() # 设定某个节点多少秒不可成为主节点 rs.freeze(secs) # 设置次节点从指定节点同步数据 rs.syncFrom(hostportstr) # 下降主节点为次节点,只能在主节点上运行 rs.stepDown([stepdownSecs, catchUpSecs]) # 查看帮助 rs.help() # 次节点执行,表示容许次节点读取数据 rs.slaveOk() # 判断当前节点是不是主节点 rs.isMaster() # 查看 Oplog 信息 rs.printReplicationInfo() # 查看副本集的次节点与主节点延迟 db.printSlaveReplicationInfo() # 移除原有副本集命令 use local db.system.replset.remove({}) # 关闭 mongodb进程服务 use admin db.shutdownServer()
建议将副本集至少部署在3个可用区。
配置副本集成员,使用的是主机名而不是 ip,由于 ip 可能变更。
副本集包含奇数个投票成员。
报错内容:
Failed global initialization: BadValue: replication.replSetName is not allowed when storage.indexBuildRetry is specified
storage
参数 indexBuildRetry
不能与 副本集共存,当开启 副本集的时候,就须要将indexBuildRetry
参数注释。官网连接
Changed in version 4.0: The setting
storage.indexBuildRetry
cannot be used in conjunction withreplication.replSetName
.