MongoDB的数据复制和数据切片

MongoDB简介

MongoDB由C++开发,是NoSQL中比较接近关系型数据库的一种。MongoDB中的数据以类似于json的格式存储,性能非常优越,且支持大量的数据存储。但是MongoDB不支持事务性的操作,使得其适用场景受到限制。

MongoDB副本集

MongoDB的数据复制有两种类型:

1)master/slave

2)replica set

第一种为类似于MySQL的主从复制模型,第二种为副本集复制方式。现在主要应用的为副本集复制模型。结构图如下:

一个副本集即为服务于同一数据集的多个MongoDB实例,其中一个为主节点,其余的都为从节点。主节点上能够完成读写操作,从节点仅能用于读操作。主节点需要记录所有改变数据库状态的操作,这些记录保存在oplog中,这个文件存储在local数据库,各个从节点通过此oplog来复制数据并应用于本地,保持本地的数据与主节点的一致。oplog具有幂等性,即无论执行几次其结果一致,这个比mysql的二进制日志更好用。

集群中的各节点还会通过传递心跳信息来检测各自的健康状况。当主节点故障时,多个从节点会触发一次新的选举操作,并选举其中的一个成为新的主节点(通常谁的优先级更高,谁就是新的主节点),心跳信息默认每2秒传递一次。

实现过程

副本集的实现至少需要三个节点,且应该为奇数个节点,可以使用arbiter(仲裁节点)来参与选举。

实验环境:

主节点:192.168.1.132

从节点:192.168.1.139,192.168.1.140

1)安装配置MongoDB

在各个节点上安装MongoDB服务器端需要的rpm包(安装包的下载地址:http://downloads-distro.mongodb.org/repo/redhat/os/):

[[email protected] mongodb-2.6.5]# yum install -y mongodb-org-server-2.6.5-1.x86_64.rpm mongodb-org-tools-2.6.5-1.x86_64.rpm mongodb-org-shell-2.6.5-1.x86_64.rpm

配置文件信息:

[[email protected] ~]# vim /etc/mongod.conf 
logpath=/var/log/mongodb/mongod.log 
logappend=true 
fork=true
dbpath=/mongodb/data
pidfilepath=/var/run/mongodb/mongod.pid
bind_ip=0.0.0.0
httpinterface=true
rest=true
replSet=rs0
replIndexPrefetch = _id_only

replSet指定副本集的名称,这个至关重要,这个决定了对应的每一个节点加入的是哪一个副本集的集群。

replIndexPrefetch指定副本集的索引预取,如果有预取功能可以让复制过程更为高效,有3个值none,_id_only,all。none:不预取任何索引,_id_only:预取ID索引,all:预取所有索引。这个预取操作只能定义在从节点上。

在各节点上创建数据存放目录,然后启动服务:

[[email protected] ~]# mkdir -pv /mongodb/data
mkdir: created directory `/mongodb‘
mkdir: created directory `/mongodb/data‘
[[email protected] ~]# chown -R mongod.mongod /mongodb

[[email protected] ~]# service mongod start
Starting mongod:                                           [  OK  ]

2)配置集群的成员

查看集群信息(此时没有任何节点)

[[email protected] ~]# mongo --host 192.168.1.132
MongoDB shell version: 2.6.5
connecting to: 192.168.1.132:27017/test
> rs.status()
{
	"startupStatus" : 3,
	"info" : "run rs.initiate(...) if not yet done for the set",
	"ok" : 0,
	"errmsg" : "can‘t get local.system.replset config from self or any seed (EMPTYCONFIG)"
}

添加集群成员,首先配置cfg定义集群信息,然后执行rs.initiate(cfg)完成节点的添加。在定义集群时,需要指定每一个节点的属性信息,例如_id,host。还有很多属性字段,常见的有priority,votes,arbiterOnly.....  具体的信息可以参考官方网站http://docs.mongodb.org/manual/reference/command/replSetGetConfig/#replsetgetconfig-output。

> cfg={_id:‘rs0‘,members:[   
... ... {_id:0,host:‘192.168.1.132:27017‘},  
... ... {_id:1,host:‘192.168.1.139:27017‘},
... ... {_id:2,host:‘192.168.1.140:27017‘}]  
... ... }
{
	"_id" : "rs0",
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.1.132:27017"
		},
		{
			"_id" : 1,
			"host" : "192.168.1.139:27017"
		},
		{
			"_id" : 2,
			"host" : "192.168.1.140:27017"
		}
	]
}
#################################
> rs.initiate(cfg)
{
	"info" : "Config now saved locally.  Should come online in about a minute.",
	"ok" : 1
}

查看各节点的状态信息:

> rs.status()
{
	"set" : "rs0",
	"date" : ISODate("2015-09-04T23:02:13Z"),
	"myState" : 1,
	"members" : [                                                       #显示副本集的所有成员信息
		{
			"_id" : 0,                                          #节点的标识符
			"name" : "192.168.1.132:27017",                     #节点名称    
			"health" : 1,                                       #节点的健康状态            
			"state" : 1,                                                                                
			"stateStr" : "PRIMARY",                             #该节点为主节点                                
			"uptime" : 1750,                                    #运行时长                   
			"optime" : Timestamp(1441407002, 1),                #oplog最后一次操作的时间戳                                                     
			"optimeDate" : ISODate("2015-09-04T22:50:02Z"),     #oplog最后一次操作的时间                                
			"electionTime" : Timestamp(1441407011, 1),          #选举时间                       
			"electionDate" : ISODate("2015-09-04T22:50:11Z"),   #选举日期                                  
			"self" : true                                       #表示是否为当前节点
		},
		{
			"_id" : 1,
			"name" : "192.168.1.139:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",                            #从节点
			"uptime" : 730,
			"optime" : Timestamp(1441407002, 1),
			"optimeDate" : ISODate("2015-09-04T22:50:02Z"),
			"lastHeartbeat" : ISODate("2015-09-04T23:02:13Z"),
			"lastHeartbeatRecv" : ISODate("2015-09-04T23:02:12Z"),
			"pingMs" : 0,
			"syncingTo" : "192.168.1.132:27017"                  #指向的主节点
		},
		{
			"_id" : 2,
			"name" : "192.168.1.140:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 730,
			"optime" : Timestamp(1441407002, 1),
			"optimeDate" : ISODate("2015-09-04T22:50:02Z"),
			"lastHeartbeat" : ISODate("2015-09-04T23:02:13Z"),
			"lastHeartbeatRecv" : ISODate("2015-09-04T23:02:12Z"),
			"pingMs" : 0,
			"syncingTo" : "192.168.1.132:27017"
		}
	],
	"ok" : 1
}

在创建副本集时,有3种方式:

1、db.runCommand( { replSetInitiate : <config_object> } )

2、rs.initiate(<config_object>)

3、rs.initiate()      #先在其中一个节点上初始化,再通过rs.add添加另外的节点

这里采用的是第二种方式,<config_object>即为上述中的cfg文件,对该文件的修改使用replSetInitiate命令。

3)访问测试

在主节点上添加数据(192.168.1.132):

rs0:PRIMARY> use student_db
switched to db student_db
rs0:PRIMARY> for (i=1;i<=100000;i++) db.students.insert({name:"student"+i,age:(i%120),address:"china_nb"});
WriteResult({ "nInserted" : 1 })

此时在从节点上访问数据会报如下错误:

rs0:SECONDARY> use student_db
switched to db student_db
rs0:SECONDARY> db.students.findOne()
2015-09-04T19:28:10.730-0400 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:131

执行rs.slaveOk()后,数据才可读。

rs0:SECONDARY> rs.slaveOk()
rs0:SECONDARY> db.student.findOne()
null
rs0:SECONDARY> db.students.findOne()
{
	"_id" : ObjectId("55ea287ce476f31ac766a383"),
	"name" : "student1",
	"age" : 1,
	"address" : "china_nb"
}

当主节点故障时,从节点会重新投票选举出主节点,继续提供服务,避免单点故障。

主节点上关闭服务:

[[email protected] ~]# service mongod stop
Stopping mongod:                                           [  OK  ]

从节点上查看状态信息:

rs0:SECONDARY> rs.status()
{
	"set" : "rs0",
	"date" : ISODate("2015-09-04T23:31:49Z"),
	"myState" : 1,
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.1.132:27017",
			"health" : 0,                       #主节点已经下线
			"state" : 8,
			"stateStr" : "(not reachable/healthy)",
                         ................
		},
		{
			"_id" : 1,
			"name" : "192.168.1.139:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",              #新选出的主节点
			............
		},
		{
			"_id" : 2,
			"name" : "192.168.1.140:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			.........
		}
	],
	"ok" : 1
}

可以看到原来的主节点已经下线(health为0),重新选举的主节点为192.168.1.139。可以通过rs.isMaster()查看当前节点是否为主节点。

4)添加一个从节点

数据库运行一段时间后,可能需要再次添加节点来分散压力。通过rs.add命令添加从节点。添加完成后,该节点需要和主节点同步数据,同步过程有3个步骤:

1、初始同步(initial sync)

2、回滚后追赶(post-rollback catch-up)

3、切分块迁移(sharding chunk migrations)

添加从节点(在主节点上):

rs0:PRIMARY> rs.add("192.168.1.138")
{ "ok" : 1 }

查看状态:

{
	"_id" : 2,
	"name" : "192.168.1.127:27017",
	"health" : 1,
        .....................
	"lastHeartbeatMessage" : "still initializing"        #正在初始化
}
#######################
{
	"_id" : 1,
	"name" : "192.168.1.138:27017",
	"health" : 1,
        ........
	"lastHeartbeatMessage" : "initial sync need a member to be primary or secondary to do our initial sync"    #同步数据
}
#######################
{
	"_id" : 1,
	"name" : "192.168.1.138:27017",
	"health" : 1,
        ........
	"syncingTo" : "node1.xiaoxiao.com:27017"                 #同步完成
}

执行rs.slaveOk()后,即可实现访问。

5)更改某个节点的优先级

若某个从节点的硬件配置不错,可以对应的调高其优先级,使其在选举过程中能够优先被选举为主节点。例如设置第3个节点的优先级为2(默认均为1),过程如下:

rs0:PRIMARY> cfg=rs.conf()
rs0:PRIMARY> cfg.members[2].priority=2        #节点的标识符为2
rs0:PRIMARY> rs.reconfig(cfg)                 #更新配置
################
rs0:SECONDARY> rs.config()   
{
                ................
		{
			"_id" : 2,
			"host" : "192.168.1.140:27017",
			"priority" : 2        #对应优先级
		}
	]
}

此时会立刻进行选举,优先级最高的为主节点,如下图所示:

MongoDB数据分片

时间: 2024-11-05 11:44:00

MongoDB的数据复制和数据切片的相关文章

MongoShake——基于MongoDB的跨数据中心的数据复制平台

摘要: MongoShake是基于MongoDB的通用型平台服务,作为数据连通的桥梁,打通各个闭环节点的通道.通过MongoShake的订阅消费,可以灵活对接以适应不同场景,例如日志订阅.数据中心同步.监控审计等.其中,集群数据同步作为核心应用场景,能够灵活实现灾备和多活的业务场景. 背景 在当前的数据库系统生态中,大部分系统都支持多个节点实例间的数据同步机制,如Mysql Master/Slave主从同步,Redis AOF主从同步等,MongoDB更是支持3节点及以上的副本集同步,上述机制很

mongodb 将一个列的数据复制到其他列上

db.memberEntity.find().forEach(function(item){ db.memberEntity.update({"_id":item._id}, {"$set": {"create_time":item.registrationTime}},false,true) }) 这里是将注册的数据复制到创建时间字段上 db.memberEntity.update({"_id":"303eeead

Windows Server2016 安装及配置DFS实现数据复制

我们今天主要介绍的是Windows Server2016 安装及配置DFS实现数据复制,那什么是DFS呢?DFS就是Microsoft文件分布系统  是一个网络服务器组件,它能够使你更容易地在网络上查询和管理数据.分布式文件系统是将分布于不同电脑上的文件组合为单一的名称空间,并使得在网络上建立一个单一的.层次化多重文件服务器和服务器共享的工作更为方便的途径,使用户更加容易访问和管理物理上跨网络分布的文件.DFS为文件系统提供了单个访问点和一个逻辑树结构,通过DFS,用户在访问文件时不需要知道它们

【IPC进程间通信之四】数据复制消息WM_COPYDATA

IPC进程间通信+数据复制消息WM_COPYDATA         IPC(Inter-Process Communication,进程间通信).         数据复制消息WM_COPYDATA是Windows中一个特殊的消息,通过这个消息能够在进程间传递数据.        1.WM_COPYDATA:         WM_COPYDATA消息含两个參数WPARAM wParam和LPARAM  lParam.WPARAM和LPARAM是匈牙利命名法,历史更迭,WPARAM指32位整形

集合数据复制问题

将一个List中的数据复制到另一个List中去,List有一个专门的方法: boolean java.util.List.addAll(Collection 版权声明:本文为博主原创文章,未经博主允许不得转载.

GoldenGate V11.1数据复制限制

以下对goldengate数据复制的限制情况进行说明. 不支持文件等非结构化数据复制 GoldenGate依赖对于数据库日志的解析获取数据变化,因此只能支持数据库中的数据变化复制,无法支持文件等非结构化数据的复制. Oracle数据类型限制 GoldenGate支持Oralce常见数据类型的复制. GoldenGate不支持的数据类型 1)         ANYDATA 2)         ANYDATASET 3)         ANYTYPE 4)         BFILE 5)  

串口摄像头得到了一张图像的JPEG数据,我把这些数据复制到txt文档了,想将这些数据变为图像

从串口摄像头得到了一张图像的JPEG数据,我把这些数据复制到txt文档了,想将这些数据变为图像,在VC++中应该怎么做呢?看了一 些资料,有人说直接保存成jpg格式,于是我把文件名的后缀.txt改成了.jpg,但打开时显示“没有预览”.我在VC++中执行了以下程序: FILE *pFile=fopen("tst.txt","rb");//tst.txt为JPEG数据 char *pBuf; fseek(pFile,0,SEEK_END); int len=ftell

GOLDENGATE安装与数据复制流搭建配置_不含DDL抽取版

GOLDENGATE安装与数据复制流搭建配置 (源库为实例,支持ASM,不含DDL抽取版) 1.配置场景 2.OGG软件安装 2.1 源端和目标端创建OGG安装目录与授权 #mkdir /u01/ogg #chown –R oracle:oinstall/u01/ogg #chmod –R 777/u01/ogg 2.2 源端和目标端配置环境变量 #su – oracle [[email protected]~]$ vi.bash_profile 添加以下内容: export OGG=/u01/

SqlServer将表中数据复制到另一张表

insert into phone2(ph,attr,type,carrier) select top 1000 ph,attr,type,carrier from phone 将表phone的字段和前1000条数据复制到Phone2表 数据库中的某个表删除重复数据(phone2表不能存在) select distinct  * into phone2 from phone 表phone的数据放到phone2中(phone2表可以存在) insert into phone2(ph,attr,ty