博客文章除注明转载外,均为原创。转载请注明出处。本文链接地址:http://blog.chinaunix.net/uid-31396856-id-5780054.html一、mongo副本集的原理主节点是集中接收写入操作的唯一成员。MongoDB中的应用连接到主节点进行写入操作,然后记录在主节点操作oplog。从节点成员复制此日志并将操作应用于其数据集。 在以下三个副本集中,primary节点接收所有写入操作。然后secondary节点复制oplog以应用到他们的数据集。mongo副本集的基础原理:副本集依赖于两个基础机制:oplog和heartbeat。oplog负责进行数据的复制;而心跳则监控各节点的健康状况并触发故障转移。1.oplog 副本集的复制是通过操作日志oplog实现的,oplog包含了节点的每一次写操作,记录。oplog是位于每个节点的lcoal数据库中的一个固定collection。所有副本集成员都在集合中包含oplog的副本local.oplog.rs,备份节点通过查询这个集合就可以知道需要进行复制的集合。 每次客户端向主节点写入数据,就会自动向主节点的oplog集合里面添加一个条目,记录当前的写操作。一旦写操作被复制到从节点,从节点的oplog也会保存一条关于写入的记录。每个oplog条目都由一个BSON时间戳进行标识,所有从节点都使用这个时间戳来追踪它们最后的应用条目。2.heartbeat心跳检测 副本集的心跳检测是进行选举和故障转移的基础。默认情况,每个副本集成员每两秒ping一次其它成员,做一次心跳请求(heartbeat request)。这样,每个成员就可以知道其它成员的状态:哪个是主节点?哪个可以作为同步源?哪个挂掉了? 心跳最重要的功能就是让主节点知道自己是否满足集合"大多数"的条件。如果主节点不在得到大多数支持,就会退位,变成备份节点。在运行re.status()时候,可以看到每个节点上次心跳检测的时间戳和健康状况。3.选举(Elections)当任意的故障切换发生,都会伴随着一个选举的出现,mongo副本集采用Bully选举算法,以此来决定哪个成员成为primary。选举提供了一种机制,用于副本集中的成员无需管理员的干预,自动的选出一个新的primary。选举可以让副本集快速和坚决的从故障中恢复。当primary变为不可达时,secondary成员发起选举,第一个收到大多数选票的成员成为新的primary(最大投票成员数)。4.副本集的特征:N 个节点的集群(N为奇数)任何节点可作为主节点所有写入操作都在主节点上自动故障转移二、创建mongo副本集1、安装并启动mongo:安装过程(略)[root@mongo 27017]# mongod -f /data/mongo/27017/conf/mongodb.confabout to fork child process, waiting until server is ready for connections.forked process: 1930child process started successfully, parent exiting[root@mongo 27018]# mongod -f /data/mongo/27018/conf/mongodb.confabout to fork child process, waiting until server is ready for connections.forked process: 1845child process started successfully, parent exiting[root@mongo 27019]# mongod -f /data/mongo/27019/conf/mongodb.confabout to fork child process, waiting until server is ready for connections.forked process: 1886child process started successfully, parent exiting状态如下:[root@mongo ~]# ps -ef|grep mongo|grep -v greproot 1845 1 0 11:34 ? 00:00:01 mongod -f /data/mongo/27018/conf/mongodb.confroot 1886 1 0 11:36 ? 00:00:00 mongod -f /data/mongo/27019/conf/mongodb.confroot 1930 1 2 11:38 ? 00:00:00 mongod -f /data/mongo/27017/conf/mongodb.confmongo的监听状态:[root@mongo ~]# netstat -antlp|grep mongotcp 0 0 0.0.0.0:27017 0.0.0.0:* LISTEN 1930/mongodtcp 0 0 0.0.0.0:27018 0.0.0.0:* LISTEN 1845/mongodtcp 0 0 0.0.0.0:27019 0.0.0.0:* LISTEN 1886/mongod2.选择主节点登陆进行配置副本集(1)选择admin数据库> use adminswitched to db admin(2)创建副本集> rsConfig = {_id: "repl", members: []}{ "_id" : "repl", "members" : [ ] }(3)添加副本集成员> rsConfig.members.push({_id: 0, host: "localhost:27017"})1> rsConfig.members.push({_id: 1, host: "localhost:27018"})2> rsConfig.members.push({_id: 2, host: "localhost:27019"})3(4)初始化副本集> rs.initiate(rsConfig);{ "ok" : 1 }创建副本集配置各项参数说明:"_id": 副本集的名称"members": 副本集的服务器列表"_id": 服务器的唯一ID"host": 服务器主机"priority": 是优先级,默认为1,优先级0为被动节点,不能成为活跃节点。优先级不位0则按照有大到小选出活跃节点。"arbiterOnly": 仲裁节点,只参与投票,不接收数据,也不能成为活跃节点。3.配置完成后,检查副本集配置信息和状态repl:PRIMARY> rs.isMaster(){ "hosts" : [ "localhost:27017", "localhost:27018", "localhost:27019" ], "setName" : "repl", "setVersion" : 1, "ismaster" : true, "secondary" : false, "primary" : "localhost:27017", "me" : "localhost:27017", "electionId" : ObjectId("7fffffff0000000000000001"), "lastWrite" : { "opTime" : { "ts" : Timestamp(1511500882, 1), "t" : NumberLong(1) }, "lastWriteDate" : ISODate("2017-11-24T05:21:22Z") }, "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "maxWriteBatchSize" : 1000, "localTime" : ISODate("2017-11-24T05:21:23.313Z"), "maxWireVersion" : 5, "minWireVersion" : 0, "readOnly" : false, "ok" : 1}repl:PRIMARY> rs.status(){ "set" : "repl", "date" : ISODate("2017-11-24T05:19:38.643Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) } }, "members" : [ { "_id" : 0, "name" : "localhost:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1041, "optime" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-11-24T05:19:32Z"), "electionTime" : Timestamp(1511500650, 1), "electionDate" : ISODate("2017-11-24T05:17:30Z"), "configVersion" : 1, "self" : true }, { "_id" : 1, "name" : "localhost:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 139, "optime" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-11-24T05:19:32Z"), "optimeDurableDate" : ISODate("2017-11-24T05:19:32Z"), "lastHeartbeat" : ISODate("2017-11-24T05:19:38.571Z"), "lastHeartbeatRecv" : ISODate("2017-11-24T05:19:37.703Z"), "pingMs" : NumberLong(0), "syncingTo" : "localhost:27017", "configVersion" : 1 }, { "_id" : 2, "name" : "localhost:27019", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 139, "optime" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1511500772, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-11-24T05:19:32Z"), "optimeDurableDate" : ISODate("2017-11-24T05:19:32Z"), "lastHeartbeat" : ISODate("2017-11-24T05:19:38.571Z"), "lastHeartbeatRecv" : ISODate("2017-11-24T05:19:37.730Z"), "pingMs" : NumberLong(0), "syncingTo" : "localhost:27018", "configVersion" : 1 } ], "ok" : 1}说明:setName:指明复制集的名称,本例中的取值是"rs1"。ismaster:指明当前连接的实例是否是primary角色。它是一个布尔类型:"true"说明此实例是primary角色,"false"说明此实例不是primary角色。secondary:指明当前连接的实例是否是slave角色。它是一个布尔类型:"true"说明此实例是slave角色,"false"说明此实例不是slave角色。hosts:指明Replica Sets各成员IP及端口信息。ok:表明复制集的状态。“1”说明状态正常,“0”说明状态异常。4.测试副本集(1)测试数据复制首先在主节点插入记录use dbwatcherfor (i = 5000; idb.users.insert({"i": i,"userName": "user" + i,"age": Math.floor(Math.random() * 120),"created": new Date(),total: Math.floor(Math.random() * 100) * i})}(2)检查复制状态repl:SECONDARY> db.printSlaveReplicationInfo()source: localhost:27018 syncedTo: Fri Nov 24 2017 13:37:30 GMT+0800 (CST) 0 secs (0 hrs) behind the primarysource: localhost:27019 syncedTo: Fri Nov 24 2017 13:37:32 GMT+0800 (CST) -2 secs (0 hrs) behind the primary (3)在从库节点上检查数据repl:SECONDARY> db.getCollectionNames()[ "users" ]repl:SECONDARY> db.users.find(){ "_id" : ObjectId("5a17b00210e7ebcda3d09c32"), "i" : 5000, "userName" : "user5000", "age" : 5, "created" : ISODate("2017-11-24T05:37:06.684Z"), "total" : 305000 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c33"), "i" : 5001, "userName" : "user5001", "age" : 31, "created" : ISODate("2017-11-24T05:37:06.715Z"), "total" : 355071 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c35"), "i" : 5003, "userName" : "user5003", "age" : 87, "created" : ISODate("2017-11-24T05:37:06.717Z"), "total" : 295177 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c36"), "i" : 5004, "userName" : "user5004", "age" : 52, "created" : ISODate("2017-11-24T05:37:06.717Z"), "total" : 75060 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c34"), "i" : 5002, "userName" : "user5002", "age" : 44, "created" : ISODate("2017-11-24T05:37:06.716Z"), "total" : 70028 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c38"), "i" : 5006, "userName" : "user5006", "age" : 53, "created" : ISODate("2017-11-24T05:37:06.718Z"), "total" : 440528 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c37"), "i" : 5005, "userName" : "user5005", "age" : 91, "created" : ISODate("2017-11-24T05:37:06.718Z"), "total" : 465465 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c39"), "i" : 5007, "userName" : "user5007", "age" : 104, "created" : ISODate("2017-11-24T05:37:06.719Z"), "total" : 45063 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c3a"), "i" : 5008, "userName" : "user5008", "age" : 1, "created" : ISODate("2017-11-24T05:37:06.719Z"), "total" : 310496 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c3e"), "i" : 5012, "userName" : "user5012", "age" : 102, "created" : ISODate("2017-11-24T05:37:06.727Z"), "total" : 210504 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c4a"), "i" : 5024, "userName" : "user5024", "age" : 43, "created" : ISODate("2017-11-24T05:37:06.732Z"), "total" : 85408 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c59"), "i" : 5039, "userName" : "user5039", "age" : 1, "created" : ISODate("2017-11-24T05:37:06.765Z"), "total" : 342652 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c58"), "i" : 5038, "userName" : "user5038", "age" : 14, "created" : ISODate("2017-11-24T05:37:06.764Z"), "total" : 20152 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c3f"), "i" : 5013, "userName" : "user5013", "age" : 42, "created" : ISODate("2017-11-24T05:37:06.727Z"), "total" : 170442 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c65"), "i" : 5051, "userName" : "user5051", "age" : 19, "created" : ISODate("2017-11-24T05:37:06.772Z"), "total" : 50510 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c4c"), "i" : 5026, "userName" : "user5026", "age" : 14, "created" : ISODate("2017-11-24T05:37:06.733Z"), "total" : 55286 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c62"), "i" : 5048, "userName" : "user5048", "age" : 25, "created" : ISODate("2017-11-24T05:37:06.770Z"), "total" : 479560 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c46"), "i" : 5020, "userName" : "user5020", "age" : 25, "created" : ISODate("2017-11-24T05:37:06.730Z"), "total" : 316260 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c49"), "i" : 5023, "userName" : "user5023", "age" : 59, "created" : ISODate("2017-11-24T05:37:06.731Z"), "total" : 421932 }{ "_id" : ObjectId("5a17b00210e7ebcda3d09c55"), "i" : 5035, "userName" : "user5035", "age" : 72, "created" : ISODate("2017-11-24T05:37:06.763Z"), "total" : 176225 }Type "it" for morerepl:SECONDARY> db.users.insert({username: "dbwatcher", age: 25})WriteResult({ "writeError" : { "code" : 10107, "errmsg" : "not master" } })repl:SECONDARY>---The END! 12-18 09:45