MongoDB副本集复制和分片
来源:互联网 发布:全国网络110报案中心 编辑:程序博客网 时间:2024/06/16 08:39
MongoDB是一个开源非关系文档型数据库。在MongoDB中的每一个记录是一个文档,文档类似于JSON对象,它是一个由字段和值对组成的数据结构。
类似json的文档存储
MongoDB出现解决了传统关系型数据库对海量数据的处理难题。以传统的MySQL为代表的关系型数据库,事务保证操作和数据的可靠性,但同时也限制了数据的扩展性和数据库海量数据的处理能力。MongoDB的数据库不支持事务,这使它突破了关系型数据库的局限性,得到了良好的扩展性。在实现上MongoDB借鉴了MySQL,在操作方式上和工作模式与MySQL类似。
以下通过MongoDB副本集复制和分片
,认识其对海量数据的处理和其原理:
MongoDB副本集复制
MongoDB在数据冗余方面提供了两种方案:
master/slave
主从复制replica set
副本集复制
master/slave
是和MySQL类似的一种复制方式,master端启动一个I/O线程用于向slave端同步写日志文件,slave端启动两个线程,一个IO线程把日志文件记录在slave节点的中继日志中,SQL线程把中继日志进行回放完成备份,只是MySQL中的binlog
在MongoDB叫做OpLog
日志文件。
这种复制方式最大的弊端在于:主节点成为最大的单点所在,可能有人会说,给主节点做高可用,随之而来是就是一堆问题:
- 两个主节点数据不应该也一样吗?两个主节点又互为单点所在
- 当主节点A的宕机,A中的事务没有执行完,B中的数据怎么回滚?双主节点事务难以同步
可以看出,事务在某些不必要的场景,反而带来很多问题,于是MongoDB摆脱了事务的限制,提出了第二种方式replica set
:
副本集复制过程
工作方式如下:
在MongoDB中一个副本集即为服务于同一数据集的多个MongoDB实例,其中一个为主节点Primary
,其余的都为从节点Secondary
(主节点上能够完成读写操作,从节点仅能用于读操作)。主节点记录所有改变数据库状态的操作,将这些记录保存在oplog中,oplog存储在local数据库,各个从节点通过此oplog来复制数据并应用于本地,保持本地的数据与主节点的一致。oplog具有幂等性(无论执行几次其结果一致),比mysql的二进制日志更高效可靠。
集群中的各节点通过传递心跳信息(默认每2秒传递一次)来检测各自的健康状况。当主节点故障时多个从节点会触发一次新的选举操作,并选举其中的一个成为新的主节点(通常谁的优先级更高,谁就是新的主节点)。
各个从节点传递心跳
没有事务的限制,当主节点宕机时,每个从节点都可以作为主节点。
实例
实验环境
其配置较为简单,分为以下几个步骤:
安装配置MongoDB服务器端和客户端
yum install -y mongodb-server mongodb
配置文件信息:
[root@mongo1 ~]# vim /etc/mongod.conf logpath=/var/log/mongodb/mongod.log logappend=true fork=truedbpath=/data/mongodbpidfilepath=/var/run/mongodb/mongod.pidbind_ip=0.0.0.0 # 服务监听的地址httpinterface=truerest=truereplSet=rs0 # 指定了副本集名称,多个副本集用于区别replIndexPrefetch = _id_only #指定副本集的索引预取,如果有预取功能可以让复制过程更为高效,# 有3个值none,_id_only,all。# none:不预取任何索引,# _id_only:预取ID索引,# all:预取所有索引。
创建数据目录启动服务
[root@mongo1 ~]# mkdir -pv /data/mongodbmkdir: created directory `/mongodb'mkdir: created directory `/data/mongodb'[root@mongo1 ~]# chown -R mongod.mongod /data/mongodb[root@mongo1 ~]# systemctl start mongod # 在每一个节点启动服务
配置添加集群成员
[root@mongo1 ~]# mongo --host 192.168.1.132MongoDB shell version: 2.6.5connecting 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)"}>rs.initiate() #主节点初始化>rs.status(){ "set" : "testSet", "date" : ISODate("2017-10-13T08:25:57Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "www.dearecho.me:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 234, "optime" : Timestamp(1507883148, 1), "optimeDate" : ISODate("2017-10-13T08:25:48Z"), "electionTime" : Timestamp(1507883149, 1), "electionDate" : ISODate("2017-10-13T08:25:49Z"), "self" : true } ], "ok" : 1}rs0:PRIMARY> rs.add("192.168.80.8") # 发现前面的标识变为了Primary,添加从节点{ "ok" : 1 }rs0:PRIMARY> rs.add("192.168.80.9"){ "ok" : 1 }在创建副本集时,有3种方式:db.runCommand( { replSetInitiate : <config_object> } )rs.initiate(<config_object>)rs.initiate() #先在其中一个节点上初始化,再通过rs.add添加另外的节点这里采用的是第一种方式。
查看各节点信息
> rs.status(){ "set" : "rs0", "date" : ISODate("2015-09-04T23:02:13Z"), "myState" : 1, "members" : [ #显示副本集的所有成员信息 { "_id" : 0, #节点的标识符 "name" : "192.168.80.5:27017", #节点名称 "health" : 1, #节点的健康状态 "state" : 1, "stateStr" : "PRIMARY", #该节点为主节点 "uptime" : 1750, #运行时长 "optime" : Timestamp(1507898695, 173), #oplog最后一次操作的时间戳 "optimeDate" : ISODate("2017-10-13T12:44:55Z"), "lastHeartbeat" : ISODate("2017-10-13T12:53:19Z"), "lastHeartbeatRecv" : ISODate("2017-10-13T12:53:19Z"), "pingMs" : 0, "electionTime" : Timestamp(1507899169, 1), #选举日期 "self" : true #表示是否为当前节点 }, { "_id" : 1, #节点的标识符 "name" : "192.168.80.8:27017", #节点名称 "health" : 1, #节点的健康状态 "state" : 1, "stateStr" : "SECONDARY", #从节点 "uptime" : 1750, #运行时长 "optime" : Timestamp(1507898695, 173), #oplog最后一次操作的时间戳 "optimeDate" : ISODate("2017-10-13T12:44:55Z"), "lastHeartbeat" : ISODate("2017-10-13T12:53:19Z"), "lastHeartbeatRecv" : ISODate("2017-10-13T12:53:19Z"), "pingMs" : 0, "syncingTo" : "192.168.80.5:27017" #指向的主节点 }, { "_id" : 2, "name" : "192.168.80.9:27017", "health" : 1, "state" : 1, "stateStr" : "SECONDARY", #从节点 "uptime" : 1750, "optime" : Timestamp(1507898695, 173), "optimeDate" : ISODate("2017-10-13T12:44:55Z"), "lastHeartbeat" : ISODate("2017-10-13T12:53:19Z"), "lastHeartbeatRecv" : ISODate("2017-10-13T12:53:19Z"), "pingMs" : 0, "syncingTo" : "192.168.80.5:27017" #指向的主节点 } ], "ok" : 1}
测试
在主节点添加测试数据:
rs0:PRIMARY> use student_db switched to db student_dbrs0:PRIMARY> for (i=1;i<=100000;i++) db.students.insert({name:"student"+i,age:(i%120),address:"china_nb"});WriteResult({ "nInserted" : 1 })
在从节点查看数据
rs0:SECONDARY> show collections 2017-10-13T20:46:55.346+0800 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:131rs0:SECONDARY> rs.slaveOk() # 需启用从节点才可查看rs0:SECONDARY> db.students.findOne(){ "_id" : ObjectId("59e0b54660703b86d071762f"), "name" : "student1", "age" : 1, "address" : "china_nb"}
主节点修改优先级
rs0:PRIMARY> cfg = rs.config(){ "_id" : "test", "version" : 3, "members" : [ { "_id" : 0, "host" : "192.168.80.5:27017" }, { "_id" : 1, "host" : "192.168.80.8:27017" }, { "_id" : 2, "host" : "192.168.80.9:27017" } ]}rs0:PRIMARY> cfg.members[1].priority=2 # 设置第二个节点优先级为22rs0:PRIMARY> rs.reconfig(cfg)2017-10-13T21:13:01.255+0800 DBClientCursor::init call() failed2017-10-13T21:13:01.269+0800 trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed2017-10-13T21:13:01.282+0800 reconnect 127.0.0.1:27017 (127.0.0.1) okreconnected to server after rs command (which is normal)
在192.168.80.8
查看状态
rs0:PRIMARY> db.printReplicationInfo()configured oplog size: 990MBlog length start to end: 1098secs (0.31hrs)oplog first event time: Fri Oct 13 2017 20:26:37 GMT+0800 (CST)oplog last event time: Fri Oct 13 2017 20:44:55 GMT+0800 (CST)now: Fri Oct 13 2017 20:56:23 GMT+0800 (CST)rs.status() { "_id" : 1, #节点2 "name" : "192.168.80.8:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", #已抢占为主节点 "uptime" : 1602, "optime" : Timestamp(1507898695, 173), "optimeDate" : ISODate("2017-10-13T12:44:55Z"), "lastHeartbeat" : ISODate("2017-10-13T12:53:19Z"), "lastHeartbeatRecv" : ISODate("2017-10-13T12:53:19Z"), "pingMs" : 0, "electionTime" : Timestamp(1507899169, 1), "electionDate" : ISODate("2017-10-13T12:52:49Z") }
MongoDB数据分片
在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。
当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。
MongoDB中使用分片集群结构分布:
上图中主要有如下所述三个主要组件:
Query Routers
前端路由,客户端由此接入,把客户端的请求路由到合适的shared上。Config Server
实质为mongod实例存储了整个 ClusterMetadata,其中包括 chunk信息和索引信息。Shard
存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
分片过程:
把表上以某个字段为例,字段创建为索引,索引当做分片的元数据,而后把大数据切割成一个一个的chunk,把每个chunk分配到每个shared。在整个业务运行过程中,重新均衡,chunk在每个节点上挪来挪去。
实例
实现步骤如下:
配置各个节点
配置config server
yum install -y mongodb-server mongodbvim /etc/mongod.confconfigsvr = true
启动其他节点:
yum install -y mongodb-server mongodbmongos --configdb=192.168.80.7 --fork --logpath=/var/log/mongodb/mongo.log # 启动Query Routers 2017-10-14T10:32:40.251+0800 warning: running with 1 config server should be done only for testing purposes and is not recommended for productionabout to fork child process, waiting until server is ready for connections.forked process: 16035child process started successfully, parent exiting[root@node ~]# ss -tnlLISTEN 0 128 *:27017 *:* # monogs监听在27017 systemctl start mongod # 启动shared
Query Routers
配置节点加入`Shard`:mongos> sh.addShard("192.168.80.8"){ "shardAdded" : "shard0000", "ok" : 1 }mongos> sh.addShard("192.168.80.9"){ "shardAdded" : "shard0001", "ok" : 1 }mongos> use student_db # 创建数据库switched to db student_dbmongos> sh.enableSharding("student_db") # 数据库启用分片{ "ok" : 1 }mongos> sh.shardCollection("student_db.students",{"age":1}) # 创建collections,并指明索引{ "collectionsharded" : "student_db.students", "ok" : 1 } mongos> sh.status()--- Sharding Status --- sharding version: { "_id" : 1, "version" : 4, "minCompatibleVersion" : 4, "currentVersion" : 5, "clusterId" : ObjectId("59e17748c68473e873f81bc7")} shards: { "_id" : "shard0000", "host" : "192.168.80.8:27017" } { "_id" : "shard0001", "host" : "192.168.80.9:27017" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "test", "partitioned" : true, "primary" : "shard0001" } { "_id" : "student", "partitioned" : false, "primary" : "shard0000" } { "_id" : "student_db", "partitioned" : true, "primary" : "shard0000" } #数据库分片已启用
测试
#插入数据mongos> for (i=1;i<=100000;i++) db.students.insert({name:"student"+i,age:(i%120),address:"china_nb"});mongos>sh.status() # 查看数据库分片状态 student_db.students shard key: { "age" : 1 } chunks: shard0000 2 # 数据被分布在每一个shared上 shard0001 1 { "age" : { "$minKey" : 1 } } -->> { "age" : 1 } on : shard0001 Timestamp(2, 0) { "age" : 1 } -->> { "age" : 119 } on : shard0000 Timestamp(2, 2) { "age" : 119 } -->> { "age" : { "$maxKey" : 1 } } on : shard0000 Timestamp3, 3)
总结
Mongodb在丢弃了关系型数据库一些局限性:事务
关系
。同时采用文档形式对数据的存储,加大数据存储的同时加快数据的查询效率。此外Mongodb还提供完备的HA解决方案和分片的分布式策略。在不依赖于事务的大数据场景中,让其作为大数据处理有效的解决方案之一。
- MongoDB副本集复制和分片
- mongodb 副本集+分片
- mongodb 副本集+分片
- Mongodb的分片和副本集
- mongodb副本集和分片部署
- mongodb副本集和分片部署命令
- MongoDB副本集和分片模式安装
- MongoDB 主从复制,副本集,分片....(八)
- CentOS mongodb 副本集分片
- Mongodb分片+副本集配置
- mongodb 分片 副本集 集群
- mongoDB副本集与分片
- mongodb 分片与副本集
- mongodb复制和分片
- window下MongoDB副本集和分片高可靠性部署
- MongoDb复制-副本集
- mongodb复制-副本集
- mongodb主从复制和副本集
- 软件工程(C编码实践篇) 实验四:用可重用的链表模块来实现命令行菜单小程序V2.5
- Linux文本处理三剑客之awk命令
- 乔布斯自传(笔记)——第一回合
- laravel migrate 时出现错误 [PDOException] SQLSTATE[HY000]: General error: 1215 Cannot add foreign key
- 试验二 Linux用户管理
- MongoDB副本集复制和分片
- IntentService源码欣赏
- 【Spring】对jdbc支持(十三)
- 欢迎使用CSDN-markdown编辑器
- 编写判断素数的函数。在主调函数中输出1-100之间的素数。
- MacBook升级到OSX 10.13 下运行Android Simulator失败的一种解决方案
- 【Spring】程序中的事务控制(十四)
- java虚拟机
- linux-sys_进程间通信(IPC)