MongoDB分片

什么是MongoDB分片?

就是把数据库拆分,把所有的数据分散存放到不同的服务器上的过程

为什么要实现MongoDB分片?

为了解决数据的不断增加的方法 垂直扩展:增加CPU、硬盘等存储资源来扩展容量 水平扩展:将数据分布在多个服务器上,也就是会使用到分片技术 - 对集群进行抽象,让集群“不可见”,MongoDB自带了一个叫做mongos的专有路由进程 - 解决磁盘存储空间的问题,提高数据处理的性能 - 提高数据的安全性,保证集群总是可读写,将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每分数据都有相应的备份,这样就可以确保有服务器换掉时,其他的从库可以立即接替坏掉的部分继续工作 - 使集群易于扩展

分片集群中的主要组件:
mongos : 数据路由,用于对外应用访问,数据迁移和数据自动均衡
config : 存储记录集群所有节点和所有存、取数据的方式,所有shard节点的信息,分片功能的一些配置信息
shard: 真正的数据存储位置,以chunk为单位存数据

TOC

一、MongoDB分片群集搭建

★准备工作★

一共需要3台服务器,配置12个实例
mongs:192.168.31.101:27017、192.168.31.102:27017、192.168.31.103:27017
config:192.168.31.101:37017、192.168.31.102:37017、192.168.31.103:37017
shard1:192.168.31.101.27018、192.168.31.101.27019
shard2:192.168.31.102.27018、192.168.31.102.27019
shard3:192.168.31.103.27018、192.168.31.103.27019

安装包:mongodb-linux-x86_64-rhel70-4.0.28.tgz

配置环境如下图所示:
mongo.002

安装MongoDB和配置群集认证

注意:因为三台服务器的架构都一样所以操作都一样
1.三台服务器都要安装MongoDB,以及创建各个实例的数据存储、日志、pid文件和配置文件存放等目录以及日志文件
192.168.31.101、192.168.31.102、192.168.31.103:

yum -y install openssl-devel
tar zxf mongodb-linux-x86_64-rhel70-4.0.28.tgz
mv mongodb-linux-x86_64-rhel70-4.0.28 /mongodb
mkdir -p /mongodb/{config,shard1,shard2,logs,run,conf}
touch /mongodb/logs/{mongos.log,config.log,shard1.log,shard2.log}

config、shard1、shard2用于各实例的存放数据的data目录,mongos没有数据,所以不需要创建配置dbpath
2.配置群集认证
注意:随机在一台服务器上创建keyfile文件,然后拷贝到其他服务器上的相同路径上
192.168.31.101:

touch /mongodb/run/mongo-keyfile
openssl rand -base64 164 > /mongodb/run/mongo-keyfile
chmod 600 /mongodb/run/mongo-keyfile

会生成164位的加密字符串

cat /mongodb/run/mongo-keyfile
---------------------------------
rC3H7VCXtBfrrVFVo/cxgbpgGwAfx6Jw3+Zeb7DGQYloVTj7AxIMvTIOnZX746CK
LuG7AvTm1FdbVFgrfOfVP5lZkaYVcKwP3xr0W+/8vM6tTORitSWdSESm+fGyih/Q
YfHkrW78CH5peEGU7XKsI9xl8rSq8iOFZAjUlz9f7sW/aduw1OPDnbQ//zWSlgdI
tOdHzAPJY4Sa3eJ2Gs03olPSWss=

把该文件拷贝到192.168.31.102和192.168.31.103服务器配置的keyFile目录下即可

配置安装config和shard实例

1.配置config配置文件

注意:因为三台服务器的架构都一样所以操作都一样
192.168.31.101、192.168.31.102、192.168.31.103:

vim /mongodb/conf/config.conf
-----------------------------------
port=37017
bind_ip=0.0.0.0
dbpath=/mongodb/config
logpath=/mongodb/logs/config.log
logappend=true
pidfilepath=/mongodb/run/config.pid
fork=true
maxConns=5000
storageEngine=wiredTiger
replSet=config
configsvr=true
clusterAuthMode=keyFile
keyFile=/mongodb/run/mongo-keyfile

2.配置shard配置文件

注意:这里以192.168.31.101为例
配置shard1(192.168.31.101:27018)实例配置文件

vim /mongodb/conf/shard1.conf
--------------------------------
port=27018
bind_ip=0.0.0.0
dbpath=/mongodb/shard1
logpath=/mongodb/logs/shard1.log
logappend=true
pidfilepath=/mongodb/run/shard1.pid
fork=true
maxConns=5000
storageEngine=wiredTiger
replSet=shard1
shardsvr=true
clusterAuthMode=keyFile
keyFile=/mongodb/run/mongo-keyfile

配置shard2(192.168.31.101:27019)实例配置文件

vim /mongodb/conf/shard2.conf
--------------------------------
port=27019
bind_ip=0.0.0.0
dbpath=/mongodb/shard2
logpath=/mongodb/logs/shard2.log
logappend=true
pidfilepath=/mongodb/run/shard2.pid
fork=true
maxConns=5000
storageEngine=wiredTiger
replSet=shard1
shardsvr=true
clusterAuthMode=keyFile
keyFile=/mongodb/run/mongo-keyfile

因为这里是以192.168.31.101这台服务器的mongodb实例演示,所以192.168.31.102和192.168.31.103两台服务器配置shard1和shard2的配置文件需要修改replSet参数,分别改成shard2shard3,其他参数都可以不用变更

3.启动config、shard实例和配置副本集

启动所有config和shard实例
192.168.31.101、192.168.31.102、192.168.31.103:

/mongodb/bin/mongod -f /mongodb/conf/shard1.conf
/mongodb/bin/mongod -f /mongodb/conf/shard2.conf
/mongodb/bin/mongod -f /mongodb/conf/config.conf

查看启动状态

[root@mongo1 ~]# netstat -anptu |grep mongo
tcp        0      0 0.0.0.0:37017           0.0.0.0:*               LISTEN      1731/mongod
tcp        0      0 0.0.0.0:27018           0.0.0.0:*               LISTEN      1665/mongod
tcp        0      0 0.0.0.0:27019           0.0.0.0:*               LISTEN      1698/mongod
[root@mongo1 ~]# ps -aux |grep mongod |grep -v grep
root       1665  2.8  2.1 1115132 61120 ?       SLl  06:44   0:01 /mongodb/bin/mongod -f /mongodb/conf/shard1.conf
root       1698  2.6  1.9 1115128 54904 ?       SLl  06:44   0:01 /mongodb/bin/mongod -f /mongodb/conf/shard2.conf
root       1731  2.9  1.9 1115124 55608 ?       SLl  06:44   0:01 /mongodb/bin/mongod -f /mongodb/conf/config.conf

配置config实例副本集
注意:只用登录一台服务器的config实例即可
192.168.31.101:

/mongodb/bin/mongo --port 37017

创建config副本集

> cfg={"_id":"config","members":[{"_id":0,"host":"192.168.31.101:37017"},{"_id":1,"host":"192.168.31.102:37017"},{"_id":2,"host":"192.168.31.103:37017"}]}
{
	"_id" : "config",
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.31.101:37017"
		},
		{
			"_id" : 1,
			"host" : "192.168.31.102:37017"
		},
		{
			"_id" : 2,
			"host" : "192.168.31.103:37017"
		}
	]
}
> rs.initiate(cfg)
{ "ok" : 1 }
config:SECONDARY>
config:PRIMARY>

配置shard1和shard2实例副本集
192.168.31.101、192.168.31.102、192.168.31.103:
注意:这里以192.168.31.101为例,只用在登录shard1实例即可

/mongodb/bin/mongo --port 27018

创建副本集

> cfg={_id:'shard1',members:[{_id:0,host:'192.168.31.101:27018'},{_id:1,host:'192.168.31.101:27019'}]}
{
	"_id" : "shard1",
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.31.101:27018"
		},
		{
			"_id" : 1,
			"host" : "192.168.31.101:27019"
		}
	]
}
> rs.initiate(cfg)
{ "ok" : 1 }
shard1:SECONDARY>

其他192.168.31.102和192.168.31.102两台服务器登录shard1实例执行的时候把_id参数改成shard2shard3,并且把ip地址变成192.168.31.102和192.168.31.102执行即可
注意:配置副本集的时候不要使用localhost地址,也就是127.0.0.1之类的,因为mongos去读取config服务时,有三台shard,就会无法识别

配置安装mongos实例

1.配置mongos配置文件
注意:因为三台服务器的架构都一样所以操作都一样
192.168.31.101、192.168.31.102、192.168.31.103:

vim /mongodb/conf/mongos.conf
-----------------------------------
port=27017
bind_ip=0.0.0.0
configdb=config/192.168.31.101:37017,192.168.31.102:37017,192.168.31.103:37017
dbpath=/mongodb/mongos
logpath=/mongodb/logs/mongos.log
logappend=true
pidfilepath=/mongodb/run/mongos.pid
fork=true
clusterAuthMode=keyFile
keyFile=/mongodb/run/mongo-keyfile

启动mongos实例
192.168.31.101、192.168.31.102、192.168.31.103:

/mongodb/bin/mongos -f /mongodb/conf/mongos.conf

2.登录随机一台服务器mongos实例

/mongodb/bin/mongo --port 27017

添加三台服务器创建的shard1、shard2、shard3集群

mongos> sh.addShard("shard1/192.168.31.101:27018,192.168.31.101:27019")
{
	"shardAdded" : "shard1",
	"ok" : 1,
	"operationTime" : Timestamp(1658235168, 7),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658235168, 7),
		"signature" : {
			"hash" : BinData(0,"NMI7vvtLAE9N3JKEXpaQbO/e5i4="),
			"keyId" : NumberLong("7122052307964919840")
		}
	}
}
mongos> sh.addShard("shard2/192.168.31.102:27018,192.168.31.102:27019")
{
	"shardAdded" : "shard2",
	"ok" : 1,
	"operationTime" : Timestamp(1658235182, 4),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658235182, 6),
		"signature" : {
			"hash" : BinData(0,"1kMaxupyZrLFft745a5Hn4WDJrU="),
			"keyId" : NumberLong("7122052307964919840")
		}
	}
}
mongos> sh.addShard("shard3/192.168.31.103:27018,192.168.31.103:27019")
{
	"shardAdded" : "shard3",
	"ok" : 1,
	"operationTime" : Timestamp(1658235193, 6),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658235193, 6),
		"signature" : {
			"hash" : BinData(0,"9drMbrd8qbUxbtNe4laoaVUpqxQ="),
			"keyId" : NumberLong("7122052307964919840")
		}
	}
}

3.登录随机一台服务器mongos实例创建root权限的账号

/mongodb/bin/mongo --port 27017

进入到admin库查看是否有权限查看数据库,没有的话就创建root权限的账号

mongos> use admin
switched to db admin
mongos> show dbs
mongos>  db.createUser({user:"admin",pwd:"123456",roles:["root"]})
Successfully added user: { "user" : "admin", "roles" : [ "root" ] }
mongos> db.auth('admin', '123456')
1
mongos> show dbs
admin   0.000GB
config  0.003GB

查看群集状态

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("62d69cd7704c3430bf63cbf7")
  }
  shards:
        {  "_id" : "shard1",  "host" : "shard1/192.168.31.101:27018,192.168.31.101:27019",  "state" : 1 }
        {  "_id" : "shard2",  "host" : "shard2/192.168.31.102:27018,192.168.31.102:27019",  "state" : 1 }
        {  "_id" : "shard3",  "host" : "shard3/192.168.31.103:27018,192.168.31.103:27019",  "state" : 1 }
  active mongoses:
        "4.0.28" : 3
  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: 
                633 : Success
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                shard1	391
                                shard2	316
                                shard3	317
                        too many chunks to print, use verbose if you want to force print

其他服务器的mongos实例都可以通过创建的账号登录

/mongodb/bin/mongo -u admin -p '123456' --port 27017

测试结果

在数据库上启用分片攻能

mongos> use shard_test
switched to db shard_test
mongos> sh.enableSharding("shard_test")
{
	"ok" : 1,
	"operationTime" : Timestamp(1658239260, 3),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658239260, 3),
		"signature" : {
			"hash" : BinData(0,"i5S7DB8YaVICyicT+iBH10vKab8="),
			"keyId" : NumberLong("7122052307964919840")
		}
	}
}
mongos> db.name_test.find().count()
0
mongos> for(var i=1;i<=10000;i++)db.name_test.insert({age:i,name:"wangmazi",addr:"Beijing",country:"China"})
WriteResult({ "nInserted" : 1 })
mongos> db.name_test.find().count()
10000
mongos> db.name_test.find()
{ "_id" : ObjectId("62d6b970c03e14500167ac6b"), "age" : 1, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac6c"), "age" : 2, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac6d"), "age" : 3, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac6e"), "age" : 4, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac6f"), "age" : 5, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac70"), "age" : 6, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac71"), "age" : 7, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac72"), "age" : 8, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac73"), "age" : 9, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac74"), "age" : 10, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac75"), "age" : 11, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac76"), "age" : 12, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac77"), "age" : 13, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac78"), "age" : 14, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac79"), "age" : 15, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac7a"), "age" : 16, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac7b"), "age" : 17, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac7c"), "age" : 18, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac7d"), "age" : 19, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
{ "_id" : ObjectId("62d6b970c03e14500167ac7e"), "age" : 20, "name" : "wangmazi", "addr" : "Beijing", "country" : "China" }
Type "it" for more

再创建第二个库插入数据

mongos> use shard_test2
switched to db shard_test2
mongos> sh.shardCollection(shard_test2.name_test2)
2022-07-19T10:09:11.957-0400 E QUERY    [js] ReferenceError: shard_test2 is not defined :
@(shell):1:1
mongos> sh.enableSharding("shard_test2")
{
	"ok" : 1,
	"operationTime" : Timestamp(1658239768, 4),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1658239768, 4),
		"signature" : {
			"hash" : BinData(0,"7xcZjC4XSyjTikAo7XxLOxkUzQQ="),
			"keyId" : NumberLong("7122052307964919840")
		}
	}
}
mongos> for(var i=1;i<=10000;i++)db.name_test2.insert({age:i,name:"zhangsan",addr:"Chengdu",country:"China"})
WriteResult({ "nInserted" : 1 })

查看分片状态

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("62d69cd7704c3430bf63cbf7")
  }
  shards:
        {  "_id" : "shard1",  "host" : "shard1/192.168.31.101:27018,192.168.31.101:27019",  "state" : 1 }
        {  "_id" : "shard2",  "host" : "shard2/192.168.31.102:27018,192.168.31.102:27019",  "state" : 1 }
        {  "_id" : "shard3",  "host" : "shard3/192.168.31.103:27018,192.168.31.103:27019",  "state" : 1 }
  active mongoses:
        "4.0.28" : 3
  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: 
                682 : Success
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                shard1	342
                                shard2	341
                                shard3	341
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "kgc",  "primary" : "shard2",  "partitioned" : true,  "version" : {  "uuid" : UUID("2653055b-65ac-4543-8c00-f48e5c8042e5"),  "lastMod" : 1 } }
        {  "_id" : "shard_test",  "primary" : "shard2",  "partitioned" : true,  "version" : {  "uuid" : UUID("165bbb52-485e-4075-af8f-075c85c62689"),  "lastMod" : 1 } }
        {  "_id" : "shard_test2",  "primary" : "shard1",  "partitioned" : true,  "version" : {  "uuid" : UUID("38355519-6f60-4c3f-aeff-2fde2835ed67"),  "lastMod" : 1 } }

发现shard_test和shard_test2库数据存储在不同shard上,说明成功!!!