mongodb分片集群
mongodb分片集群
Sharding cluster是一种可以水平扩展的模式,在数据量很大时特给力,实际大规模应用一般会采用这种架构去构建。sharding分片很好的解决了单台服务器磁盘空间、内存、cpu等硬件资源的限制问题,把数据水平拆分出去,降低单节点的访问压力。每个分片都是一个独立的数据库,所有的分片组合起来构成一个逻辑上的完整的数据库。因此,分片机制降低了每个分片的数据操作量及需要存储的数据量,达到多台服务器来应对不断增加的负载和数据的效果。
1)Sharding分区概念
分片 (sharding)是指将数据库拆分,将其分散在不同的机器上的过程。将数据分散到不同的机器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载。
分片的基本思想就是:
将集合切成小块,这些块分散到若干片里,每个片只负责总数据的一部分。通过一个名为 mongos 的路由进程进行操作,mongos 知道数据和片的对应
关系(通过配置服务器)。 大部分使用场景都是解决磁盘空间的问题,对于写入有可能会变差(+++里面的说明+++),查 询则尽量避免跨分片查询。使用分片的时机:
使用场景:
1)机器的磁盘不够用了。使用分片解决磁盘空间的问题。
2)单个mongod已经不能满足写数据的性能要求。通过分片让写压力分散到各个分片上面,使用分片服务器自身的资源。
3)想把大量数据放到内存里提高性能。和上面一样,通过分片使用分片服务器自身的资源。
要构建一个MongoDB Sharding Cluster(分片集群),需要三种角色:
1)分片服务器(Shard Server)
mongod 实例,用于存储实际的数据块,实际生产环境中一个 shard server 角色可由几台机器组个一个 relica
set
承担,防止主机单点故障
这是一个独立普通的mongod进程,保存数据信息。可以是一个副本集也可以是单独的一台服务器。
2)配置服务器(Config Server)
mongod 实例,存储了整个 Cluster Metadata,其中包括 chunk 信息。
这是一个独立的mongod进程,保存集群和分片的元数据,即各分片包含了哪些数据的信息。最先开始建立,启用日志功能。像启动普通的 mongod 一样启动
配置服务器,指定configsvr 选项。不需要太多的空间和资源,配置服务器的 1KB 空间相当于真是数据的 200MB。保存的只是数据的分布表。
3)路由服务器(Route Server)
mongos实例,前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用
起到一个路由的功能,供程序连接。本身不保存数据,在启动时从配置服务器加载集群信息,开启 mongos 进程需要知道配置服务器的地址,指定configdb选项。
片键的意义
一个好的片键对分片至关重要。 片键必须是一个索引 ,通 过 sh.shardCollection 加会自动创建索引。一个自增的片键对写入和数据均匀分布就不是很好, 因为自增
的片键总会在一个分片上写入,后续达到某个阀值可能会写到别的分片。但是按照片键查询会非常高效。随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询。
在所有分片上查询,mongos 会对结果进行归并排序
水平数据分片
分片集群主要由三种组件组成:mongos,config server,shard 1) mongos (路由进程, 应用程序接入 mongos 再查询到具体分片) 数据库集群请求的入口,所有的请求都通过 mongos 进行协调,不需要在应用程序添加一个路由选择器,mongos 自己就是一个请求分发中心,它负责把对应的数据请求 请求转发到对应的 shard 服务器上。在生产环境通常有多个 mongos 作为请求的入口,防止其中一个挂掉所有的 mongodb 请求都没有办法操作。 2) config server (路由表服务。 每一台都具有全部 chunk 的路由信息) 顾名思义为配置服务器,存储所有数据库元信息(路由、分片)的配置。mongos 本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储 这些数据。mongos 第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,这个可不能丢失!就算挂掉其中一台,只要还有存货, mongodb 集群就不会挂掉。 3) shard (为数据存储分片。 每一片都可以是复制集(replica set)) 这就是传说中的分片了。如图所示,一台机器的一个数据表 Collection1 存储了 1T 数据,压力太大了!在分给 4 个机器后, 每个机器都是 256G,则分摊了集中在一台 机器的压力。事实上,上图4个分片如果没有副本集(replica set)是个不完整架构,假设其中的一个分片挂掉那四 分之一的数据就丢失了,所以在高可用性的分片架构还 需要对于每一个分片构建 replica set 副本集保 证分片的可靠性。生产环境通常是 2 个副本 + 1 个仲裁。
2)Sharding分区的原理
分片,是指将数据拆分,将其分散到不同的机器上。这样的好处就是,不需要功能强大的大型计算机也可以存储更多的数据,处理更大的负载。mongoDB 的分片,
是将collection 的数据进行分割,然后将不同的部分分别存储到不同的机器上。当 collection 所占空间过大时,我们需要增加一台新的机器,分片会自动
将 collection 的数据分发到新的机器上。
mongos:
首先我们要了解”片键“的概念,也就是说拆分集合的依据是什么?按照什么键值进行拆分集合。mongos就是一个路由服务器,它会根据管理员设置的
"片键"
将数据分摊到自己管理的mongod集群,数据和片的对应关系以及相应的配置信息保存在
"config服务器"
上。
客户端只需要对 mongos 进行操作就行了,至于如何进行分片,不需要 客户端参与,由 mongos 和 config 来完成。
mongod:
一个普通的数据库实例或者副本集,如果不分片的话,我们会直接连上mongod。
分片是指将数据拆分,将其分散存在不同机器上的过程.有时也叫分区.将数据分散在不同的机器上MongoDB支持自动分片,可以摆脱手动分片的管理.集群自动切分数据,做负载均衡
![](https://img2020.cnblogs.com/blog/1339149/202008/1339149-20200817140247659-1400986579.png)
分片集群由以下3个服务组成:
Shards Server: 每个shard由一个或多个mongod进程组成,用于存储数据
Config Server: 用于存储集群的Metadata信息,包括每个Shard的信息和chunks信息
Route Server: 用于提供路由服务,由Client连接,使整个Cluster看起来像单个DB服务器
部署分片集群:
分别在3台机器运行一个mongod实例(称为mongod shard11,mongod shard12,mongod shard13)组织replica set1,作为cluster的shard1
分别在3台机器运行一个mongod实例(称为mongod shard21,mongod shard22,mongod shard23)组织replica set2,作为cluster的shard2
每台机器运行一个mongod实例,作为3个config server
每台机器运行一个mongos进程,用于客户端连接
1)安装mongodb (3台机器都要操作) 下载压缩包, 安装可以参考前边的安装
# tar -zxvf mongodb-linux-x86_64-enterprise-rhel70-4.4.0.tgz
[root@localhost ~]# cd /usr/local/src/
[root@localhost src]# mv /root/mongodb-linux-x86_64-enterprise-rhel70-4.4.0 ./
[root@localhost src]# mv mongodb-linux-x86_64-enterprise-rhel70-4.4.0 mongodb
# yum install net-snmp -y
2)创建sharding数据目录
根据本例sharding架构图所示,在各台sever上创建shard数据文件目录
2)创建sharding数据目录
根据本例sharding架构图所示,在各台sever上创建shard数据文件目录
slave1
[root@slave1 src]
# mkdir /home/services/
[root@slave1 src]
# mv mongodb /home/services/
[root@slave1 src]
# cd /home/services/mongodb/
[root@slave1 mongodb]
# mkdir -p data/shard11
[root@slave1 mongodb]
# mkdir -p data/shard21
slave2
[root@slave2 src]
# mkdir /home/services/
[root@slave2 src]
# mv mongodb /home/services/
[root@slave2 src]
# cd /home/services/mongodb/
[root@slave2 mongodb]
# mkdir -p data/shard12
[root@slave2 mongodb]
# mkdir -p data/shard22
slave3
[root@slave3 src]
# mkdir /home/services/
[root@slave3 src]
# mv mongodb /home/services/
[root@slave3 src]
# cd /home/services/mongodb/
[root@slave3 mongodb]
# mkdir -p data/shard13
[root@slave3 mongodb]
# mkdir -p data/shard23
3)配置relica sets
3.1)配置shard1所用到的replica sets 1:
slave1
[root@slave1 ~]
# /home/services/mongodb/bin/mongod --shardsvr --replSet shard1 --port 27018 --dbpath /home/services/mongodb/data/shard11 --oplogSize 100 --logpath /home/services/mongodb/data/shard11.log --logappend --fork --bind_ip 192.168.88.191
slave2
[root@slave2 ~]
# /home/services/mongodb/bin/mongod --shardsvr --replSet shard1 --port 27018 --dbpath /home/services/mongodb/data/shard12 --oplogSize 100 --logpath /home/services/mongodb/data/shard12.log --logappend --fork --bind_ip 192.168.88.192
slave3
[root@slave3 ~]
# /home/services/mongodb/bin/mongod --shardsvr --replSet shard1 --port 27018 --dbpath /home/services/mongodb/data/shard13 --oplogSize 100 --logpath /home/services/mongodb/data/shard13.log --logappend --fork --bind_ip 192.168.88.194
检测各个机器上的mongod进程是否正常起来了(
ps
-ef|
grep
mongod),27018端口是否正常起来了
3.2)初始化replica
set
1
从3台机器中任意找一台,连接mongod
[root@slave1 ~]
# /home/services/mongodb/bin/mongo --port 27018 --host 192.168.88.191
......
> config = {
"_id"
:
"shard1"
,
"members"
: [{
"_id"
: 0,
"host"
:
"192.168.88.191:27018"
},{
"_id"
: 1,
"host"
:
"192.168.88.192:27018"
},{
"_id"
: 2,
"host"
:
"192.168.88.194:27018"
}]}
> rs.initiate(config);
{
"ok"
: 1 }
3.3)配置shard2所用到的replica sets 2:
slave1
[root@slave1 ~]
# /home/services/mongodb//bin/mongod --shardsvr --replSet shard2 --port 27019 --dbpath /home/services/mongodb/data/shard21 --oplogSize 100 --logpath /home/services/mongodb/data/shard21.log --logappend --fork --bind_ip 192.168.88.191
slave2
[root@slave2 ~]
# /home/services/mongodb//bin/mongod --shardsvr --replSet shard2 --port 27019 --dbpath /home/services/mongodb/data/shard22 --oplogSize 100 --logpath /home/services/mongodb/data/shard22.log --logappend --fork --bind_ip 192.168.88.192
slave3
[root@slave3 ~]
# /home/services/mongodb//bin/mongod --shardsvr --replSet shard2 --port 27019 --dbpath /home/services/mongodb/data/shard23 --oplogSize 100 --logpath /home/services/mongodb/data/shard23.log --logappend --fork --bind_ip 192.168.88.194
3.4)初始化replica
set
2
从3台机器中任意找一台,连接mongod
[root@slave1 ~]
# /home/services/mongodb/bin/mongo --port 27019
......
> config = {
"_id"
:
"shard2"
,
"members"
: [{
"_id"
: 0,
"host"
:
"192.168.88.191:27019"
},{
"_id"
: 1,
"host"
:
"192.168.88.192:27019"
},{
"_id"
: 2,
"host"
:
"192.168.88.194:27019"
}]}
> rs.initiate(config);
{
"ok"
: 1 }
4)配置三台config server
slave1
[root@slave1 ~]
# mkdir -p /home/services/mongodb/data/config
[root@slave1 ~]
# /home/services/mongodb//bin/mongod --configsvr --dbpath /home/services/mongodb/data/config --port 20000 --logpath /home/services/mongodb/data/config.log --logappend --fork --bind_ip 192.168.88.191
slave2
[root@slave2 ~]
# mkdir -p /home/services/mongodb/data/config
[root@slave2 ~]
# /home/services/mongodb//bin/mongod --configsvr --dbpath /home/services/mongodb/data/config --port 20000 --logpath /home/services/mongodb/data/config.log --logappend --fork --bind_ip 192.168.88.192
slave3
[root@slave3 ~]
# mkdir -p /home/services/mongodb/data/config
[root@slave3 ~]
# /home/services/mongodb//bin/mongod --configsvr --dbpath /home/services/mongodb/data/config --port 20000 --logpath /home/services/mongodb/data/config.log --logappend --fork --bind_ip 192.168.88.194
5)配置mongs
在三台机器上分别执行: slave1 [root@slave1 ~]# /home/services/mongodb/bin/mongos --configdb shard1/192.168.88.191:20000,192.168.88.192:20000,192.168.88.194:20000 --port 27017 --chunkSize 5 --logpath /home/services/mongodb/data/mongos.log --logappend --fork --bind_ip 192.168.88.191 slave2 [root@slave2 ~]# /home/services/mongodb/bin/mongos --configdb shard1/192.168.88.191:20000,192.168.88.192:20000,192.168.88.194:20000 --port 27017 --chunkSize 5 --logpath /home/services/mongodb/data/mongos.log --logappend --fork
--bind_ip 192.168.88.192
slave3 [root@slave3 ~]# /home/services/mongodb/bin/mongos --configdb shard1/192.168.88.191:20000,192.168.88.192:20000,192.168.88.194:20000 --port 27017 --chunkSize 5 --logpath /home/services/mongodb/data/mongos.log --logappend --fork
--bind_ip 192.168.88.194
注意:新版版的mongodb的mongos命令里就不识别--chunkSize参数了
报错信息:
--logpath /home/services/mongodb/data/mongos.log --logappend --fork --bind_ip 192.168.88.192
FailedToParse: mirrored config server connections are not supported; for config server replica sets be sure to use the replica set connection string
try '/home/services/mongodb/bin/mongos --help' for more information
需要加上副本名称
{"t":{"$date":"2020-08-17T17:16:12.133+08:00"},"s":"I", "c":"NETWORK", "id":4712102, "ctx":"ReplicaSetMonitor-TaskExecutor","msg":"Host failed in replica set","attr":{"replicaSet":"shard1","host":"192.169.88.192:20000","error":{"code":202,"codeName":"NetworkInterfaceExceededTimeLimit","errmsg":"Couldn't get a connection within the time limit of 483ms"},"action":{"dropConnections":false,"requestImmediateCheck":false,"outcome":{"host":"192.169.88.192:20000","success":false,"errorMessage":"NetworkInterfaceExceededTimeLimit: Couldn't get a connection within the time limit of 483ms"}}}}
about to fork child process, waiting until server is ready for connections
尚未解决
6)配置分片集群(Configuring the Shard Cluster)
从3台机器中任意找一台,连接mongod,并切换到admin数据库做以下配置
[root@slave1 ~]# /home/services/mongodb/bin/mongo 182.48.115.236:27017/admin6.2)加入shards分区
如里shard是单台服务器,用
"db.runCommand( { addshard : “[:]” } )"
这样的命令加入
如果shard是replica sets,用
"replicaSetName/[:port][,serverhostname2[:port],…]"
这样的格式表示,例如本例执行:
mongos> db.runCommand( { addshard:
"shard1/192.168.88.191:27018,192.168.88.192:27018,192.168.88.194:27018"
,name:
"s1"
,maxsize:20480});
{
"shardAdded"
:
"s1"
,
"ok"
: 1 }
mongos> db.runCommand( { addshard:
"shard2/1192.168.88.191:27019,192.168.88.192:27019,192.168.88.194:27019"
,name:
"s2"
,maxsize:20480});
{
"shardAdded"
:
"s2"
,
"ok"
: 1 }
注意:
可选参数
Name:用于指定每个shard的名字,不指定的话系统将自动分配
maxSize:指定各个shard可使用的最大磁盘空间,单位megabytes
6.3)Listing shards
mongos> db.runCommand( { listshards : 1 } )
6.4)激活数据库分片
命令:
db.runCommand( { enablesharding : “” } );
通过执行以上命令,可以让数据库跨shard,如果不执行这步,数据库只会存放在一个shard,一旦激活数据库分片,数据库中不同的collection将被存放在不同的shard上,
但一个collection仍旧存放在同一个shard上,要使单个collection也分片,还需单独对collection作些操作
Collecton分片
要使单个collection也分片存储,需要给collection指定一个分片key,通过以下命令操作:
db.runCommand( { shardcollection : “”,key : });
注意:
a)分片的collection系统会自动创建一个索引(也可用户提前创建好)
b)分片的collection只能有一个在分片key上的唯一索引,其它唯一索引不被允许
本案例:
mongos> db.runCommand({enablesharding:
"test2"
});
{
"ok"
: 1 }
mongos> db.runCommand( { shardcollection :
"test2.books"
, key : {
id
: 1 } } );
{
"collectionsharded"
:
"test2.books"
,
"ok"
: 1 }
mongos> use test2
switched to db test2
mongos> db.stats();
{
"raw"
: {
"shard1/182.48.115.236:27018,182.48.115.237:27018,182.48.115.238:27018"
: {
"db"
:
"test2"
,
"collections"
: 3,
"objects"
: 6,
"avgObjSize"
: 69.33333333333333,
"dataSize"
: 416,
"storageSize"
: 20480,
"numExtents"
: 3,
"indexes"
: 2,
"indexSize"
: 16352,
"fileSize"
: 67108864,
"nsSizeMB"
: 16,
"extentFreeList"
: {
"num"
: 0,
"totalSize"
: 0
},
"dataFileVersion"
: {
"major"
: 4,
"minor"
: 22
},
"ok"
: 1,
"$gleStats"
: {
"lastOpTime"
: Timestamp(0, 0),
"electionId"
: ObjectId(
"586286596422d63aa9f9f000"
)
}
},
"shard2/182.48.115.236:27019,182.48.115.237:27019,182.48.115.238:27019"
: {
"db"
:
"test2"
,
"collections"
: 0,
"objects"
: 0,
"avgObjSize"
: 0,
"dataSize"
: 0,
"storageSize"
: 0,
"numExtents"
: 0,
"indexes"
: 0,
"indexSize"
: 0,
"fileSize"
: 0,
"ok"
: 1
}
},
"objects"
: 6,
"avgObjSize"
: 69,
"dataSize"
: 416,
"storageSize"
: 20480,
"numExtents"
: 3,
"indexes"
: 2,
"indexSize"
: 16352,
"fileSize"
: 67108864,
"extentFreeList"
: {
"num"
: 0,
"totalSize"
: 0
},
"ok"
: 1
}
mongos> db.books.stats();
{
"sharded"
:
true
,
"paddingFactorNote"
:
"paddingFactor is unused and unmaintained in 3.0. It remains hard coded to 1.0 for c ompatibility only."
,
"userFlags"
: 1,
"capped"
:
false
,
"ns"
:
"test2.books"
,
"count"
: 0,
"numExtents"
: 1,
"size"
: 0,
"storageSize"
: 8192,
"totalIndexSize"
: 16352,
"indexSizes"
: {
"_id_"
: 8176,
"id_1"
: 8176
},
"avgObjSize"
: 0,
"nindexes"
: 2,
"nchunks"
: 1,
"shards"
: {
"s1"
: {
"ns"
:
"test2.books"
,
"count"
: 0,
"size"
: 0,
"numExtents"
: 1,
"storageSize"
: 8192,
"lastExtentSize"
: 8192,
"paddingFactor"
: 1,
"paddingFactorNote"
:
"paddingFactor is unused and unmaintained in 3.0. It remains hard co ded to 1.0 for compatibility only."
,
"userFlags"
: 1,
"capped"
:
false
,
"nindexes"
: 2,
"totalIndexSize"
: 16352,
"indexSizes"
: {
"_id_"
: 8176,
"id_1"
: 8176
},
"ok"
: 1,
"$gleStats"
: {
"lastOpTime"
: Timestamp(0, 0),
"electionId"
: ObjectId(
"586286596422d63aa9f9f000"
)
}
}
},
"ok"
: 1
}
7)测试
mongos>
for
(var i = 1; i <= 20000; i++) db.books.save({
id
:i,name:
"12345678"
,sex:
"male"
,age:27,value:
"test"
});
WriteResult({
"nInserted"
: 1 })
mongos> db.books.stats();
{
"sharded"
:
true
,
"paddingFactorNote"
:
"paddingFactor is unused and unmaintained in 3.0. It remains hard coded to 1.0 for compatibility only."
,
"userFlags"
: 1,
"capped"
:
false
,
"ns"
:
"test2.books"
,
"count"
: 20000,
"numExtents"
: 10,
"size"
: 2240000,
"storageSize"
: 5586944,
"totalIndexSize"
: 1250928,
"indexSizes"
: {
"_id_"
: 670432,
"id_1"
: 580496
},
"avgObjSize"
: 112,
"nindexes"
: 2,
"nchunks"
: 5,
"shards"
: {
"s1"
: {
"ns"
:
"test2.books"
,
"count"
: 12300,
"size"
: 1377600,
"avgObjSize"
: 112,
"numExtents"
: 5,
"storageSize"
: 2793472,
"lastExtentSize"
: 2097152,
"paddingFactor"
: 1,
"paddingFactorNote"
:
"paddingFactor is unused and unmaintained in 3.0. It remains hard coded to 1.0 for compatibility only."
,
"userFlags"
: 1,
"capped"
:
false
,
"nindexes"
: 2,
"totalIndexSize"
: 760368,
"indexSizes"
: {
"_id_"
: 408800,
"id_1"
: 351568
},
"ok"
: 1,
"$gleStats"
: {
"lastOpTime"
: Timestamp(0, 0),
"electionId"
: ObjectId(
"586286596422d63aa9f9f000"
)
}
},
"s2"
: {
"ns"
:
"test2.books"
,
"count"
: 7700,
"size"
: 862400,
"avgObjSize"
: 112,
"numExtents"
: 5,
"storageSize"
: 2793472,
"lastExtentSize"
: 2097152,
"paddingFactor"
: 1,
"paddingFactorNote"
:
"paddingFactor is unused and unmaintained in 3.0. It remains hard coded to 1.0 for compatibility only."
,
"userFlags"
: 1,
"capped"
:
false
,
"nindexes"
: 2,
"totalIndexSize"
: 490560,
"indexSizes"
: {
"_id_"
: 261632,
"id_1"
: 228928
},
"ok"
: 1,
"$gleStats"
: {
"lastOpTime"
: Timestamp(0, 0),
"electionId"
: ObjectId(
"58628704f916bb05014c5ea7"
)
}
}
},
"ok"
: 1
}