啥是分片
分片(sharding)是MongoDB用来将大型集合水平分割到不同服务器(或者复制集)上所采用的方法。不需要很强大的大型计算机就可以存储更多的数据,处理更大的负载
为啥要分片
- 存储容量需求超出单机磁盘容量
- 活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能。
- IOPS超出单个MongoDB节点的服务能力,随着数据的增长,单机实例的瓶颈会越来越明显
- 副本集具有节点数量限制
ps:垂直拓展vs水平拓展
垂直拓展:增加更多的cpu和存储资源来扩展容量
水平拓展:将数据集分布在多个服务器上。上面说的分片就是水平拓展
分片的工作原理
分片集群由3个服务组成:
Shards Server:每个shard有一个或者多个Mongod进程组成,用来存储数据
Router Server:数据库集群的请求入口,所有请求都是通过router进行协调,不需要在应用程序中添加路由选择器,router就是一个请求分发中心,他负责将应用程序的请求转发到对应的shard服务上。
Config Server:配置服务, 存储所有数据库元信息(路由,分片)的配置。
片键:shard key,为了在数据集合中分配文档,MongoDB使用分片主键分割集合
区块:chunk,在一个shard server内部,MongoDB还是会吧数据分为chunks,每个chunk代表这个shard server内部一部分数据。MongoDB分割分片数据到区块,每一个区块包含基于分片主键的左闭右开的区间范围。
分片策略
-
范围分片(Range based sharding)
范围分片是根据分片主键的值切分数据,每一个区块会分到一个范围。范围分片是够满足在一定范围内查找,缺点是如果shard key有明显的递增或递减趋势,会导致新插入的文档多会分布到同一个chunk,无法拓展写的能力
-
hash分片
Hash分片是计算一个分片主键的hash值,每一个区块分配到一个范围的hash值
hash分片与范围分片互补,能将文档随机分配到各个区块,充分拓展写能力,弥补了范围分片的不足,缺点就是不能高效的服务范围查询,所有的范围查询要查询所有shard才能找到满足条件的文档
分片集群搭建
以我本机为例,搭建一个单服务器的伪集群,过程与真正的多服务集群没有差别
集群架构如“”分片原理”中的架构图
路由节点:端口27017
配置集群:3个配置节点 端口分别为17011,17013,17015
分片节点集群:4个复制集集群,每一个复制集中3台数据节点,一台仲裁节点
首先安装mongo(可以参考我的另一篇《centos下安装mangodb(社区版)》)
这里我安装在/usr/local/mongodb/shard/mongo/目录下
1.配置并启动config集群节点
1).配置config节点集群
在/usr/local/mongodb/shard/mongo/目录下创建三个目录
mkdir config/config1 -p
mkdir config/config2 -p
mkdir config/config3 -p
这是三个目录用来放置配置服务的数据库文件
创建日志文件目录(在config下)
mkdir config/logs -p
最终目录结构:
在config目录下分别创建config集群节点的配置文件
congfig-17011.conf
# 数据库文件位置
dbpath=config/config1
#日志文件位置
logpath=config/logs/config1.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork = true
bind_ip=0.0.0.0
port = 17011
# 表示是一个配置服务器
configsvr=true
#配置服务器副本集名称
replSet=configsvr
congfig-17013.conf
# 数据库文件位置
dbpath=config/config2
#日志文件位置
logpath=config/logs/config2.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork = true
bind_ip=0.0.0.0
port = 17013
# 表示是一个配置服务器
configsvr=true
#配置服务器副本集名称
replSet=configsvr
congfig-17015.conf
# 数据库文件位置
dbpath=config/config3
#日志文件位置
logpath=config/logs/config3.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork = true
bind_ip=0.0.0.0
port = 17015
# 表示是一个配置服务器
configsvr=true
#配置服务器副本集名称
replSet=configsvr
2).启动配置节点
./bin/mongod -f config/config-17011.conf
./bin/mongod -f config/config-17013.conf
./bin/mongod -f config/config-17015.conf
启动成功后查看进程:
3).启动成功后进入任意节点mongo shell 配置节点集群,注意要使用admin
./bin/mongo --port 17011
use admin
var cfg ={"_id":"configsvr",
"members":[ {"_id":1,"host":"10.9.147.132:17011"}, {"_id":2,"host":"10.9.147.132:17013"},
{"_id":3,"host":"10.9.147.132:17015"}] };
rs.initiate(cfg)
rs.status()//查看集群状态
2.配置shard集群
复制集节点集群1搭建37011,37013,37015,37017,其中37017为仲裁节点
1)创建集群1的目录结构
cd 到目录/usr/local/mongodb/shard/mongo
mkdir shard/shard1/shard1-37011 -p
mkdir shard/shard1/shard1-37013 -p
mkdir shard/shard1/shard1-37015 -p
mkdir shard/shard1/shard1-37017 -p
mkdir shard/shard1/logs -p
mkdir shard/shard1/config-p
在shard1/config目录下分别配置37011-37017的配置文件
shard1-37011.conf
dbpath=shard/shard1/shard1-37011
bind_ip=0.0.0.0
port=37011
fork=true
logpath=shard/shard1/logs/shard1-37011.log
replSet=shard1
shardsvr=true
shard1-37013.conf
dbpath=shard/shard1/shard1-37013
bind_ip=0.0.0.0
port=37013
fork=true
logpath=shard/shard1/logs/shard1-37013.log
replSet=shard1
shardsvr=true
shard1-37015.conf
dbpath=shard/shard1/shard1-37015
bind_ip=0.0.0.0
port=37015
fork=true
logpath=shard/shard1/logs/shard1-37015.log
replSet=shard1
shardsvr=true
shard1-37017.conf
dbpath=shard/shard1/shard1-37017
bind_ip=0.0.0.0
port=37017
fork=truecd
logpath=shard/shard1/logs/shard1-37017.log
replSet=shard1
shardsvr=true
2)启动并配置集群
启动:
./bin/mongod -f shard/shard1/config/shard1-37011.conf
./bin/mongod -f shard/shard1/config/shard1-37013.conf
./bin/mongod -f shard/shard1/config/shard1-37015.conf
./bin/mongod -f shard/shard1/config/shard1-37017.conf
配置:
启动之后进入任一节点,例如37011
./bin/mongo --port 37011
var cfg ={"_id":"shard1", "protocolVersion" : 1, "members":[ {"_id":1,"host":"10.9.147.132:37011"}, {"_id":2,"host":"10.9.147.132:37013"}, {"_id":3,"host":"10.9.147.132:37015"}, {"_id":4,"host":"10.9.147.132:37017","arbiterOnly":true} ]};
# ps:注意节点4,arbiterOnly=true表示为仲裁节点
rs.initiate(cfg) #初始化节点
rs.status() #查看节点状态
其他三个分片,shard2,shard3,shard4与shard1搭建方法一致,只是文件目录和配置有差别,可参考上面方法搭建,不再一一赘述
3.配置和启动路由节点
在/usr/local/mongodb/shard/mongo目录下创建route目录,用来放置路由节点
mkdir route
mkdir route/log -p
在route目录下创建配置文件
route-27017.conf
port=27017
bind_ip=0.0.0.0
fork=true
logpath=route/logs/route.log
configdb=configsvr/10.9.147.132:17011,10.9.147.132:17013,10.9.147.132:17015 #配置服务节点:wq
启动路由节点
./bin/mongos -f route/route-27017.conf
注意启动路由的命令是mongos
4.mongos(路由)中添加分片节点
进入路由服务
./bin/mongo --port 27017
#添加分片节点(即上面配置的4个复制集节点shard1,shard2,shard3,shard4)
sh.addShard("shard1/10.9.147.132:37011,10.9.147.132:37013,10.9.147.132:37015,10.9.147.132:37017")
sh.addShard("shard2/10.9.147.132:47011,10.9.147.132:47013,10.9.147.132:47015,10.9.147.132:47017")
sh.addShard("shard3/10.9.147.132:57011,10.9.147.132:57013,10.9.147.132:57015,10.9.147.132:57017")
sh.addShard("shard4/10.9.147.132:58011,10.9.147.132:58013,10.9.147.132:58015,10.9.147.132:58017")
#查看服务状态
sh.status()
5.开启数据库和集合分片(指定片键)
为数据库开启分片功能
sh.enableSharding(“test_db”)
为指定集合开启分片功能
sh.shardCollection(“test_db.test_datas”,{“片键字段名如 name”:索引说 明})
这里我们使用hash分片
sh.shardCollection(“test_db.test_datas”,{“name”:“hashed”})
补充说明:
1.如何查看建立的片键
进入路由节点:
use config
db.getCollection("collections").find({})
就可以查询出所有的分片键
2.如何删除片键
db.collections.remove({_id:"1中查询出的片键id"})
# 注意删除片键后还要进行以下操作才能从新建立片键,否则报错
db.chunks.remove({ns:"1中查询出的片键id"})
db.locks.remove({_id:"1中查询出的片键id"})
use admin
db.adminCommand("flushRouterConfig)
6.插入测试数据
通过路由循环向集合中添加数据
use test_db
for(var i=1;i<= 1000;i++){
db.test_datas.insert({"name":"test"+i,
salary:(Math.random()*20000).toFixed(2)}); }
7.验证分片效果
进入任意一个分片中查看,例如shard1
./bin/mongo --port 37011
show dbs
这里可以看到shard1中已经有数据库test_db
use test_db
show collections
这里可以看到已经有集合test_datas
db.test_datas.count()
这里可以看到在shard1中存储了253条数据
8.总结
一个3个核心部分:
配置服务复制集节点:用来存放我们分片集群的配置信息
分片复制集节点:用来存储数据的分片
路由节点:作为分片集群的统一入口,我们对分片集群的读写操作都是通过路由来进行操作的,就好像在操作一个单实例数据库,集群分片的细节对于我们来说是透明的,分片的细节由路由来完成。
至此,mongo分片集群的搭建介绍完毕~~~