MongoDb 为什么用副本集

MongoDB的主从复制存在以下问题:

  • 主节点挂了能否自动切换连接?目前需要手工切换。
  • 主节点的读写压力过大如何解决?
  • 从节点每个上面的数据都是对数据库全量拷贝,从节点压力会不会过大?
  • 数据压力大到机器支撑不了的时候能否做到自动扩展?

因此,MongoDB设计了副本集和分片的功能

具体可理解为:

副本集合(Replica Sets),是一个基于主/从复制机制的复制功能,但增加了自动故障转移和恢复特性。一个集群最多可以支持7个服务器,并且任意节点都可以是主节点。所有的写操作都被分发到主节点,而读操作可以在任何节点上进行。

wKioL1NQzbSgSA34AAFQG8lb-7k273.jpg

由图可以看到客户端连接到整个副本集,不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写,副本集定期同步数据备份,一但主节点挂掉,副本节点就会选举一个新的主服务器,这一切对于应用服务器不需要关心。我们看一下主服务器挂掉后的架构:

wKiom1NQzd7BZ6yCAAFANLC22rU540.jpg

副本集中的副本节点在主节点挂掉后通过心跳机制检测到后,就会在集群内发起主节点的选举机制,自动选举一位新的主服务器。看起来很牛X的样子,我们赶紧操作部署一下!官方推荐的副本集机器数量为至少3个,那我们也按照这个数量配置测试。

例:我在同一台机器上的操作

cd mongod

 

方式一:

mkdir data/rs0-0 data/rs0-1 data/rs0-2

开启三个mongod进程,跟启普通的mongod进程基本相同,不同的跟了--replSet选项,rs0是该副本集的名称。

 

1. <strong><strong>#./bin/mongod --dbpath=data/rs0-1/ --logpath=log/rs0-1.log --port=37018 --bind_ip 10.8.8.162 --fork --replSet rs0
2. #./bin/mongod --dbpath=data/rs0-2/ --logpath=log/rs0-2.log --port=37019 --bind_ip 10.8.8.162 --fork --replSet rs0
3. #./bin/mongod --dbpath=data/rs0-0/ --logpath=log/rs0-0.log --port=37017 --bind_ip 10.8.8.162 --fork --replSet rs0</strong></strong>

然后我们用mongo shell连上端口为37017的mongod:

 

 

1. <strong><strong>#./bin/mongo --port 37017 --host 10.8.8.162</strong></strong>

设置副本集rs0

接着我们需要初始化一个Replica Set:首先创建一个副本集配置对象:

01. <strong><strong>&gt;  rsconf={"_id":"rs0","members":[{"_id":0,"host":"10.8.8.162:37017"}]}
02. {
03. "_id" "rs0",
04. "members" : [
05. {
06. "_id" : 0,
07. "host" "10.8.8.162:37017"
08. }
09. ]
10. }
11. &gt; rs.initiate(rsconf)  ###然后用rs.initiate()进程初始化###
12. {
13. "info" "Config now saved locally.  Should come online in about a minute.",
14. "ok" : 1
15. }
16. &gt; rs.status()##会发现37017这个端口的mongod进程默认就是PRIMARY##
17. {
18. "set" "rs0",
19. "date" : ISODate("2014-04-18T06:46:14Z"),
20. "myState" : 1,
21. "members" : [
22. {
23. "_id" : 0,
24. "name" "10.8.8.162:37017",
25. "health" : 1,
26. "state" : 1,
27. "stateStr" "PRIMARY",
28. "uptime" : 399,
29. "optime" : Timestamp(1397803396, 1),
30. "optimeDate" : ISODate("2014-04-18T06:43:16Z"),
31. "self" true
32. }
33. ],
34. "ok" : 1
35. }
36. rs0:PRIMARY&gt; rs.add("10.8.8.162:37018")##通过rs.add()将另外两个mongod添加到副本集当中##
37. "ok" : 1 }
38. rs0:PRIMARY&gt; rs.add("10.8.8.162:37019")
39. "ok" : 1 }
40. rs0:PRIMARY&gt; rs.status()##这个可能需要几分钟才能看见##
41. {
42. "set" "rs0",
43. "date" : ISODate("2014-04-18T06:51:50Z"),
44. "myState" : 1,
45. "members" : [
46. {
47. "_id" : 0,
48. "name" "10.8.8.162:37017",
49. "health" : 1,##1表明状态正常,0表示不正常##
50. "state" : 1,##1表示PRIMARY,2表示SECONDARY##
51. "stateStr" "PRIMARY",
52. "uptime" : 735,
53. "optime" : Timestamp(1397803597, 1),
54. "optimeDate" : ISODate("2014-04-18T06:46:37Z"),
55. "self" true
56. },
57. {
58. "_id" : 1,
59. "name" "10.8.8.162:37018",
60. "health" : 1,
61. "state" : 2,
62. "stateStr" "SECONDARY",
63. "uptime" : 318,
64. "optime" : Timestamp(1397803597, 1),
65. "optimeDate" : ISODate("2014-04-18T06:46:37Z"),
66. "lastHeartbeat" : ISODate("2014-04-18T06:51:49Z"),
67. "lastHeartbeatRecv" : ISODate("2014-04-18T06:51:50Z"),
68. "pingMs" : 0,
69. "syncingTo" "10.8.8.162:37017"
70. },
71. {
72. "_id" : 2,
73. "name" "10.8.8.162:37019",
74. "health" : 1,
75. "state" : 2,
76. "stateStr" "SECONDARY",
77. "uptime" : 313,
78. "optime" : Timestamp(1397803597, 1),
79. "optimeDate" : ISODate("2014-04-18T06:46:37Z"),
80. "lastHeartbeat" : ISODate("2014-04-18T06:51:49Z"),
81. "lastHeartbeatRecv" : ISODate("2014-04-18T06:51:49Z"),
82. "pingMs" : 0,
83. "syncingTo" "10.8.8.162:37017"
84. }
85. ],
86. "ok" : 1
87. }</strong></strong>

在两个SECONDARY节点上

 

1. <strong><strong>#./bin/mongo --port 37018 --host 10.8.8.162
2. MongoDB shell version: 2.4.5
3. connecting to: 10.8.8.162:37018/test
4. rs0:SECONDARY&gt; rs.status();
5. #./bin/mongo --port 37019 --host 10.8.8.162
6. MongoDB shell version: 2.4.5
7. connecting to: 10.8.8.162:37019/test
8. rs0:SECONDARY&gt; rs.status();</strong></strong>

 

方式二

01. <strong><strong>#./bin/mongod --dbpath=data/rs0-0/ --logpath=log/rs0-0.log --bind_ip 10.8.8.162 --fork --rest --logappend --replSet rs0 --port=30000
02. ##注:--rest是为了打开web监控。http://10.8.8.162:31000/_replSet可以查看各个节点的状态
03. #./bin/mongod --dbpath=data/rs0-1/ --logpath=log/rs0-1.log --bind_ip 10.8.8.162 --fork --rest --logappend --replSet rs0 --port=30001
04. #./bin/mongod --dbpath=data/rs0-2/ --logpath=log/rs0-2.log --bind_ip 10.8.8.162 --fork --rest --logappend --replSet rs0 --port=30002
05. #./bin/mongod --dbpath=data/rs0-arb/ --logpath=log/rs0-arb.log --bind_ip 10.8.8.162 --fork --rest --logappend --replSet rs0 --port=40000
06. #./bin/mongo --port 30000 --host 10.8.8.162
07. MongoDB shell version: 2.4.5
08. connecting to: 10.8.8.162:30000/test
09. &gt; rs.conf()
10. null
11. &gt; use admin
12. switched to db admin
13. &gt; db.runCommand({"replSetInitiate" : {
14. ...  "_id":"rs0",##这个键指明了副本集的名称,必须与气动mongod进程时指定的名称一致!##
15. ...  "members":[ ##这个键指明服务器列表,我们以后还可以往副本集中加入服务器##
16. ... {"_id":0,"host":"10.8.8.162:30000","priority":2},##“id”内嵌文档的键,用于唯一标示副本集中的某一台服务器."priority :N,优先级,指明一个服务器的优先级,默认为1,可以是[0,1000],通过这个我们可以指明副本集某台服务器节点初始为活跃节点"##
17. ... {"_id":1,"host":"10.8.8.162:30001","priority":3},
18. ... {"_id":2,"host":"10.8.8.162:30002","priority":4},
19. ... {"_id":3,"host":"10.8.8.162:40000","arbiterOnly":"true"}##arbiterOnly :true,仲裁节点,特定指明某个服务器节点为仲裁节点,仲裁节点不会复制数据,不会成为活跃节点,其存在的目的只有一个:当前活跃节点失效后,副本集内重新投票选活跃节点时,防止出现僵局!##
20. ... ]
21. ... }
22. ... }
23. ... );
24. {
25. "info" "Config now saved locally.  Should come online in about a minute.",
26. "ok" : 1
27. }
28. rs0:SECONDARY&gt; rs.status();##这个可能需要数分钟才能正常显示!##
29. {
30. "set" "rs0",
31. "date" : ISODate("2014-04-18T09:06:41Z"),
32. "myState" : 2,
33. "syncingTo" "10.8.8.162:30002",
34. "members" : [
35. {
36. "_id" : 0,
37. "name" "10.8.8.162:30000",
38. "health" : 1,
39. "state" : 2,
40. "stateStr" "SECONDARY",
41. "uptime" : 1411,
42. "optime" : Timestamp(1397811410, 1),
43. "optimeDate" : ISODate("2014-04-18T08:56:50Z"),
44. "self" true
45. },
46. {
47. "_id" : 1,
48. "name" "10.8.8.162:30001",
49. "health" : 1,
50. "state" : 2,
51. "stateStr" "SECONDARY",
52. "uptime" : 591,
53. "optime" : Timestamp(1397811410, 1),
54. "optimeDate" : ISODate("2014-04-18T08:56:50Z"),
55. "lastHeartbeat" : ISODate("2014-04-18T09:06:39Z"),
56. "lastHeartbeatRecv" : ISODate("2014-04-18T09:06:39Z"),
57. "pingMs" : 0,
58. "syncingTo" "10.8.8.162:30002"
59. },
60. {
61. "_id" : 2,
62. "name" "10.8.8.162:30002",
63. "health" : 1,
64. "state" : 1,
65. "stateStr" "PRIMARY",
66. "uptime" : 591,
67. "optime" : Timestamp(1397811410, 1),
68. "optimeDate" : ISODate("2014-04-18T08:56:50Z"),
69. "lastHeartbeat" : ISODate("2014-04-18T09:06:40Z"),
70. "lastHeartbeatRecv" : ISODate("2014-04-18T09:06:39Z"),
71. "pingMs" : 0,
72. "syncingTo" "10.8.8.162:30000"##开始我觉得这里有些奇怪!当我用30002这个PRIMARY节点登陆之后再查看,显示就正常了!##
73. },
74. {
75. "_id" : 3,
76. "name" "10.8.8.162:40000",
77. "health" : 1,
78. "state" : 7,
79. "stateStr" "ARBITER",
80. "uptime" : 562,
81. "lastHeartbeat" : ISODate("2014-04-18T09:06:40Z"),
82. "lastHeartbeatRecv" : ISODate("2014-04-18T09:06:40Z"),
83. "pingMs" : 0
84. }
85. ],
86. "ok" : 1
87. }</strong></strong>

 

至此,Mongod的副本集rs0就做完了!

 

节点切换

kill掉37017端口的mongod进程

#./bin/mongo --port 37018 --host 10.8.8.162
MongoDB shell version: 2.4.5
connecting to: 10.8.8.162:37018/test
rs0:SECONDARY> rs.status();
#./bin/mongo --port 37018 --host 10.8.8.162###会发现37019端口的mongod进程变成了PRIMARY#
MongoDB shell version: 2.4.5
connecting to: 10.8.8.162:37018/test
rs0:PRIMARY> rs.status();

此时,在作为PRIMARY节点的37109进程上就可以查看数据!

再把37017端口的mongod进程启动

1. <strong><strong>#rm -fr data/rs0-0/*
2. #rm -fr log/rs0-0.log
3. #./bin/mongod --dbpath=data/rs0-0/ --logpath=log/rs0-0.log --port=37017 --bind_ip 10.8.8.162 --fork --replSet rs0</strong></strong>

会发现37019依然还是PRIMARY,而重启起来的37017就是SECONDARY

 

但,此时在PRIMARY节点上插入数据,在SECONDARY节点是不可以进行数据查看的!因为mongodb默认是从主节点读写数据的,副本节点上不允许读,需要设置副本节点可以读。

 

 

01. <strong><strong>#./bin/mongo --port 37017 --host 10.8.8.162
02. MongoDB shell version: 2.4.5
03. connecting to: 10.8.8.162:37017/test
04. rs0:SECONDARY&gt; show dbs##能够查看有哪些数据库##
05. local   8.07421875GB
06. test    0.203125GB
07. rs0:SECONDARY&gt; use test
08. switched to db test
09. rs0:SECONDARY&gt; show collections;##但是不能查看数据##
10. Fri Apr 18 15:35:55.525 JavaScript execution failed: error: { "$err" "not master and slaveOk=false""code" : 13435 } at src/mongo/shell/query.js:L128
11. rs0:SECONDARY&gt; rs.slaveOk()##开启从库查询功能,或者用db.getMongo().setSlaveOk()##
12. rs0:SECONDARY&gt; show collections;
13. system.indexes
14. table1
15. rs0:SECONDARY&gt; db.table1.find()
16. "_id" : ObjectId("5350cbe620f384efd9ac5583"), "x" : 1 }
17. "_id" : ObjectId("5350d5b974b8eddf14724359"), "id" : 1, "name" "ycy" }
18. "_id" : ObjectId("5350d60174b8eddf1472435a"), "id" : 2, "name" "yu" }
19. rs0:SECONDARY&gt; db.table1.insert({"id":3,"age":26})##在SECONDARY节点上插入数据是不行的,看来是PRIMARY是读写、SECONDARY是只读##
20. not master</strong></strong>

增加、删除节点

1. <strong><strong>rs0:PRIMARY&gt; rs.remove("10.8.8.162:37017")##从副本集rs0中删除一个节点##
2. Fri Apr 18 16:22:49.591 DBClientCursor::init call() failed
3. Fri Apr 18 16:22:49.593 JavaScript execution failed: Error: error doing query: failed at src/mongo/shell/query.js:L78
4. Fri Apr 18 16:22:49.594 trying reconnect to 10.8.8.162:37019
5. Fri Apr 18 16:22:49.595 reconnect 10.8.8.162:37019 ok
6. rs0:PRIMARY&gt; rs.add("10.8.8.162:37017")##再把删除的节点添加进来##
7. "down" : [ "10.8.8.162:37017" ], "ok" : 1 }</strong></strong>

 

如果我想让300这个端口的Mongod进程升级为PRIMORY节点

1. <strong><strong>rs0:PRIMARY&gt; cfg=rs.conf()
2. rs0:PRIMARY&gt; cfg.members[0].priority = 5##设置“id”为“0”的节点,priority为5##
3. 5
4. rs0:PRIMARY&gt; rs.reconfig(cfg)
5. rs0:SECONDARY&gt; rs.conf()##查看配置文件,就会发现30001的priority变成5##
6. rs0:SECONDARY&gt; rs.status();##过几分钟再看,就会发现30001变成了PRIMARY节点##</strong></strong>

注:此操作必须在PROMARY节点上进行!

 

副本集(replica set)

 

MongoDB的replica set是一个mongod进程实例簇,数据在这个簇中相互复制,并自动进行故障切换。

MongoDB的数据库复制增加了冗余,确保了高可用性,简化了管理任务如备份,并且增加了读能力。大多数产品部署都使用了复制。MongoDB中primary处理写操作,其它进行复制的成员则是secondaries。

一个副本集可以最多支持12个成员,但是只有7个成员可以参与投票。

注:MongoDB同时提供了传统的master/slave复制,这种复制的操作方法与副本集相同,但是master/slave复制不支持自动故障切换。很容易理解,主备模式下,cli端是指定了地址和端口进行mongodb的访问的,而副本集模式则是通过访问mongos来隐藏动态切换的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值