mybk_yzy
当下数据为王的时代,数据的重要性已经和土地,劳动力,资本一样不分伯仲。尤其近年来各色各样的数据级公司相对崛起,数据的安全已经成为了决一兴败的关键。数据库的选型亦然成为了热度比较高的话题讨论。产品的存在必然有它存在的意义,产品的诞生的目地往往是为了弥补市场的空白,但也存在着另一个层次的目的,替代那些原有老旧维护力度不高的产品。
MongoDB 介于关系数据库和非关系数据库之间,相对于Mysql在表结构的扩展性方面非常松散灵活,此外,在海量数据存储,读写分离及弹性扩展的层面上也是相对弥补了Mysql集中式架构带来的弊端。在事务层次方面略逊于传统关系型数据库,
MongoDB 4.0 引入的事务功能,支持多文档ACID特性
。这对要求数据一致性较强的业务场景也多了一份选择。反过来思考,当下数据库产品各具千秋,
没有任何一种数据库能100%适用于任何业务场景,不断的尝试创新,融合才是保证数据高效的初心。
对于MongoDB,可以支持使用单节点模式提供服务,但是在实际的生产环境中,单机模式将面临很大的风险,一旦这个数据库服务出现问题,就会导致线上的服务出现错误甚至崩溃。因此,在实际生产环境下,需要对MongoDB做相应的主备处理,提高数据库服务的可用性。复本集(Replica Set)的方式做主备处理是目前官方社区推荐的高可用方案。
描述服务器环境Centos7的操作系统,Mongo3.4.2安装介质,节点分布情况大致为:
|
Host |
Ip |
softWare |
Port |
Usage |
note |
OS |
|
node-1 |
192.168.56.103 |
mongo 3.4 |
28001 |
Primary |
主节点 |
CentOS 7.6 |
|
node-2 |
192.168.56.101 |
mongo 3.4 |
28001 |
Secondary |
从节点 |
CentOS 7.6 |
|
node-3 |
192.168.56.102 |
mongo 3.4 |
28001 |
Arbiter |
仲裁节点 |
CentOS 7.6 |
要实现的业务目地
:
使用Replica Sets来实现读写分离,
Secondary负责读的操作,Primary负责写的操作。减轻数据库压力。

复制原理:
如网上这张图所展示的执行顺序,Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己的oplog。如果某个操作失败,则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动后,就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,由于oplog属于高幂等性,将oplog的同一个操作执行多次,与执行一次的效果是一样的。做MySql的都知道PTR,利用的就是全备+binlog恢复,MongoDB在这一点上跟mysql是一样的。
当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步:
1.检查自己local库的oplog.rs集合找出最近的时间戳。
2.检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。
3.将找到的记录插入到自己的oplog.rs集合中,并执行这些操作。
副本集的同步和主从同步一样,都是异步同步的过程,不同的是副本集有个自动故障转移的功能。其原理是slave端从primary端获取日志,然后在自己身上完全顺序的执行日志所记录的各种操作(该日志是不记录查询操作的),这个日志就是local数据 库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小可以在启动参数中设 定:--oplogSize 1000,单位是M。
注意,在副本集的环境中,要是所有的Secondary都宕机了,只剩下Primary。最后Primary会变成Secondary,不能提供服务。
部署副本集操作流程:
3台服务器全部安装mongoDB,提前规划好各个节点的分布。我是编写shell 进行自动化安装。
安装流程相对简单,本篇笔记不多做介绍。
pwd
/home/mogodb3/mongod.conf
配置文件 mongod.conf 如下:
|
port=28001 #实例端口 |
|
dbpath=/data/whale28001_mongo3/data#数据存储路径 |
|
logpath=/data/whale28001_mongo3/log/mongodb3.log#日志存取路径 |
|
pidfilepath=/data/whale28001_mongo3/primary.pid#服务实例ID |
|
directoryperdb=true#
数据目录存储模式,每个数据库的文件存储在DBPATH指定目录的不同的文件夹中。使用此选项,可以配置的MongoDB将数据存储在不同的磁盘设备上,以提高写入吞吐量或磁盘容量。默认为false。 |
|
logappend=true#日志追加 |
|
fork=true#后台进程运行实例 |
|
maxConns=500#最大连接数,根据系统环境调整 |
|
auth=false#关闭权限校验 |
|
journal=false#数据故障恢复和持久化数据 |
|
storageEngine=wiredTiger#数据引擎 |
|
bind_ip =0.0.0.0 |
|
quiet=false#日志是否记录事件关闭和连接日志信息 |
|
oplogSize=100#日志大小,这个设置挺有意思的,太大浪费性能,太小不满足,(请指点) |
|
noprealloc=true#磁盘预分配空间,防止数据增量过快防止IO阻塞 |
|
replSet=monitor#副本集名称 |
启动各个节点mongo服务:
pwd
/home/mogodb3/bin
启动mongo:
./mongod --config /home/mogodb3/mongod.conf
建立mongo 连接:
./mongo 192.168.56.103:28001
注意,刚建立的mongoDB 数据库服务,需要在mongod.conf 中 将auth权限认证关闭auth=false。再去创建数据库和对应账户。另外,关闭权限认证,登录用户会看见系统库,不安全。如若对外方提供账号不建议。
1.use admin;#选择库
2.创建 admin 库的所属用户admin 角色为数据库管理角色。如果在副本集运行过程中创建节点数据库对应的角色提示 not master相关关键字,则说明的是该节点目前不可添加,需要把集群关系中断关闭其他节点再次尝试创建用户。

在mongoShell中创建用户:db.createUser({user:"admin", pwd:"admin", roles:[{role:"userAdminAnyDatabase", db:"admin"}]})
#查看当前数据库的所有用户
show users();
MongoShell 创建数据库的注意点 使用use 创建数据库 use mydb; 然后show dbs; 你会发现新建的数据库不显示。因为show dbs 不会显示空的数据库。需要插入一条记录才可显示数据库。
db.mydb.insert("date":"20210506");
后再次查看可看到新库。
db.mongo.find(); 查看插入记录。

接下来的操作给刚刚创建的mydb数据库创建用户,并赋予角色权限和指定数据库。
db.createUser(
{
user: "mydb",
pwd: "mydb",
roles: [ { role: "dbOwner", db: "mydb" } ]
}
)
再次给用户增加用户
readWrite
角色权限。
db.grantRolesToUser("mydb", [ { role: "readWrite", db: "mydb" } ])
查看赋值后的用户属性。

各个节点创建完用户后在各个节点启动MongoServer,开始配置高可用副本集,明确节点分布,定制集群配置,priority设置的等级越高越容易成为主节点。_id 后为集群名称。
cfg={
_id:"monitor",
members:[{_id:0,host:'192.168.56.103:28001',priority:2},{_id:1,host:'192.168.56.101:28001',priority:1},{_id:2,host:'192.168.56.102:28001',arbiterOnly:true}]
};
rs.initiate(cfg); //初始化配置
rs.reconfig(
cfg
); //使配置生效
rs.reconfig(
cfg
, { force: true})//强制使其配置文件生效,生效后MongoShell光标会发生变化
主节点查看集群状态:
monitor:PRIMARY> rs.status()
{
"set" : "monitor",#集群名称
"date" : ISODate("2021-05-04T08:00:43.742Z"),
"myState" : 1,#状态
"term" : NumberLong(11),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"appliedOpTime" : {
"ts" : Timestamp(1620115242, 1),
"t" : NumberLong(11)
},
"durableOpTime" : {
"ts" : Timestamp(1620112370, 1),
"t" : NumberLong(10)
}
},
"members" : [
{
"_id" : 0,
"name" : "192.168.56.103:28001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",#主节点
"uptime" : 2663,
"optime" : {
"ts" : Timestamp(1620115242, 1),
"t" : NumberLong(11)
},
"optimeDate" : ISODate("2021-05-04T08:00:42Z"),
"electionTime" : Timestamp(1620112591, 1),
"electionDate" : ISODate("2021-05-04T07:16:31Z"),
"configVersion" : 4,
"self" : true
},
{
"_id" : 1,
"name" : "192.168.56.101:28001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",#复制节点
"uptime" : 2662,
"optime" : {
"ts" : Timestamp(1620115232, 1),
"t" : NumberLong(11)
},
"optimeDurable" : {
"ts" : Timestamp(1620112370, 1),
"t" : NumberLong(10)
},
"optimeDate" : ISODate("2021-05-04T08:00:32Z"),
"optimeDurableDate" : ISODate("2021-05-04T07:12:50Z"),
"lastHeartbeat" : ISODate("2021-05-04T08:00:41.876Z"),
"lastHeartbeatRecv" : ISODate("2021-05-04T08:00:42.146Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "192.168.56.103:28001",
"configVersion" : 4
},
{
"_id" : 2,
"name" : "192.168.56.102:28001",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",#仲裁节点
"uptime" : 2662,
"lastHeartbeat" : ISODate("2021-05-04T08:00:41.876Z"),
"lastHeartbeatRecv" : ISODate("2021-05-04T08:00:39.498Z"),
"pingMs" : NumberLong(0),
"configVersion" : 4
}
],
"ok" : 1
}
查看副本集信息:
monitor:PRIMARY> db.isMaster()
{
"hosts" : [
"192.168.56.103:28001",#主节点
"192.168.56.101:28001"#备份节点
],
"arbiters" : [
"192.168.56.102:28001"#仲裁节点
],
"setName" : "monitor",#集群名称
"setVersion" : 4,
"ismaster" : true,
"secondary" : false,
"primary" : "192.168.56.103:28001",
"me" : "192.168.56.103:28001",
"electionId" : ObjectId("7fffffff000000000000000b"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1620199579, 1),
"t" : NumberLong(11)
},
"lastWriteDate" : ISODate("2021-05-05T07:26:19Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2021-05-05T07:26:22.197Z"),
"maxWireVersion" : 5,
"minWireVersion" : 0,
"readOnly" : false,
"ok" : 1
}
登录不同的节点进行mongo连接,会进入不同的mongoShell 界面,使用可视化工具连接主节点和复制节点,模式选Replica Set连接,俩个节点都有mydb这个库,并有着对应的数据库用户,mongo的用户是指定库的,连接后 在主节点PRIMARY端创建个新表并插入测试数据。


刷新从节点服务端表数据,发现已经从主节点同步过来了刚刚新增过来的数据记录。为了更好的测试数据同步机制。在主节点上导入一个备数据,测试节点是否也会有同样的表。主节点恢复数据操作:
备份数据:
/home/mongodb3/mongodump --host 127.0.0.1 --port 28001 -u
admin
-p
admin
--authenticationDatabase admin -d
newdb
-c wb0097xxxry_all -o
/data/bak
恢复备份数据:
/home/mogodb3/bin/mongorestore --host 127.0.0.1 --port 28001 -u admin -p admin --authenticationDatabase admin -d mydb /data/bak
恢复完成后发现各个复制节点已经有这张表说明副本集可用,数据同步机制正在生效。
副本集添加新备份节点:
在主节点添加节点: rs.add("192.168.104:28001");返回1说明添加节点生效。

查看副本集状态,发现节点状态异常为not healthy。

最有效的解决方法,先关闭新节点数据库,一定不要使用kill -9 pid 的方式停止服务。 ./mongod --shutdown -f /home/
mongodb3/mogod.conf
再清空新节点下 数据目录的文件数据 重新启动。rm -rf *
./mongod --config /home/mongodb3/mongod.conf --replSet monitor
在主节点查看集群状态,发现新添加节点状态还是不健康,解决办法删除该节点重新添加。
rs.remove("192.168.56.104:28001")
rs.add("192.168.56.104:28001");
rs.status();集群状态恢复正常。

本篇笔记偏基础的介绍了MongoDB高可用的实践来保证业务的稳定和数据库的健壮性。还有很多工作中经常用到的点在这里没介绍到,接下来会力争在空闲时间内使用python 达到集群的自动化配置和高容灾策略的实现。人算不如天算,做数据行业的多考虑一点风险还是好的。希望各位老师多点评,不吝指教。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69999437/viewspace-2770831/
,如需转载,请注明出处,否则将追究法律责任。