您的位置:首页 > 数据库 > Mongodb

MongoDB分片集群部署

2016-05-20 00:27 936 查看
之前提到了mongodb复制集(副本集)的一些概念,在这篇博文介绍一下如何使用复制集在单机上进行分片集群的部署。在这里先介绍集群部署复制集和分片的一些概念,然后再完成部署实现。

CAP

首先我们来了解一下什么是CAP理论,其核心是:一个分布式系统不可能同时很好的满足 一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

- 一致性(Consistency) :所有节点在同一时间具有相同的数据;

- 可用性(Availability) :保证每个请求不管成功或者失败都有响应;

- 分区容错性(Partition tolerance) :系统中任意信息的丢失或失败不会 影响系统的继续运作,即可靠性。

而MongoDB通过复制集和分片技术很好的满足了CP原则。

复制集

MongoDB复制集是由一组mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,客户端的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。默认情况下,复制集的所有读请求都发到Primary。



Primary选举

复制集首先进行初始化,初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作,获得『大多数』成员投票支持的节点,会成为Primary,其余节点成为Secondary。

『大多数』:假设复制集内投票成员数量为N,则大多数为 N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。通常建议将复制集成员数量设置为奇数。例如,当投票成员数为3或者4时,容忍失效数均为1。



特殊Secondary——Arbiter

正常情况下,复制集的Seconary会参与Primary选举(自身也可能会被选为Primary),并从Primary同步最新写入的数据,以保证与Primary存储相同的数据。Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力,同时提升复制集的可用性。而Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据。它的目的是通过响应心跳来维持复制集成员选举时要求的法定成员数。



异常处理和自动故障转移

Primary重新选举场景:

-复制集被reconfig;

-Secondary节点检测到Primary宕机时;

-当有Primary节点主动stepDown(主动降级为Secondary)。

Primary的选举受节点间心跳、优先级、最新的oplog(数据同步)时间等多种因素影响。当Primary宕机时,如果有数据未同步到Secondary或当Primary重新加入时,如果新的Primary上已经发生了写操作,则旧Primary需要回滚部分操作,以保证数据集与新的Primary一致。

复制集成员间默认每2s会发送一次心跳信息,如果10s未收到某个节点的心跳,则认为该节点已宕机;如果宕机的节点为Primary,Secondary(前提是可被选为Primary)会发起新的Primary选举。



Sharding分片

与mysql等关系数据库的Cluster不同,mongodb支持自动分片。

为什么需要分片?

当MongoDB复制集遇到下面的业务场景时,就需要考虑使用分片。

-存储容量需求超出单机磁盘容量;

-活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能;

-写IOPS超出单个MongoDB节点的写服务能力。

Sharded cluster使得集合的数据可以分散到多个Shard(复制集或者单个Mongod节点)存储,使得MongoDB具备了横向扩展的能力。例如,将1TB的数据均分成4个256GB的片,从而使数据库的负载均衡。



Sharded cluster架构

Sharded cluster由Shard、Mongos和Config server 3个组件构成。



-Mongos: Sharded cluster的访问入口,所有的请求都通过mongos来路由、分发、合并,这些动作对客户端透明。 Mongos会根据请求类型及shard key将请求路由到对应的Shard。在生产环境通常有多mongos,目的是防止其中一个挂掉后所有的mongodb请求都无法操作。

-Config server: 存储所有数据库元信息(路由、分片)的配置。这个数据包含集群数据集与片的映射。 Mongos使用这些元数据来定位到特定的片进行操作。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。 同样,在生产环境通常有多个配置服务器,防止其中一个挂掉后还有后备的元数据,这样 mongodb集群就不会挂掉。

-Shard: 存储数据。为了提供高可用性和数据的一致性,在生产分片集群时,每个片都是一个复制集。

Hash片键策略

MongoDB分片有多种片键策略,这里介绍一下博文集群部署时采用的Hash片键策略。

对于Hash片键策略, MongoDB计算字段的hash值(64bit整型),然后使用这些hash值来创建chunk。基于散列的分片,“临近” 片键值的两个文档不可能是相同chunk的一部分,这确保了集合在集群中更随机的分布。



Hash分片能将文档随机的分散到各个chunk ,充分地扩展写能力,但不能高效地服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。

部署实现



在部署图中mongos 3个, config server 3个,数据分3片 shard server 3个,每个shard 有一个Secondary和一个Arbiter也就是 3 * 2 = 6 个,总共需要部署15个mongod实例。将这些实例部署一台机器上,通过配置不同的端口来实现。数据分为3个片,每个片都是一个复制集,分别为shard1,shard2,shard3。

服务器环境:Ubuntu 14.04 LTS、MongoDB 3.2.0,单机的IP地址为localhost(127.0.0.1)

建立文件夹,存放mongodb数据文件

sudo mkdir /data/mongodbtest1
sudo mkdir /data/mongodbtest2
sudo mkdir /data/mongodbtest3


为mongos 、config 、 shard1 、shard2、shard3 建立目录,用来存放数据和日志文件,因为mongos不存储数据,只需要建立日志文件目录即可。

#/data/mongodbtest1文件目录
sudo mkdir /data/mongodbtest1/mongos/log

sudo mkdir /data/mongodbtest1/config/data
sudo mkdir /data/mongodbtest1/config/log

sudo mkdir /data/mongodbtest1/shard11/data
sudo mkdir /data/mongodbtest1/shard11/log

sudo mkdir /data/mongodbtest1/shard12/data
sudo mkdir /data/mongodbtest1/shard12/log

sudo mkdir /data/mongodbtest1/shard13/data
sudo mkdir /data/mongodbtest1/shard13/log

#/data/mongodbtest2文件目录
sudo mkdir /data/mongodbtest2/mongos/log

sudo mkdir /data/mongodbtest2/config/data
sudo mkdir /data/mongodbtest2/config/log

sudo mkdir /data/mongodbtest2/shard21/data
sudo mkdir /data/mongodbtest2/shard21/log

sudo mkdir /data/mongodbtest2/shard22/data
sudo mkdir /data/mongodbtest2/shard22/log

sudo mkdir /data/mongodbtest2/shard23/data
sudo mkdir /data/mongodbtest2/shard23/log

#/data/mongodbtest3文件目录
sudo mkdir /data/mongodbtest3/mongos/log

sudo mkdir /data/mongodbtest3/config/data
sudo mkdir /data/mongodbtest3/config/log

sudo mkdir /data/mongodbtest3/shard31/data
sudo mkdir /data/mongodbtest3/shard31/log

sudo mkdir /data/mongodbtest3/shard32/data
sudo mkdir /data/mongodbtest3/shard32/log

sudo mkdir /data/mongodbtest3/shard33/data
sudo mkdir /data/mongodbtest3/shard33/log


启动配置服务器,端口号分别为:10001,20001,30001

sudo /usr/local/mongodb/bin/mongod --configsvr --dbpath /data/mongodbtest1/config/data --port 10001 --logpath /data/mongodbtest1/config/log/config.log --fork

sudo /usr/local/mongodb/bin/mongod --configsvr --dbpath /data/mongodbtest2/config/data --port 20001 --logpath /data/mongodbtest2/config/log/config.log --fork

sudo /usr/local/mongodb/bin/mongod --configsvr --dbpath /data/mongodbtest3/config/data --port 30001 --logpath /data/mongodbtest3/config/log/config.log --fork


mongos服务器,端口号分别为:10002,20002,30002

sudo /usr/local/mongodb/bin/mongos --configdb localhost:10001,localhost:20001,localhost:30001 --port 10002 --logpath /data/mongodbtest1/mongos/log/mongos.log --fork

sudo /usr/local/mongodb/bin/mongos --configdb localhost:10001,localhost:20001,localhost:30001 --port 20002 --logpath /data/mongodbtest2/mongos/log/mongos.log –fork

sudo /usr/local/mongodb/bin/mongos --configdb localhost:10001,localhost:20001,localhost:30001 --port 30002 --logpath /data/mongodbtest3/mongos/log/mongos.log --fork


启动复制集shard1,shard2,shard3

#shard1,端口号分别为10003,10004,10005
sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard1 --dbpath /data/mongodbtest1/shard11/data  --logpath /data/mongodbtest1/shard11/log/shard1.log --port 10003 --oplogSize 1024 --fork

sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard1 --dbpath /data/mongodbtest1/shard12/data  --logpath /data/mongodbtest1/shard12/log/shard2.log --port 10004 --oplogSize 1024 --fork

sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard1 --dbpath /data/mongodbtest1/shard13/data  --logpath /data/mongodbtest1/shard13/log/shard3.log --port 10005 --oplogSize 1024 --fork

#shard2,端口号分别为20003,20004,20005
sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard2 --dbpath /data/mongodbtest2/shard21/data  --logpath /data/mongodbtest2/shard21/log/shard1.log --port 20003 --oplogSize 1024 --fork

sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard2 --dbpath /data/mongodbtest2/shard22/data  --logpath /data/mongodbtest2/shard22/log/shard2.log --port 20004 --oplogSize 1024 --fork

sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard2 --dbpath /data/mongodbtest2/shard23/data  --logpath /data/mongodbtest2/shard23/log/shard3.log --port 20005 --oplogSize 1024 --fork

#shard3,端口号分别为30003,30004,30005
sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard3 --dbpath /data/mongodbtest3/shard31/data  --logpath /data/mongodbtest3/shard31/log/shard1.log --port 30003 --oplogSize 1024 --fork

sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard3 --dbpath /data/mongodbtest3/shard32/data  --logpath /data/mongodbtest3/shard32/log/shard2.log --port 30004 --oplogSize 1024 --fork

sudo /usr/local/mongodb/bin/mongod --shardsvr --replSet shard3 --dbpath /data/mongodbtest3/shard33/data  --logpath /data/mongodbtest3/shard33/log/shard3.log --port 30005 --oplogSize 1024 --fork


查看mongod进程开启状态





添加复制集

任意登陆一个机器,比如登陆localhost:10003

sudo /usr/local/mongodb/bin/mongo localhost:10003


设置shard1复制集

use admin

config = { _id:"shard1", members:[
{_id:0,host:"localhost:10003"},
{_id:1,host:"localhost:10004"},
{_id:2,host:"localhost:10005",arbiterOnly:true}
]
}
rs.initiate(config);


登陆localhost:20003

sudo /usr/local/mongodb/bin/mongo localhost:20003


设置shard2复制集

use admin
config = { _id:"shard2", members:[
{_id:0,host:"localhost:20003"},
{_id:1,host:"localhost:20004"},
{_id:2,host:"localhost:20005",arbiterOnly:true}
]
}
rs.initiate(config);


登陆localhost:30003

sudo /usr/local/mongodb/bin/mongo localhost:30003


设置shard3复制集

use admin
config = { _id:"shard3", members:[
{_id:0,host:"localhost:30003"},
{_id:1,host:"localhost:30004"},
{_id:2,host:"localhost:30005",arbiterOnly:true}
]
}
rs.initiate(config);


shard1复制集配置结果,shard2,shard3类似



配置好复制集后,连接到其中一个mongos

sudo /usr/local/mongodb/bin/mongo localhost:10002




串联路由服务器并分配复制集

use admin
db.runCommand( { addshard : "shard1/localhost:10003,localhost:10004,localhost:10005"});

db.runCommand( { addshard : "shard2/localhost:20003,localhost:20004,localhost:20005"});

db.runCommand( { addshard : "shard3/localhost:30003,localhost:30004,localhost:30005"});




查看分片服务器的配置

db.runCommand( { listshards : 1 } );




在这里,每个复制集的仲裁节点没有显示。

让指定的数据库和指定的集合分片生效

指定test集合分片生效

db.runCommand( { enablesharding :"test"});




对test数据库中的userinfo集合进行分片,片键采用Hash片键

db.runCommand({shardcollection:"test.userinfo",key:{"_id": "hashed"}})




测试分片结果

连接mongos服务器,之前已经连接,如果关闭了就重新连接

sudo /usr/local/mongodb/bin/mongo localhost:10002


插入数据

use test
for(var i=0;i<100000;i++){db.userinfo.insert({"username":"user"+i});}




查看分片情况(只截取展示关键信息)

由于采用的是hash分片,将100000条数据比较均匀的分成3个片

db.userinfo.stats();








查看集群状态

每个片有两个chuck(块)

sh.status();




到这里整个分片集群就搭建完了,希望对大家有所帮助,博文中不足的地方可以探讨探讨。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: