文章目录
- 一、概念理解
- 1. 什么是分片
- 2. 为什么要使用分片集群
- 3. MongoDB 分片集群组成
- 4. 分片集群角色
- 4.1 路由节点
- 4.2 配置节点
- 4.3 数据节点
- 5. 分片键与分片规则
- 5.1 范围分片
- 5.2 hash分片
- 6. 选择片键
- 7. 数据段的分裂
- 8. 集群的平衡
- 9. MongoDB分片集群特点
- 二、搭建集群环境
- 1. 配置第一个复制集
- 1.1 创建数据目录
- 1.2 创建日志文件
- 1.3. 启动第一个mongod分片实例(共三个实例)
- 1.4 第一个分片的mongod实例都启动好了后,将其加入到复制集中
- 1.5 查看状态
- 2. 配置Config 复制集:一共三个实例
- 2.1 创建数据目录
- 2.2 创建日志文件
- 2.3 启动配置复制集
- 2.4 配置复制集进行初始化
- 3. 配置mongs路由节点
- 3.1 启动mongos实例,需要指定配置服务器的地址列表
- 3.2 连接到mongos中添加分片
- 3.3 查看分片状态
- 4、创建第二个复制集
- 4.1 启动服务
- 4.2 初始化复制集
- 4.3 加入到集群分片
- 4.4 查看分配状态
- 5. 创建分片表
- 5.1 首先需要启用数据库分片
- 5.2 启用集合分片
- 三、优缺点分析
- 1、缺点
- 2、优点
一、概念理解
1. 什么是分片
将数据水平拆分到不同的服务器上。
2. 为什么要使用分片集群
1、数据量突破单机瓶颈,数据量大,恢复很慢,不利于数据管理。
2、并发量突破单机性能瓶颈。
3. MongoDB 分片集群组成
4. 分片集群角色
4.1 路由节点
mongos提供集群单一入口,转发应用端请求,选择合适的数据节点进行读写,合并多个数据节点的返回。
无状态,建议 mongos节点集群部署以提供高可用性。
客户请求应发给mongos,而不是分片服务器,当查询包含分片片键时,mongos将查询发送到指定分片,否则,mongos将查询发送到所有分片,并汇总所有查询结果。
4.2 配置节点
就是普通的mongod进程, 建议以复制集部署,提供高可用。
提供集群元数据存储分片数据分布的数据。主节点故障时,配置服务器进入只读模式,
只读模式下,数据段分裂和集群平衡都不可执行。整个复制集故障时,分片集群不可用。
4.3 数据节点
以复制集为单位,横向扩展最大1024分片,分片之间数据不重复,所有数据在一起才可以完整工作。
5. 分片键与分片规则
可以是单个字段, 也可以是复合字段。
5.1 范围分片
比如key的值从min - max。
可以把数据进行范围分片。
缺点:冷热数据不均匀。可能大部分的压力来自新的用户和新的记录。
5.2 hash分片
通过 hash(key ) 进行数据分段。
片键值用来将集合中的文档划分为数据段,片键必须对应一个索引或索引前缀(单键、复合键),可以使用片键的值或者片键值的哈希值进行分片。
缺点:不支持范围查询和排序。
6. 选择片键
1、片键值的范围更广(可以使用复合片键扩大范围)
2、片键值的分布更平衡(可使用复合片键平衡分布)
3、片键值不要单向增大、减小(可使用哈希片键)
7. 数据段的分裂
当数据段尺寸过大,或者包含过多文档时,触发数据段分裂。
只有新增、更新文档时才可能自动触发数据段分裂,数据段分裂通过更新元数据来实现。
8. 集群的平衡
后台运行的平衡器负责监视和调整集群的平衡,当最大和最小分片之间的数据段数量相差过大时触发。
集群中添加或移除分片时也会触发。
9. MongoDB分片集群特点
1、应用全透明
2、数据自动均衡
3、动态扩容,无需下线
二、搭建集群环境
本次搭建一个2个分片的集群。
1. 配置第一个复制集
1.1 创建数据目录
准备给两个复制集使用,每个复制集有三个实例 ,共 6 个数据节点。
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second1
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second2
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second1
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second2
1.2 创建日志文件
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1/mongod.log
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second1/mongod.log
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second2/mongod.log
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2/mongod.log
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second1/mongod.log
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second2/mongod.log
// 或者可以一次创建多个
touch a b c...
1.3. 启动第一个mongod分片实例(共三个实例)
注意:这里我们没有添加配置文件,所以有一些设置需要在启动的时候使用参数的形式加上。
mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1/mongod.log --port 27010 --fork --shardsvr
mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second1 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second1/mongod.log --port 27011 --fork --shardsvr
mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second2 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard1second2/mongod.log --port 27012 --fork --shardsvr
PS:–replSet shard1这里配置的是复制集名称,同一个复制集的名称需要保持一致。
1.4 第一个分片的mongod实例都启动好了后,将其加入到复制集中
等待上面三个实例都启动好之后,我们登入第一个的客户端,执行以下命令:
mongo --host 192.168.131.171 --port 27010
注意这里的IP地址和端口号要写正确。
rs.initiate(
{_id:"shard1",
"members":[
{"_id":0,"host":"192.168.131.171:27010"},
{"_id":1,"host":"192.168.131.171:27011"},
{"_id":2,"host":"192.168.131.171:27012"}
]
});
等待集群选举结束,可以看到27010已经成为了主节点。
1.5 查看状态
shard1:PRIMARY> rs.status()
{
"set" : "shard1",
"date" : ISODate("2021-09-12T03:00:23.693Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 3,
"writableVotingMembersCount" : 3,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2021-09-12T03:00:23.589Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"readConcernMajorityWallTime" : ISODate("2021-09-12T03:00:23.589Z"),
"appliedOpTime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2021-09-12T03:00:23.589Z"),
"lastDurableWallTime" : ISODate("2021-09-12T03:00:23.589Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1631415613, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2021-09-12T02:58:13.531Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1631415482, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2021-09-12T02:58:13.557Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2021-09-12T02:58:15.091Z")
},
"members" : [
{
"_id" : 0,
"name" : "192.168.131.171:27010",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 505,
"optime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2021-09-12T03:00:23Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1631415493, 1),
"electionDate" : ISODate("2021-09-12T02:58:13Z"),
"configVersion" : 1,
"configTerm" : -1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.131.171:27011",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 141,
"optime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2021-09-12T03:00:23Z"),
"optimeDurableDate" : ISODate("2021-09-12T03:00:23Z"),
"lastHeartbeat" : ISODate("2021-09-12T03:00:23.684Z"),
"lastHeartbeatRecv" : ISODate("2021-09-12T03:00:23.176Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "192.168.131.171:27010",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1,
"configTerm" : -1
},
{
"_id" : 2,
"name" : "192.168.131.171:27012",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 141,
"optime" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1631415623, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2021-09-12T03:00:23Z"),
"optimeDurableDate" : ISODate("2021-09-12T03:00:23Z"),
"lastHeartbeat" : ISODate("2021-09-12T03:00:23.684Z"),
"lastHeartbeatRecv" : ISODate("2021-09-12T03:00:23.206Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "192.168.131.171:27010",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1,
"configTerm" : -1
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1631415623, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1631415623, 1)
}
members中可看到实例的信息。
2. 配置Config 复制集:一共三个实例
2.1 创建数据目录
cd /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data
mkdir -p config configsecond1 configsecond2
2.2 创建日志文件
cd /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data
// touch:创建空文件
touch ./config/mongod.log ./configsecond1/mongod.log ./configsecond2/mongod.log
2.3 启动配置复制集
注意:这里我们没有添加配置文件,所以有一些设置需要在启动的时候使用参数的形式加上。
mongod --bind_ip 0.0.0.0 --replSet config --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/config --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/config/mongod.log --port 37010 --fork --configsvr
mongod --bind_ip 0.0.0.0 --replSet config --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/configsecond1 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/configsecond1/mongod.log --port 37011 --fork --configsvr
mongod --bind_ip 0.0.0.0 --replSet config --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/configsecond2 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/configsecond2/mongod.log --port 37012 --fork --configsvr
2.4 配置复制集进行初始化
注意这里配置的IP地址和端口号要和复制集的一致!
等到复制集启动成功后,我们登入37010的客户端,准备执行命令配置复制集进行初始化。
mongo --host 192.168.131.171 --port 37010
rs.initiate(
{_id:"config",
"members":[
{"_id":0,"host":"192.168.131.171:37010"},
{"_id":1,"host":"192.168.131.171:37011"},
{"_id":2,"host":"192.168.131.171:37012"}
]
});
执行后会开始进行选举,默认会将执行该命令的设置为主节点。
3. 配置mongs路由节点
3.1 启动mongos实例,需要指定配置服务器的地址列表
先创建一个mongos实例的log文件:
mkdir /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/mongos
touch /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/mongos/mongos.log
然后准备命令,来启动实例:
其中configdb为配置服务器的地址列表,注意这里是复制集的服务地址。
mongos --bind_ip 0.0.0.0 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/mongos/mongos.log --port 4000 --fork --configdb config/192.168.131.171:37010,192.168.131.171:37011,192.168.131.171:37012
3.2 连接到mongos中添加分片
等待mongos启动成功后,我们直接通过mongo shell客户端进行连接:
mongo --host 192.168.131.171 --port 4000
连接成功后来执行添加分片的命令:
注意:这里的服务地址是mongod分片实例的地址!
sh.addShard("shard1/192.168.131.171:27010,192.168.131.171:27011,192.168.131.171:27012");
3.3 查看分片状态
分片添加成功后我们就可以来查看分配状态了:
mongos> sh.status();
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("613d70e0a464c8d502073514")
}
shards:
{ "_id" : "shard1", "host" : "shard1/192.168.131.171:27010,192.168.131.171:27011,192.168.131.171:27012", "state" : 1 }
active mongoses:
"4.4.2" : 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 }
mongos可以用同样的方式,创建多个!
4、创建第二个复制集
4.1 启动服务
数据目录和日志文件我们之前创建第一个复制集的时候已经创建好了,现在直接启动即可:
mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2/mongod.log --port 27013 --fork --shardsvr
mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second1 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second1/mongod.log --port 27014 --fork --shardsvr
mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second2 --logpath /usr/local/mongodb/mongodb-linux-x86_64-rhel70-4.4.2/data/shard2second2/mongod.log --port 27015 --fork --shardsvr
4.2 初始化复制集
都启动成功之后,我们登录到27013,27014,27015中任意一个客户端上,来初始化第二个复制集:
mongo --host 192.168.131.171 --port 27013
rs.initiate(
{_id:"shard2",
"members":[
{"_id":0,"host":"192.168.131.171:27013"},
{"_id":1,"host":"192.168.131.171:27014"},
{"_id":2,"host":"192.168.131.171:27015"}
]
});
可以使用rs.status()查看复制集状态:
shard2:PRIMARY> rs.status()
{
"set" : "shard2",
"date" : ISODate("2021-09-12T06:24:09.657Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 3,
"writableVotingMembersCount" : 3,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2021-09-12T06:24:04.278Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"readConcernMajorityWallTime" : ISODate("2021-09-12T06:24:04.278Z"),
"appliedOpTime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2021-09-12T06:24:04.278Z"),
"lastDurableWallTime" : ISODate("2021-09-12T06:24:04.278Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1631427844, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2021-09-12T06:22:04.171Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1631427713, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2021-09-12T06:22:04.262Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2021-09-12T06:22:06.280Z")
},
"members" : [
{
"_id" : 0,
"name" : "192.168.131.171:27013",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 471,
"optime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2021-09-12T06:24:04Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1631427724, 1),
"electionDate" : ISODate("2021-09-12T06:22:04Z"),
"configVersion" : 1,
"configTerm" : -1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.131.171:27014",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 136,
"optime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2021-09-12T06:24:04Z"),
"optimeDurableDate" : ISODate("2021-09-12T06:24:04Z"),
"lastHeartbeat" : ISODate("2021-09-12T06:24:08.332Z"),
"lastHeartbeatRecv" : ISODate("2021-09-12T06:24:07.797Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "192.168.131.171:27013",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1,
"configTerm" : -1
},
{
"_id" : 2,
"name" : "192.168.131.171:27015",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 136,
"optime" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1631427844, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2021-09-12T06:24:04Z"),
"optimeDurableDate" : ISODate("2021-09-12T06:24:04Z"),
"lastHeartbeat" : ISODate("2021-09-12T06:24:08.332Z"),
"lastHeartbeatRecv" : ISODate("2021-09-12T06:24:07.751Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "192.168.131.171:27013",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1,
"configTerm" : -1
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1631427844, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1631427844, 1)
}
4.3 加入到集群分片
我们登录到mongos客户端中,然后将第二个复制集也加入到集群中:
mongo --host 192.168.131.171 --port 4000
sh.addShard("shard2/192.168.131.171:27013,192.168.131.171:27014,192.168.131.171:27015");
4.4 查看分配状态
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("613d70e0a464c8d502073514")
}
shards:
{ "_id" : "shard1", "host" : "shard1/192.168.131.171:27010,192.168.131.171:27011,192.168.131.171:27012", "state" : 1 }
{ "_id" : "shard2", "host" : "shard2/192.168.131.171:27013,192.168.131.171:27014,192.168.131.171:27015", "state" : 1 }
active mongoses:
"4.4.2" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: yes
Collections with active migrations:
config.system.sessions started at Sun Sep 12 2021 09:30:39 GMT+0300 (EEST)
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
40 : Success
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 984
shard2 40
too many chunks to print, use verbose if you want to force print
{ "_id" : "order", "primary" : "shard1", "partitioned" : true, "version" : { "uuid" : UUID("f8ffa000-6a09-4fef-95e8-6ac556f7bf73"), "lastMod" : 1 } }
可以看到,此时已经有两个分片了,分别是shard1和shard2。
shard1和shard2是两个复制集。
5. 创建分片表
注意:如果已经有数据了, 不能再再分配分片键!
MongoDB的分片是基于集合的,就算有分片集群不等于数据会自动分片,需要显示分片表。
我们收下来查看一下mongos的状态看看是否正常:
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("613d70e0a464c8d502073514")
}
shards:
{ "_id" : "shard1", "host" : "shard1/192.168.131.171:27010,192.168.131.171:27011,192.168.131.171:27012", "state" : 1 }
{ "_id" : "shard2", "host" : "shard2/192.168.131.171:27013,192.168.131.171:27014,192.168.131.171:27015", "state" : 1 }
active mongoses:
"4.4.2" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: yes
Collections with active migrations:
config.system.sessions started at Sun Sep 12 2021 09:39:26 GMT+0300 (EEST)
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
178 : Success
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 846
shard2 178
too many chunks to print, use verbose if you want to force print
{ "_id" : "order", "primary" : "shard1", "partitioned" : true, "version" : { "uuid" : UUID("f8ffa000-6a09-4fef-95e8-6ac556f7bf73"), "lastMod" : 1 } }
此时有两个shard,表示我们之前的配置正常。
接下来我们准备来配置分片规则。
5.1 首先需要启用数据库分片
需要在启动的mongos客户端shell中执行命令。
我们需要首先准备好一个数据库,我们就创建一个order数据库吧。
use order
然后我们来对order这个数据库启用分片:
sh.enableSharding("库名");
// 如:
sh.enableSharding("order");
数据库分片启动成功后,我们还需要启动集合分片。
5.2 启用集合分片
注意:添加分片之前,集合中一定不能有数据!否则可能会报如下的错误:
please create an index that starts with the shard key before sharding。
大概意思是在启用分片前需要在分片key上建立索引。我们并没有立刻在分片key上建立索引,因为之前在启用表分片,在分片key上会自动建立索引,为什么要我手动建立呢?mongodb源码中,在src/mongo/s/commands_admin.cpp文件中544行找到这个错误信息:
原来判断分支是查找是否有可用的索引存在,当无可用的索引,并且表不为空时,就会出现这个错误信息。
好了找到根源了,现在解决问题:需要在分片key上个建立索引!
确保集合中没有数据或者集合不存的时候,我们来直接启用集合分片!
我们就对accounts这个集合启用分片吧。
sh.shardCollection("库名.集合名",{_id: "hashed"});
// 例如:
sh.shardCollection("order.accounts",{_id: "hashed"});
可以看到此时order数据库下的accounts集合分片已经启用成功!接下来我们向accounts集合添加数据:
–我们在order数据库下创建一个accounts集合并添加一些数据。
db.accounts.insertOne({"name":"xioayan", "age":"24"});
添加完后我们在mongos上查看:
接下来我们看看这条数据到底存在哪一个复制集上。
添加完这条数据后,按照分片规则,应该会被分配到某一个复制集中。我们来分别验证一下。
首先我们登录第一个复制集27010,27011,27012中任意一个的客户端上查看记录:
mongo --host 192.168.131.171 --port 27010
经过查看,我们没有在第一个复制集上看到刚才添加的数据。那我们再来查看第二个复制集。
我们登录第二个复制集27013,27014,27015中任意一个的客户端上查看记录:
mongo --host 192.168.131.171 --port 27013
可以看到,这条记录根据id的hash规则,被分配到了第二个复制集上!
至此,我们的MongoDB的分片集群就搭建完成了。当然,有兴趣的也可以测试一下故障转移、动态扩容(再增加一个复制集即可)等。我相信功能是正常的! ^^
三、优缺点分析
1、缺点
1、项目复杂度上升
2、机器总数要求更多
3、查询数据的时候可能要从多个复制集中分别获取,然后在内容中完成合并,性能大打折扣
所以,如果数据量不是很大,还是建议使用复制集架构!
2、优点
1、高可用
2、并发量突破单机性能瓶颈