服务器配置 HOSTNAME IP 应用 1-81 172.16.1.81 mongodb-3.6.23 1-82 172.16.1.82 mongodb-3.6.23 1-83 172.16.1.83 mongodb-3.6.23 0 副本集数据过程 (1) Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并且将复制信息写入到自己 的oplog。如果某个操作失败,则备份节点停止从当前数据源复制数据。如果某个备份节点由于某些原因挂掉了,当重新启动 后就会自动从oplog的最后一个操作开始同步,同步完成后,将信息写入自己的oplog,由于复制操作是先复制数据,复制完 成后再写入oplog,有可能相同的操作会同步两份,不过MongoDB在设计之初就考虑到这个问题,将oplog的同一个操作执行 多次,与执行一次的效果是一样的。简单的说就是: 当Primary节点完成数据操作后,Secondary会做出一系列的动作保证数据的同步: 1) 检查自己local库的oplog.rs集合找出最近的时间戳。 2) 检查Primary节点local库oplog.rs集合,找出大于此时间戳的记录。 3) 将找到的记录插入到自己的oplog.rs集合中,并执行这些操作。 (2) 副本集的同步和主从同步一样,都是异步同步的过程,不同的是副本集有个自动故障转移的功能。其原理是,slave端 从primary端获取日志,然后在自己身上完全顺序的执行日志所记录的各种操作(该日志是不记录查询操作的),这个日志就 是local数据库中的oplog.rs表,默认在64位机器上这个表是比较大的,占磁盘大小的5%,oplog.rs的大小可以在启动参 数中设定"--oplogSize 1000",单位是M。 (3) 注意,在副本集的环境中,要是所有的Secondary都宕机了,只剩下Primary,最后Primary会变成Secondary,不能 提供服务。 (4) mongodb默认是从主节点读写数据的,副本节点上不允许读写,需要设置副本节点可以读。 1 配置参数 # cat > /opt/mongodb/conf/mongodb.conf << EOF dbpath=/opt/mongodb/data #数据库文件位置 bind_ip=172.16.1.81 #绑定地址,默认127.0.0.1,只能通过本地连接,每个节点绑定的ip不一样。 port=27017 #端口,默认27017,MongoDB的默认服务TCP端口,监听客户端连接。 journal=true #启用日志文件,默认启用。 logpath=/opt/mongodb/log/mongodb.log #日志文件位置,该日志文件必须存在,否则会报错 pidfilepath=/opt/mongodb/mongodb.pid #后台进程pid文件 logappend=true #以追加方式写入日志。 quiet=true #这个选项可以过滤掉一些无用的日志信息,若需要调试使用请设置为false。 fork=true #以守护进程方式运行 #shardsvr=true #分片配置 #directoryperdb=false #是否修改数据为目录存储模式,默认为false #auth=true #keyFile=/opt/mongodb/conf/mongodb-keyfile #集群私钥的完整路径,只对于ReplicaSet架构有效,auth=true时配置此项 replSet=mongodb-replset # mongodb副本集名称 oplogSize=40960 #设置oplog的大小,节点操作记录存储到local的oplog中,用于从库拉取, #单位mb,磁盘满后循环覆盖。默认占磁盘大小的5%。 EOF 2 创建集群 # mongo --host 172.16.1.81 --port 27017 > use admin #定义副本集配置变量,这里的 _id:"mongodb-replset"和mongodb.conf配置参数"replSet"要保持一样 > config = { _id:"mongodb-replset", members:[{_id:0,host:"172.16.1.81:27017"},{_id:1,host:"172.16.1.82:27017"},{_id:2,host:"172.16.1.83:27017"}]} #初始化副本集配置 > rs.initiate(config) # 查看集群配置 > rs.conf() #查看集群节点的状态 > rs.status() 注: 副本集配置成功后,172.16.1.81为主节点PRIMARY,172.16.1.82/83为副本节点SECONDARY。 health:1 1状态是正常,0表明异常 state:1 值小的是primary节点、值大的是secondary节点 # 设置延迟从库 > cfg = rs.conf() > cfg.members[2].priority = 0 > cfg.members[2].hidden = true > cfg.members[2].slaveDelay = 3600 > rs.reconfig(cfg) 注: 这里将id为2的172.16.1.83节点作为延迟从库,延迟时间为3600s。 cfg.members[2].priority = 0 表示延迟从库永远不会变为主节点。 3 添加认证 (1) 创建管理用户(在主节点上操作) # mongo --host 172.16.1.81 --port 27017 > use admin > db.createUser({user: "root",pwd: "123456",roles: [ { role: "root", db: "admin" } ]}) > exit (2) 分发认证key(在主节点上操作) # openssl rand -base64 741 > /opt/mongodb/conf/mongodb-keyfile # chmod 600 /opt/mongodb/conf/mongodb-keyfile # chown mongodb:mongodb /opt/mongodb/conf/mongodb-keyfile # scp -p /opt/mongodb/conf/mongodb-keyfile root@172.16.1.82:/opt/mongodb/conf/ # scp -p /opt/mongodb/conf/mongodb-keyfile root@172.16.1.83:/opt/mongodb/conf/ # ssh -p 22 root@172.16.1.82 "chown mongodb:mongodb /opt/mongodb/conf/mongodb-keyfile" # ssh -p 22 root@172.16.1.83 "chown mongodb:mongodb /opt/mongodb/conf/mongodb-keyfile" (3) 修改配置文件(在三个节点上分别操作) # cat >> /opt/mongodb/conf/mongodb.conf << EOF auth=true keyFile=/opt/mongodb/conf/mongodb-keyfile EOF (4) 重启mongodb服务(依次重启三个节点) # systemctl restart mongodb.service # systemctl status mongodb.service (5) 测试 # 主节点 # mongo --host 172.16.1.81 --port 27017 -uroot -p'123456' admin > use master_slave_test > function add(){var i = 0;for(;i<7;i++){db.persons.insert({"name":"master_slave_test"+i})}} > add() > db.persons.find() # 从节点 # mongo --host 172.16.1.82 --port 27017 -uroot -p'123456' admin > db.getMongo().setSecondaryOk() > use master_slave_test > db.persons.find() # mongo --host 172.16.1.83 --port 27017 -uroot -p'123456' admin > db.getMongo().setSecondaryOk() > use master_slave_test > db.persons.find() 注: # mongodb默认是从主节点读写数据的,副本节点上不允许读写,需要设置副本节点可以读 mongodb-replset:SECONDARY> db.getMongo().setSecondaryOk() <=> mongodb-replset:SECONDARY> rs.secondaryOk() 4 副本集的工作流程 (1) mongodb的oplog.rs表记录日志是默认开启的,大小为磁盘的5%。 (2) 在MongoDB副本集中,主节点负责处理客户端的读写请求,备份节点则负责映射主节点的数据。备份节点的工作原理过程可以大 致描述为,备份节点定期轮询主节点上的数据操作,然后对自己的数据副本进行这些操作,从而保证跟主节点的数据同步。至于主节 点上的所有数据库状态改变的操作,都会存放在一张特定的系统表中。备份节点则是根据这些数据进行自己的数据更新。 (3) oplog 上面提到的数据库状态改变的操作称为oplog(operation log,主节点操作记录)。oplog存储在local数据库的"oplog.rs"表中。 副本集中备份节点异步的从主节点同步oplog,然后重新执行它记录的操作,以此达到了数据同步的作用。关于oplog有几个注意的 地方: 1) oplog只记录改变数据库状态的操作。 2) 存储在oplog中的操作并不是和主节点执行的操作完全一样,例如"$inc"操作就会转化为"$set"操作。 3) oplog存储在固定集合中(capped collection),当oplog的数量超过oplogSize,新的操作就会覆盖就的操作。 (4) 数据同步 在副本集中,有两种数据同步方式: 1) initial sync(初始化): 这个过程发生在当副本集中创建一个新的数据库或其中某个节点刚从宕机中恢复,或者向副本集中添 加新的成员的时候,默认的副本集中的节点会从离它最近的节点复制oplog来同步数据,这个最近的节点可以是primary也可以是拥 有最新oplog副本的secondary节点。该操作一般会重新初始化备份节点,开销较大。 2) replication(复制): 在初始化后这个操作会一直持续的进行着,以保持各个secondary节点之间的数据同步。 (5) initial sync 当遇到无法同步的问题时,只能使用以下两种方式进行initial sync了 1) 第一种方式就是停止该节点,然后删除目录中的文件,重新启动该节点。这样这个节点就会执行initial sync。 注意: 通过这种方式sync的时间是根据数据量大小的,如果数据量过大,sync时间就会很长,同时会有很多网络传输,可能会影响 其他节点的工作。 2) 第二种方式是停止该节点,然后删除目录中的文件,找一个比较新的节点,然后把该节点目录中的文件拷贝到要sync的节点目录 中。 3) 通过上面两种方式中的一种,都可以重新恢复宕机的节点。 (6) 副本集管理 1) 查看oplog的信息通过"db.printReplicationInfo()"命令可以查看oplog的信息,字段说明: configured oplog size # oplog 文件大小 log length start to end # oplog 日志的启用时间段 oplog first event time # 第一个事务日志的产生时间 oplog last event time # 最后一个事务日志的产生时间 now: # 现在的时间 2) 查看slave状态通过"db.printSlaveReplicationInfo()"可以查看slave的同步状态当插入一条新的数据,然后重新检查 slave状态时,就会发现sync时间更新了。