第五部分 架构篇 第十五章 MongoDB Replica Sets 架构(动态增加删除结点)

1、Replica Set增加结点

MongoDB Replica Set不仅提供高可用性的解决方案,它也同时提供负载均衡的解决方案,增减Replica Sets结点在实际应用中非常普遍,比如当应用的读压力暴增时,3台结点的环境已经不能满足需求,那么就需要增加一些结点将压力平均分配一下,当应用的压力小时,可以减少一些结点来减少硬件资源的成本,总是是一个长期且持续的工作。

官方给我们提供了2个方案用于增加结点,一种是通过oplog来增加结点,一种是通过数据库快照(--fastsync)和oplog来增加结点,下面分别介绍:

1.1、通过oplog增加节点

配置并启动新节点,启动28010这个端口给新的节点:

[[email protected] bin]# ./mongod --replSet rs1 --keyFile=/usr/local/mongodb/key/r0 --fork --port 28010 --dbpath=/usr/local/mongodb/r0 --logpath=/usr/local/mongodb/log/r0.log --logappend
about to fork child process, waiting until server is ready for connections.
forked process: 41554
child process started successfully, parent exiting
[[email protected] bin]# ./mongo --port 28011
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28011/test
rs1:PRIMARY> rs.add("localhost:28010");
{ "down" : [ "localhost:28010" ], "ok" : 1 }

进行初始化:

rs1:PRIMARY> rs.status();
{
        "set" : "rs1",
        "date" : ISODate("2015-01-16T04:08:02Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 1,
                        "name" : "localhost:28011",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 3695,
                        "optime" : Timestamp(1421381275, 1),
                        "optimeDate" : ISODate("2015-01-16T04:07:55Z"),
                        "electionTime" : Timestamp(1421379114, 1),
                        "electionDate" : ISODate("2015-01-16T03:31:54Z"),
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:28012",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 326,
                        "optime" : Timestamp(1421381275, 1),
                        "optimeDate" : ISODate("2015-01-16T04:07:55Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T04:08:00Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T04:08:00Z"),
                        "pingMs" : 0,
                        "syncingTo" : "localhost:28011"
                },
                {
                        "_id" : 3,
                        "name" : "localhost:28010",
                        "health" : 1,
                        "state" : 6,
                        "stateStr" : "UNKNOWN",
                        "uptime" : 7,
                        "optime" : Timestamp(0, 0),
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T04:08:01Z"),
                        "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
                        "pingMs" : 4,
                        "lastHeartbeatMessage" : "still initializing"
                }
        ],
        "ok" : 1
}

初始化同步完成:

rs1:PRIMARY> rs.status();
{
        "set" : "rs1",
        "date" : ISODate("2015-01-16T04:08:36Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 1,
                        "name" : "localhost:28011",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 3729,
                        "optime" : Timestamp(1421381275, 1),
                        "optimeDate" : ISODate("2015-01-16T04:07:55Z"),
                        "electionTime" : Timestamp(1421379114, 1),
                        "electionDate" : ISODate("2015-01-16T03:31:54Z"),
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:28012",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 360,
                        "optime" : Timestamp(1421381275, 1),
                        "optimeDate" : ISODate("2015-01-16T04:07:55Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T04:08:36Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T04:08:36Z"),
                        "pingMs" : 0,
                        "syncingTo" : "localhost:28011"
                },
                {
                        "_id" : 3,
                        "name" : "localhost:28010",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 41,
                        "optime" : Timestamp(1421381275, 1),
                        "optimeDate" : ISODate("2015-01-16T04:07:55Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T04:08:35Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T04:08:35Z"),
                        "pingMs" : 0,
                        "syncingTo" : "localhost:28011"
                }
        ],
        "ok" : 1
}

验证数据同步:

[[email protected] bin]# ./mongo --port 28010
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28010/test
rs1:SECONDARY> show collections
2015-01-16T12:11:06.299+0800 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:131
rs1:SECONDARY> rs.slaveOK();
2015-01-16T12:11:12.135+0800 TypeError: Object function () { return "try rs.help()"; } has no method 'slaveOK'
rs1:SECONDARY> db.getMongo().setSlaveOk();
rs1:SECONDARY> show collections;
student
system.indexes
rs1:SECONDARY> db.student.find();
{ "_id" : ObjectId("54b883fb7bd891605d9c300f"), "name" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("54b8876aad5e04c1fe460154"), "name" : "lisi", "age" : 20 }
rs1:SECONDARY> 

数据已经同步过来了。

1.2、数据库快照和oplog添加节点

通过oplog直接进行增加节点操作简单且无需人工干预过多,但oplog是capped collection采用循环的方式进行处理,所以采用oplog的方式进行增加节点,有可能导致数据不一致,因为日志中存储的信息有可能已经刷新过了,不过没有关系,我们可以通过数据库快照(--fastsync)和oplog集合的方式来增加节点,这种方式的操作流程是,先取某一个复制集成员的物理文件作为初始化数据,然后剩下的部分用oplog日志来追,最终达到数据一致性。

首先来删除之前添加的28010服务:

rs1:PRIMARY> rs.remove("localhost:28010");
2015-01-16T14:40:31.529+0800 DBClientCursor::init call() failed
2015-01-16T14:40:31.546+0800 Error: error doing query: failed at src/mongo/shell/query.js:81
2015-01-16T14:40:31.547+0800 trying reconnect to 127.0.0.1:28011 (127.0.0.1) failed
2015-01-16T14:40:31.549+0800 reconnect 127.0.0.1:28011 (127.0.0.1) ok
rs1:PRIMARY> rs.status();
{
        "set" : "rs1",
        "date" : ISODate("2015-01-16T06:40:36Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 1,
                        "name" : "localhost:28011",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 12849,
                        "optime" : Timestamp(1421390431, 1),
                        "optimeDate" : ISODate("2015-01-16T06:40:31Z"),
                        "electionTime" : Timestamp(1421379114, 1),
                        "electionDate" : ISODate("2015-01-16T03:31:54Z"),
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:28012",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 5,
                        "optime" : Timestamp(1421390431, 1),
                        "optimeDate" : ISODate("2015-01-16T06:40:31Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T06:40:35Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T06:40:34Z"),
                        "pingMs" : 0,
                        "lastHeartbeatMessage" : "syncing to: localhost:28011",
                        "syncingTo" : "localhost:28011"
                }
        ],
        "ok" : 1
}

取某一个复制集成员的物理文件来做初始化数据

[[email protected] mongodb]# echo "this is rs1 super secret key">key/r4
[[email protected] mongodb]# chmod 600 key/r4
[[email protected] mongodb]# 
[[email protected] mongodb]# scp -r r0 r3
[[email protected] mongodb]# ll
total 88
drwxr-xr-x. 2 root root  4096 Jan 16 10:19 bin
-rw-r--r--. 1 1046 1046 34520 Dec  9 07:30 GNU-AGPL-3.0
drwxr-xr-x. 2 root root  4096 Jan 16 10:27 key
drwxr-xr-x. 2 root root  4096 Jan 16 11:10 log
drwxr-xr-x. 4 root root  4096 Jan 16 12:07 r0
drwxr-xr-x. 4 root root  4096 Jan 16 11:22 r1
drwxr-xr-x. 4 root root  4096 Jan 16 11:22 r2
drwxr-xr-x. 4 root root  4096 Jan 16 14:41 r3
-rw-r--r--. 1 1046 1046  1359 Dec  9 07:30 README
-rw-r--r--. 1 1046 1046 17793 Dec  9 07:30 THIRD-PARTY-NOTICES
[[email protected] mongodb]# 

在取完物理文件后,在student集中插入一条新文档,用于最后验证此更新也同步了。

[[email protected] bin]# ./mongo --port 28011
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28011/test
rs1:PRIMARY> db.student.find();
{ "_id" : ObjectId("54b883fb7bd891605d9c300f"), "name" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("54b8876aad5e04c1fe460154"), "name" : "lisi", "age" : 20 }
rs1:PRIMARY> db.student.insert({name:"wangwu",age:30});
WriteResult({ "nInserted" : 1 })

还是启动28013这个端口给新的节点:

[[email protected] bin]# ./mongod --replSet rs1 --keyFile=/usr/local/mongodb/key/r3 --fork --port 28013 --dbpath=/usr/local/mongodb/r3 --logpath=/usr/local/mongodb/log/r3.log --logappend --fastsync
about to fork child process, waiting until server is ready for connections.
forked process: 49910
child process started successfully, parent exiting
[[email protected] bin]#

添加28013节点:

[[email protected] bin]# ./mongo --port 28011
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28011/test
rs1:PRIMARY> rs.add("localhost:28013");
{ "ok" : 1 }
rs1:PRIMARY> 

验证数据同步:

[[email protected] bin]# ./mongo --port 28013
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28013/test
rs1:SECONDARY> db.getMongo().setSlaveOk();
rs1:SECONDARY> db.student.find();
{ "_id" : ObjectId("54b883fb7bd891605d9c300f"), "name" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("54b8876aad5e04c1fe460154"), "name" : "lisi", "age" : 20 }
{ "_id" : ObjectId("54b8b2fe33612049e088be9a"), "name" : "wangwu", "age" : 30 }
rs1:SECONDARY> 

至此,基于两种方式添加节点完成。

2、Relica Set减少节点

下面将节点28010从复制集当中去除掉,只需要执行rs.remove指令就可以了,具体如下:

[[email protected] bin]# ./mongo --port 28010
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28010/test
rs1:SECONDARY> rs.status();
{
        "set" : "rs1",
        "date" : ISODate("2015-01-16T03:57:41Z"),
        "myState" : 2,
        "syncingTo" : "localhost:28011",
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:28010",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 13,
                        "optime" : Timestamp(1421379434, 1),
                        "optimeDate" : ISODate("2015-01-16T03:37:14Z"),
                        "infoMessage" : "syncing to: localhost:28011",
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "localhost:28011",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 13,
                        "optime" : Timestamp(1421379434, 1),
                        "optimeDate" : ISODate("2015-01-16T03:37:14Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T03:57:40Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T03:57:40Z"),
                        "pingMs" : 0,
                        "electionTime" : Timestamp(1421379114, 1),
                        "electionDate" : ISODate("2015-01-16T03:31:54Z")
                },
                {
                        "_id" : 2,
                        "name" : "localhost:28012",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 13,
                        "optime" : Timestamp(1421379434, 1),
                        "optimeDate" : ISODate("2015-01-16T03:37:14Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T03:57:40Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T03:57:40Z"),
                        "pingMs" : 0,
                        "syncingTo" : "localhost:28011"
                }
        ],
        "ok" : 1
}
rs1:SECONDARY> 

将端口28010的节点删除:

rs1:SECONDARY> rs.remove("localhost:28010");
{
        "ok" : 0,
        "errmsg" : "replSetReconfig command must be sent to the current replica set primary."
}
rs1:SECONDARY> 

上述提示在SECONDARY节点不能进行删除节点操作,必须在PRIMARY节点上进行。

[[email protected] bin]# ./mongo --port 28011
MongoDB shell version: 2.6.6
connecting to: 127.0.0.1:28011/test
rs1:PRIMARY> rs.remove("localhost:28010");
2015-01-16T12:02:37.374+0800 DBClientCursor::init call() failed
2015-01-16T12:02:37.383+0800 Error: error doing query: failed at src/mongo/shell/query.js:81
2015-01-16T12:02:37.385+0800 trying reconnect to 127.0.0.1:28011 (127.0.0.1) failed
2015-01-16T12:02:37.385+0800 reconnect 127.0.0.1:28011 (127.0.0.1) ok
rs1:PRIMARY> rs.status();
{
        "set" : "rs1",
        "date" : ISODate("2015-01-16T04:04:28Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 1,
                        "name" : "localhost:28011",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 3481,
                        "optime" : Timestamp(1421380955, 1),
                        "optimeDate" : ISODate("2015-01-16T04:02:35Z"),
                        "electionTime" : Timestamp(1421379114, 1),
                        "electionDate" : ISODate("2015-01-16T03:31:54Z"),
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:28012",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 112,
                        "optime" : Timestamp(1421380955, 1),
                        "optimeDate" : ISODate("2015-01-16T04:02:35Z"),
                        "lastHeartbeat" : ISODate("2015-01-16T04:04:28Z"),
                        "lastHeartbeatRecv" : ISODate("2015-01-16T04:04:28Z"),
                        "pingMs" : 0,
                        "lastHeartbeatMessage" : "syncing to: localhost:28011",
                        "syncingTo" : "localhost:28011"
                }
        ],
        "ok" : 1
}
rs1:PRIMARY> 

此时服务28010的已经被删除掉。

时间: 2024-10-10 12:47:58

第五部分 架构篇 第十五章 MongoDB Replica Sets 架构(动态增加删除结点)的相关文章

第五部分 架构篇 第十四章 MongoDB Replica Sets 架构(自动故障转移/读写分离实践)

说明:该篇内容部分来自红丸编写的MongoDB实战文章. 1.简介 MongoDB支持在多个机器中通过异步复制达到故障转移和实现冗余,多机器中同一时刻只有一台是用于写操作,正是由于这个情况,为了MongoDB提供了数据一致性的保障,担当primary角色的服务能把读操作分发给Slave(详情请看前两篇关于Replica Set成员组成和理解). MongoDB高可用分为两种: Master-Slave主从复制:只需要在某一个服务启动时加上-master参数,而另外一个服务加上-slave与-so

第五部分 架构篇 第十二章 MongoDB Replica Sets 架构(简介)

1.Replication简介 MongoDB Replication即是在多个服务器中同步复制数据,数据复制的目的为提供冗余和提高数据的可用性,数据复制的操作即在不同的数据库服务器上保存多份复制的数据集,以此来避免单机故障进而丢失数据,复制机制也允许你恢复硬件故障和服务中断,进而起到数据的容灾和备份作用. 在MongoDB中,一个复制集就是一组mongod实例,一个mongod实例作为primary也就是所谓的master服务,接收所有的写操作,其他的mongod实例作为secondaries

第五部分 架构篇 第十三章 MongoDB Replica Sets 架构(成员深入理解)

在学习复制的概念之前,首先接着前面一章节的还有点未完结的内容做个简单的介绍,主要是自动故障转移.异步复制.以及附加功能,这些在此只做简单的介绍,在以后的相关章节中会专门深入学习. 1.自动故障转移 当Primary服务和架构中其他成员中断通信超过10秒,Replica Set将尝试选举其他成员成为一个新的Primary服务,获得多票数的Scondary将成为Primary. 架构如下: 说明: 在一个Replica Set架构中,如果Primary不可达,则会在除Primary之外的其他成员中自

第五部分 架构篇 第十九章 MongoDB Sharding 架构( mongos)

1.mongos mongos是用户和集群间的交互点,其职责是隐藏分片内部的复杂性并向用户提供一个简洁的单服务器接口,这个抽象层中也存在一些缝隙,不过大多数情况下mongos允许你把一个集群当做一台服务器. 使用集群时,应该连接一个mongos并向它发送所有的读写操作,无论如何,你都不应该直接访问分片(但如果想的话能做到). mongos会将所有用户请求转发到恰当的分片上,如果用户插入一份文档,mongos会查看文档的片键,对照数据块,并把文档发送到持有相应块的分片上. 举个例子,比如说我们要插

第五部分 架构篇 第十六章 MongoDB Sharding 架构(理解分片)

1.简介 这是一种将海量的数据水平扩展的数据库集群系统,数据分表存储在sharding的各个节点上,使用者通过简单的配置就可以很方便地构建一个分布式的MongoDB集群. 那么首先我们应该理解何为分片(sharding)以及它的基本工作模式. 2.什么是分片 分片(sharding)是MongoDB用来将大型集合分割到不同服务器(或者说一个集群)上所采用的方法,尽管分片起源于关系型数据库分区,但它(像MongoDB大部分方面一样)完全是另外一回事. 和你可能使用过的任何分区方案相比,MongoD

第五部分 架构篇 第十八章 MongoDB Sharding 架构(平衡)

1.平衡简介 如果存在多个可用的分片,只要块得数量足够多,MongoDB就会把数据迁移到其他分片上,这个迁移过程叫做平衡(balancing),由叫做平衡器(balancer)的进程负责执行. 2.平衡工作流程 平衡器会把数据块从一个分片挪到另外一个分片上,其优点在于自动化,即你无需担心如何保持数据在分片间的均匀分布,这项工作已经由平衡器替你搞定,不过这也是它的缺点,因为自动意味着如果你不喜欢塔做负载均衡的方式,那只能算你不走运,如果不想让某个块存在于分片3上,你可以手动移动到分片2上,但是平衡

linux架构学习第二十五天HTTP协议详解

内容: 1.http协议概述 2.http协议特点 3.http的工作模式(过程) 4.http请求报文.响应报文格式.常见状态码解析 5.web资源概述(静态资源.动态资源) 1.http协议概述 http协议工作在TCP/IP模型的应用层,其定义web服务间通信的约定通信方式,HTTP基于tcp传送数据,默认是80端口(服务器端) 几个名词: http:hyper text transfer protocol,超文本传输协议,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(

【Android的从零单排开发日记】之入门篇(十五)——TextView+SpannableStringBuilder

TextView是控件中最最基础的一个控件,也是最简单的一个控件.但如果仅此,我不会专门为TextView写一篇文章.最近发现了Android中有趣的一个类,那就是标题上写的SpannableStringBuilder.那么它是个什么东西呢?它可以为你的文字加上各种效果,像变色,各种符号,斜体,图片替换,高亮等等.如果想要文字加上一点常见的效果,我们大可不必再自己去写一个自定义的View,使用SpannableStringBuilder就能满足你的需求了. 一.TextView 首先是TextV

IOS开发——UI进阶篇(十五)Quartz2D介绍

一.Quartz2D简介 1.什么是Quartz2DQuartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作绘制图形 : 线条\三角形\矩形\圆\弧等绘制文字绘制\生成图片(图像)读取\生成PDF截图\裁剪图片自定义UI控件 2.Quartz2D实例Quartz 2D能做很多强大的事情,例如 裁剪图片 涂鸦\画板 手势解锁 报表:折线图\饼状图\柱状图 二.自定义view 1.Quartz2D在iOS开发中的价值为了便于搭建美观的UI界面,iOS提供了UI