MongoDB Sharding Cluster 分片集群
1、分片(sharding)是MongoDB将大型集合分割到不同服务器(或者说多个集群)上的方法。和MySQL分区相比,MongoDB的几乎能自动完成所有事情,只要告诉MongoDB要分配数据,它就能自动维护数据在不同服务器之间的均衡。
2、分片的目的
大数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大查询量会增大单机的CPU和存储压力。为了解决这些问题,有两个方法:垂直扩展和水平扩展。
垂直扩展:增加更多的CPU和存储资源来扩展容量。
水平扩展:将数据集分布在多个服务器上,即分片。
3、分片机制提供了如下三种优势
1)对集群进行抽象,让集群“不可见”。
MongoDB自带了叫做mongos的专有路由进程。mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。
2)保证集群总是可读写
MongoDB通过多种途径来确保集群的可用性和可靠性。将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每份数据都有相应的备份,这样就可以确保有服务器坏掉时,其他的从库可以立即接替坏掉的部分继续工作。
3)使集群易于扩展
当系统需要更多的空间和资源的时候, MongoDB使我们可以按需方便的扩充系统容量。
4、分片集群的构造
1)mongos :数据路由,和客户端打交道的模块。
mongos本身没有任何数据,他也不知道该怎么处理这些数据,去找config server。
2)Config server:所有存、取数据的方式,所有shard节点的信息,分片功能一些配置信息。可以理解为真实数据的元数据。
3)shard:真正的数据存储位置,以chunk为单位存数据(64M)。
Mongos本身并不持久化数据,Sharded cluster所有的元数据都会存储到Config Server,而用户的数据会分散存储到各个shard。
Mongos启动后,会从配置服务器加载元数据,开始提供服务,将用户的请求正确路由到对应的碎片。
MongoDB官方参考文档:https://www.mongodb.com/zh-cn/docs/manual/
实验环境
安装好MongoDB
实验步骤
规划:
10个实例:38017-38026
1)shard节点:
sh1:38021-23 (1主两从,其中一个节点为arbiter,复制集名字sh1)
sh2:38024-26 (1主两从,其中一个节点为arbiter,复制集名字sh2)
2)Config server:
3台构成的复制集(1主两从,不支持arbiter)38018-38020(复制集名字configsvr)
3)mongos: 路由节点
1台服务器或一组复制集 38017
配置过程:
1、shard复制集配置
1)创建多实例目录
su - mongod
mkdir -p /mongodb/380{21..26}/{conf,log,data}
2)创建配置文件
sh1:
cat > /mongodb/38021/conf/mongodb.conf<<EOF
systemLog:
destination: file
path: /mongodb/38021/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/38021/data
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
net:
bindIp: 192.168.8.5,127.0.0.1
port: 38021
replication:
oplogSizeMB: 2048
replSetName: sh1
sharding:
clusterRole: shardsvr
processManagement:
fork: true
EOF
cp /mongodb/38021/conf/mongodb.conf /mongodb/38022/conf/
cp /mongodb/38021/conf/mongodb.conf /mongodb/38023/conf/
sed -i 's#38021#38022#g' /mongodb/38022/conf/mongodb.conf
sed -i 's#38021#38023#g' /mongodb/38023/conf/mongodb.conf
sh2:
cat > /mongodb/38024/conf/mongodb.conf<<EOF
systemLog:
destination: file
path: /mongodb/38024/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/38024/data
directoryPerDB: true
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
net:
bindIp: 192.168.8.5,127.0.0.1
port: 38024
replication:
oplogSizeMB: 2048
replSetName: sh2
sharding:
clusterRole: shardsvr
processManagement:
fork: true
EOF
cp /mongodb/38024/conf/mongodb.conf /mongodb/38025/conf/
cp /mongodb/38024/conf/mongodb.conf /mongodb/38026/conf/
sed -i 's#38024#38025#g' /mongodb/38025/conf/mongodb.conf
sed -i 's#38024#38026#g' /mongodb/38026/conf/mongodb.conf
配置文件解释:
logAppend: true ——在MongoDB的配置文件中表示日志文件采用追加模式,而不是覆盖模式。
directoryPerDB ——用于控制数据库文件的存储方式。当设置为
true时,每个数据库的数据文件将存储在一个单独的目录中;当设置为false时,所有数据库的数据文件将存储在同一个目录中。
WiredTiger ——是一个高性能、多核扩展性强、支持事务的存储引擎,由MongoDB从3.2版本开始默认使用。
prefixCompression(前缀压缩) ——是一种数据压缩技术,通过存储词项间的共同前缀来减少冗余。例如,对于词项[“compression”, “compressed”, “compressor”],可以存储为[“compression”, “7ed”, “7or”],其中7表示前7个字符相同。
前缀压缩在数据库和索引设计中有着重要的应用。例如,在SQL Server中,前缀压缩可以用于优化存储和查询性能。通过减少存储空间和提高数据加载速度,前缀压缩能够显著提升数据库的整体性能。此外,前缀压缩还可以应用于MongoDB等分布式存储引擎中,帮助优化存储效率和查询性能。
fork ——MongoDB会在后台运行,并且创建一个子进程。
3)启动所有实例节点
mongod -f /mongodb/38021/conf/mongodb.conf
mongod -f /mongodb/38022/conf/mongodb.conf
mongod -f /mongodb/38023/conf/mongodb.conf
mongod -f /mongodb/38024/conf/mongodb.conf
mongod -f /mongodb/38025/conf/mongodb.conf
mongod -f /mongodb/38026/conf/mongodb.conf
netstat -anpt | grep mongod
4)搭建复制集
sh1:
mongo -port 38021 admin
config = {_id: 'sh1', members: [
{_id: 0, host: '192.168.8.5:38021'},
{_id: 1, host: '192.168.8.5:38022'},
{_id: 2, host: '192.168.8.5:38023',"arbiterOnly":true}]
}
初始化副本集
rs.initiate(config)
输入命令前面变成复制集的状态,一开始是SECONARY等待变成PRIMARY
sh2:
mongo -port 38024 admin
config = {_id: 'sh2', members: [
{_id: 0, host: '192.168.8.5:38024'},
{_id: 1, host: '192.168.8.5:38025'},
{_id: 2, host: '192.168.8.5:38026',"arbiterOnly":true}]
}
初始化副本集
rs.initiate(config)
输入命令前面变成复制集的状态,一开始是SECONARY等待变成PRIMARY
2、config节点配置
1)创建多实例目录
mkdir -p /mongodb/380{18..20}/{conf,log,data}
2)创建配置文件
cat > /mongodb/38018/conf/mongodb.conf <<EOF
systemLog:
destination: file
path: /mongodb/38018/log/mongodb.conf
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/38018/data
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
net:
bindIp: 192.168.8.5,127.0.0.1
port: 38018
replication:
oplogSizeMB: 2048
replSetName: configReplSet
sharding:
clusterRole: configsvr
processManagement:
fork: true
EOF
cp /mongodb/38018/conf/mongodb.conf /mongodb/38019/conf/
cp /mongodb/38018/conf/mongodb.conf /mongodb/38020/conf/
sed -i 's#38018#38019#g' /mongodb/38019/conf/mongodb.conf
sed -i 's#38018#38020#g' /mongodb/38020/conf/mongodb.conf
3)启动所有实例节点
mongod -f /mongodb/38018/conf/mongodb.conf
mongod -f /mongodb/38019/conf/mongodb.conf
mongod -f /mongodb/38020/conf/mongodb.conf
netstat -anpt | grep mongod
4)搭建复制集
mongo -port 38018 admin
config = {_id: 'configReplSet', members: [
{_id: 0, host: '192.168.8.5:38018'},
{_id: 1, host: '192.168.8.5:38019'},
{_id: 2, host: '192.168.8.5:38020'}]
}
初始化副本集
rs.initiate(config)
输入命令前面变成复制集的状态,一开始是SECONARY等待变成PRIMARY
注:Config server 可以是一个节点,官方建议复制集。Config server不能有arbiter(仲裁)。新版本中,要求必须是复制集。
注:MongoDB 3.4之后,虽然要求Config server为replica set,但是不支持arbiter
3、路由(mongos)节点配置
1)创建实例目录
mkdir -p /mongodb/38017/{conf,log}
2)创建配置文件
cat > /mongodb/38017/conf/mongos.conf << EOF
systemLog:
destination: file
path: /mongodb/38017/log/mongos.log
logAppend: true
net:
bindIp: 192.168.8.5,127.0.0.1
port: 38017
sharding:
configDB: configReplSet/192.168.8.5:38018,192.168.8.5:38019,192.168.8.5:38020
processManagement:
fork: true
EOF
3)启动路由(mongos)节点
mongos -f /mongodb/38017/conf/mongos.conf
netstat -anpt | grep mongos
4、分片集群操作
1)连接到mongos的admin数据库
mongo 192.168.8.5:38017/admin
2)添加分片
db.runCommand( { addshard : "sh1/192.168.8.5:38021,192.168.8.5:38022,192.168.8.5:38023",name:"shard1"} )
db.runCommand( { addshard : "sh2/192.168.8.5:38024,192.168.8.5:38025,192.168.8.5:38026",name:"shard2"} )
3)列出分片
db.runCommand ( { listshards : 1 } )
4)查看整体状态
sh.status()
分片方法:
范围分片-id,date类
定义:基数大、频率低、非单调变化(如果单调写,则会分到同一个块里面,容易达到chunk割裂的条件,产生chunk的搬运)
分析:存储倾斜、查询范围数据方便
Hash分片-订单号,uuid等类
定义:应该有良好的基数或者该字段包含大量不同的值-防止出现数据倾斜
分析:存储分散、查询单条数据方便
哈希索引适合单调变化的字段,例如自增值,时间值等(因为可以将单调的字段通过hash函数映射到不同的块上去,从而分散写入压力,例如下图,虽然数据连续,但是写入了不同的数据块中)
联合分片-随机值+范围值组成的联合索引
分析:适合复杂场景
5、Hash分片
对hehe库下的大表进行hash
创建哈希索引
1)对hehe库开启分片功能
mongo -port 38017 admin
use admin
针对hehe库分片
db.runCommand( { enablesharding : "hehe" } )
2)对hehe库下的他t10w表建立hash索引
use hehe
db.t10w.ensureIndex( { id: "hashed" } )
3)开启分片
use admin
sh.shardCollection( "hehe.t10w", { id: "hashed" } )
4)往hehe库下的t10w表写入十万行数据进行测试
use hehe
for(i=1;i<100000;i++){ db.t10w.insert({"id":i,"name":"lisi","age":30,"date":new Date()}); }
5)查看hash分片结果
复制一个会话
会话二:
su – mongod
mongo -port 38021
use hehe
查看t10w表中行数
db.t10w.count()
数据在持续写入
在复制一个会话
会话三:
su – mongod
mongo -port 38024
use hehe
查看t10w表中行数
db.t10w.count()
数据在持续写入
当十万行数据写入之后,再进行查看
会话二:
db.t10w.count()
会话三:
db.t10w.count()
写入的数据进行了分片存储,分别存放到了shard1和shard2上
6、判断是否为shard集群,若返回 ok 为 1,则表示是分片
db.runCommand({ isdbgrid : 1})
7、列出所有分片信息
use admin
db.runCommand({ listshards : 1})
8、列出开启分片的数据库
use config
db.databases.find( { "partitioned": true } )
或
列出所有数据库分片情况
db.databases.find()
9、查看分片的片键
db.collections.find().pretty()
10、查看分片的详细信息(查询整个集群的状态,包括副本集、分片集、mongos数量、数据库分布在哪个分片上、有无开启平衡器等)
db.printShardingStatus()
或
sh.status()
两个命令显示结果相同
11、balancer操作
介绍:
mongos的一个重要功能,自动巡查所有shard节点上的chunk的情况,自动做chunk迁移。
什么时候工作?
1)自动运行,会检测系统不繁忙的时候做迁移
2)在做节点删除的时候,立即开始迁移工作
3)balancer只能在预设定的时间窗口内运行
有需要时可以关闭和开启blancer(备份的时候)
sh.stopBalancer()
sh.startBalancer()
12、删除分片节点(谨慎)
1)确认blance(平衡器)是否工作
sh.getBalancerState()
2)删除shard2节点(谨慎),访问量低的时候才会删除
use admin
db.runCommand( { removeShard: "shard2" } )
会话二:
登录shard1的主节点
su – mongod
mongo -port 38021
use hehe
查看数据
db.t10w.count()
shard2的数据会被自动传到shard1上
13、自动平衡进行的时间段
mongo -port 38017 admin
use config
启动平衡器(默认情况下,在任何需要移动块的时候,平衡器都会进行工作)
sh.setBalancerState(true)
设置负载均衡器的时间窗口
db.settings.update( { _id: "balancer" }, { $set: { activeWindow : { start : "3:00", stop : "5:00" } } }, { upsert: true } )
获取当前均衡器时间窗口
sh.getBalancerWindow()
查看分片的详细信息
sh.status()
删除时间窗口设置
db.settings.update({ _id : "balancer" }, { $unset : { activeWindow : true } })
获取当前均衡器时间窗口
sh.getBalancerWindow()
查看分片的详细信息
sh.status()
查看所有的监控状态
db.serverStatus()
查看网络流量信息
db.serverStatus().network
统计增删改查次数
db.serverStatus().opcounters
统计连接信息
db.serverStatus().connections