1 mongo分片概念介绍
1.1 分片的背景需求
高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽。
大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。
为了解决这些问题,有两个基本的方法: 垂直扩展和水平扩展。
垂直扩展:增加更多的CPU和存储资源来扩展容量。
水平扩展:将数据集分布在多个服务器上。水平扩展即分片。
1.2 分片机制的三种优势
1.对集群进行抽象,让集群“不可见”
MongoDB自带了一个叫做mongos的专有路由进程。mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。
2.保证集群总是可读写
MongoDB通过多种途径来确保集群的可用性和可靠性。将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每分数据都有相应的备份,这样就可以确保有服务器换掉时,其他的从库可以立即接替坏掉的部分继续工作。
3.使集群易于扩展
当系统需要更多的空间和资源的时候,MongoDB使我们可以按需方便的扩充系统容量。
1.3 集群架构图
mongos
数据路由,和客户端打交道的模块。mongos本身没有任何数据,他也不知道该怎么处理这数据,去找config server。
config server
所有shard节点的信息、存取数据的方式,分片功能的一些配置信息。可以理解为真实数据的元数据。
shard
真正的数据存储位置,以chunk为单位存数据。
1.4 存储数据chunk
在一个shard server内部,MongoDB还是会把数据分为chunks,每个chunk代表这个shard server内部一部分数据。
分片集群节点的数据分布
(1)使用chunk来存储数据
(2)进群搭建完成之后,默认开启一个chunk,大小是64M,
(3)存储需求超过64M,chunk会进行分裂,如果单位时间存储需求很大,设置更大的chunk
(4)chunk会被自动均衡迁移。
chunkSize对分裂及迁移的影响
MongoDB默认的chunkSize为64MB,如无特殊需求,建议保持默认值;chunkSize会直接影响到chunk分裂、迁移的行为。
chunkSize越小,chunk分裂及迁移越多,数据分布越均衡;反之,chunkSize越大,chunk分裂及迁移会更少,但可能导致数据分布不均。
chunk自动分裂只会在数据写入时触发,所以如果将chunkSize改小,系统需要一定的时间来将chunk分裂到指定的大小。
chunk只会分裂,不会合并,所以即使将chunkSize改大,现有的 chunk数量不会减少,但chunk大小会随着写入不断增长,直到达到目标大小。
1.5 shard key分片键
MongoDB中数据的分片是、以集合为基本单位的,集合中的数据通过片键(Shard key)被分成多部分。其实片键就是在集合中选一个键,用该键的值作为数据拆分的依据。MongoDB按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。
分片键是不可变。
分片键必须有索引。
分片键大小限制512bytes。
分片键用于路由查询。
键的文档(不支持空值插入)
两种分片方式为
基于范围的分片方式。
基于哈希的分片方式。
2 搭建分片集群
2.1 主机系统环境说明
[root@mongo03 ~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[root@mongo03 ~]# uname -r
3.10.0-1062.12.1.el7.x86_64
2.2 服务器角色规划
操作系统 |
mongo版本 |
主机ip |
角色 |
CentOS Linux release 7.7.1908 (Core) |
mongodb4.2 |
192.168.32.132 |
shard1 shard2 config mongos |
CentOS Linux release 7.7.1908 (Core) |
mongodb4.2 |
192.168.32.134 |
shard1 shard2 config |
CentOS Linux release 7.7.1908 (Core) |
mongodb4.2 |
192.168.32.135 |
shard1 shard2 config |
2.3 搭建mongodb分片复制集
2.3.1 下载mongo包
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.0.tgz
[root@mongo01 ~]# tar -xzvf mongodb-linux-x86_64-rhel70-4.2.0.tgz -C /opt
mv mongodb-linux-x86_64-rhel70-4.2.0/ mongodb
2.3.3 创建相关目录
mkdir -p /opt/mongodb/mongos/log
mkdir -p /opt/mongodb/config/data
mkdir -p /opt/mongodb/config/log
mkdir -p /opt/mongodb/shard1/data
mkdir -p /opt/mongodb/shard1/log
mkdir -p /opt/mongodb/shard2/data
mkdir -p /opt/mongodb/shard2/log
2.3.3 环境变量
vim /etc/profile
export MONGODB_HOME=/opt/mongodb/
export PATH=MONGODB_HOME/bin:PATH
source /etc/profile
2.3.4 搭建config节点复制集
1.修改对应的配置文件
[root@mongo01 mongodb]# cat mongo-cfg.conf
systemLog:
destination: file
path: /opt/mongodb/config/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /opt/mongodb/config/data
# 是否一个库一个文件夹
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
# 最大使用cache(根据真实情况自行调节)
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
# 表压缩配置
blockCompressor: zlib
indexConfig:
prefixCompression: true
net:
bindIp: 192.168.32.132
port: 28018
replication:
oplogSizeMB: 2048
# 配置节点的复制集名字
replSetName: configReplSet
sharding:
clusterRole: configsvr
processManagement:
fork: true
另外两个节点修改对应的ip地址。
2.启动配置复制集
/opt/mongodb/bin/mongod -f /opt/mongodb/mongo-cfg.conf
另外两个节点一样操作
3.登录配置节点
[root@mongo01 mongodb]# /opt/mongodb/bin/mongo -host 192.168.32.132 -port 28018 admin
4.初始化命令
rs.initiate(
{
"_id" : "configReplSet",
"members" : [
{"_id" : 0, "host" : "192.168.32.132:28018"},
{"_id" : 1, "host" : "192.168.32.134:28018"},
{"_id" : 2, "host" : "192.168.32.135:28018"}
]
}
)
2.3.5 shard集群配置
1.分片1配置(三个节点配置相同)
cat mongod1.conf
systemLog:
destination: file
path: "//opt/mongodb/shard1/log/mongo.log"
logAppend: true
storage:
journal:
enabled: true
dbPath: "/opt/mongodb/shard1/data"
processManagement:
fork: true
net:
bindIp: 0.0.0.0
port: 27017
setParameter:
enableLocalhostAuthBypass: false
replication:
replSetName: "shard1_repl"
sharding:
clusterRole: shardsvr
2.分片2配置(三个节点配置相同)
cat mongod2.conf
systemLog:
destination: file
path: "/opt/mongodb/shard2/log/mongo.log"
logAppend: true
storage:
journal:
enabled: true
dbPath: "/opt/mongodb/shard2/data"
processManagement:
fork: true
net:
bindIp: 0.0.0.0
port: 27018
setParameter:
enableLocalhostAuthBypass: false
replication:
replSetName: "shard2_repl"
sharding:
clusterRole: shardsvr
3.启动副本集(每台启动)
/opt/mongodb/bin/mongod -f /opt/mongodb/mongod1.conf
/opt/mongodb/bin/mongod -f /opt/mongodb/mongod2.conf
4. 初始化集群
shard1:
/opt/mongodb/bin/mongo -port 27017 admin
config = {_id: 'shard1_repl', members: [
{_id: 0, host: '192.168.32.132:27017'},
{_id: 1, host: '192.168.32.134:27017'},
{_id: 2, host: '192.168.32.135:27017'}]
}
rs.initiate(config)
查看
rs.status();
shard2:
/opt/mongodb/bin/mongo -port 27018 admin
# 配置复制集
config = {_id: 'shard2_repl', members: [
{_id: 0, host: '192.168.32.132:27018'},
{_id: 1, host: '192.168.32.134:27018'},
{_id: 2, host: '192.168.32.135:27018'}]
}
# 初始化配置
rs.initiate(config)
三副本模式可以改成两副本+仲裁模式:
rs.initiate(
{
_id : "shard2_repl",
members: [
{ _id : 0, host : "192.168.32.132:27018" ,priority : 2 },
{ _id : 1, host : "192.168.32.134:27018" ,priority : 1 },
{ _id : 2, host : "192.168.32.135:27018" ,arbiterOnly :true }
]
}
)
注释:priority默认为0,priority越大越有可能成为master。
2.3.6 mongos节点配置
cat mongos.conf
systemLog:
destination: file
path: /opt/mongodb/mongos/log/mongos.log
logAppend: true
net:
bindIp: 192.168.32.132
port: 27019
sharding:
configDB: configReplSet/192.168.32.132:28018,192.168.32.134:28018,192.168.32.135:28018
processManagement:
fork: true
启动mongos
/opt/mongodb/bin/mongos -f /opt/mongodb/mongos.conf
2.3.7 添加集群中的分片节点
/opt/mongodb/bin/mongo -host 192.168.32.132 -port 27019
use admin
添加shard1复制集
db.runCommand( { addshard : "shard1_repl/192.168.32.132:27017,192.168.32.134:27017,192.168.32.135:27017",name:"shard1"} )
添加shard2复制集
db.runCommand( { addshard : "shard2_repl/192.168.32.132:27018,192.168.32.134:27018,192.168.32.135:27018",name:"shard2"} )
列出分片
db.runCommand( { listshards : 1 } )
{
"shards" : [
{
"_id" : "shard1",
"host" : "shard1_repl/192.168.32.132:27017,192.168.32.134:27017,192.168.32.135:27017",
"state" : 1
},
{
"_id" : "shard2",
"host" : "shard2_repl/192.168.32.132:27018,192.168.32.134:27018,192.168.32.135:27018",
"state" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1584545902, 2),
"clusterTime" : {
"clusterTime" : Timestamp(1584545902, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
查看分片状态
mongos> sh.status();
--- Sharding Status --- sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("5e7239bec4f61270d589e367")
}
shards:
{ "_id" : "shard1", "host" : "shard1_repl/192.168.32.132:27017,192.168.32.134:27017,192.168.32.135:27017", "state" : 1 }
{ "_id" : "shard2", "host" : "shard2_repl/192.168.32.132:27018,192.168.32.134:27018,192.168.32.135:27018", "state" : 1 }
active mongoses:
"4.2.0" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours: No recent migrations
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 1
{ "_id" : { "minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : shard1 Timestamp(1, 0)
3 测试分片集群
3.1 激活数据库分片功能
mongos> use admin
switched to db admin
mongos> db.runCommand( { enablesharding : "testdb" } )
{
"ok" : 1,
"operationTime" : Timestamp(1584546852, 9),
"$clusterTime" : {
"clusterTime" : Timestamp(1584546852, 9),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
3.2 创建索引
use testdb
db.users.ensureIndex( { id: 1 } )
3.3 创建分片的键(id)
db.runCommand( { shardcollection : "testdb.users",key : {id: 1} } )
3.4 集合分片验证
创建测试数据,用来测试分片功能,下面的代码向数据库中插入了200w条数据,由于数据量比较大,所以批量插入的时候,时间会稍微有点久.
var arr=[];
for(var i=0;i<2000000;i++){
var uid = i;
var name = "mongodb"+i;
arr.push({"id":uid,"name":name});
}
db.users.insertMany(arr);
或者这种方式插入数据
for(var i=0;i<2000000;i++){ var uid = i; var name = "mongodb"+i; arr.push({"id":uid,"name":name}); }
mongos> sh.status()
3.5 分片集群的一些命令
删除分片节点
sh.getBalancerState()
mongos> db.runCommand( { removeShard: "shard2" } )
修改chunk大小
use config
db.settings.save( { _id:"chunksize", value: 1 } )
不同分片键的配置
范围片键
admin> sh.shardCollection("数据库名称.集合名称",key : {分片键: 1} )
或
admin> db.runCommand( { shardcollection : "数据库名称.集合名称",key : {分片键: 1} } )
eg:
admin > sh.shardCollection("test.vast",key : {id: 1} )
或
admin> db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )
哈希片键
admin > sh.shardCollection( "数据库名.集合名", { 片键: "hashed" } )
创建哈希索引
admin> db.vast.ensureIndex( { a: "hashed" } )
admin > sh.shardCollection( "test.vast", { a: "hashed" } )
列出所有分片信息
admin> db.runCommand({ listshards : 1})
列出开启分片的数据库
admin> use config
config> db.databases.find( { "partitioned": true } )
config> db.databases.find() //列出所有数据库分片情况
查看分片的片键
{
"_id" : "config.system.sessions",
"lastmodEpoch" : ObjectId("5e72400747db9a3f25ab7a47"),
"lastmod" : ISODate("1970-02-19T17:02:47.296Z"),
"dropped" : false,
"key" : {
"_id" : 1
},
"unique" : false,
"uuid" : UUID("7b81483c-787d-496f-ad74-f631d810ac82")
}
4 balance操作
4.1 balance基础操作
查看mongo集群是否开启了 balance 状态
mongos> sh.getBalancerState()
true
4.2 如果balance开启,查看是否正在有数据的迁移
mongos> sh.isBalancerRunning()
false
4.2 设置balance窗口
切换到配置节点
mongos> use config
switched to db config
开启balance
mongos> sh.setBalancerState( true )
{
"ok" : 1,
"operationTime" : Timestamp(1585230316, 1),
"clusterTime" : {
"clusterTime" : Timestamp(1585230316, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
确定balance 是否开启
mongos> sh.getBalancerState()
true
修改balance 窗口的时间
命令如下
db.settings.update(
{ _id: "balancer" },
{set: { activeWindow : { start : "<start-time>", stop : "<stop-time>" } } },
{ upsert: true }
)
例子:
mongos> db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "00:00", stop : "5:00" } } }, true )
查看Balancer运行时间窗口
mongos> db.settings.find();
{ "_id" : "balancer", "mode" : "full", "stopped" : true, "activeWindow" : { "start" : "00:00", "stop" : "5:00" } }
{ "_id" : "autosplit", "enabled" : true }
mongos> sh.getBalancerWindow()
{ "start" : "00:00", "stop" : "5:00" }
4.3 删除balance 窗口
use config
mongos> db.settings.update({ _id : "balancer" }, { $unset : { activeWindow : true } })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
4.4 关闭balance
停止balance
mongos> sh.stopBalancer()
{
"ok" : 1,
"operationTime" : Timestamp(1585230548, 2),
"$clusterTime" : {
"clusterTime" : Timestamp(1585230548, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
查看balance状态
mongos> sh.getBalancerState()
false
停止balance 后,没有迁移进程正在迁移,可以执行下列命令
use config
while( sh.isBalancerRunning() ) {
print("waiting...");
sleep(1000);
}
4.5 重新打开balance
打开balance
mongos> sh.setBalancerState(true)
{
"ok" : 1,
"operationTime" : Timestamp(1585230700, 2),
"$clusterTime" : {
"clusterTime" : Timestamp(1585230700, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
查看blance状态
mongos> sh.getBalancerState()
true
4.6 打开或关闭某个集群的balance
关闭某个集合的balance
mongos> sh.disableBalancing("testdb.table1")
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
打开某个集合的balance
mongos> sh.enableBalancing("testdb.table1")
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })