MongoDB中的Primary Shard详解
作者:吃饭端住碗
什么是Primary Shard
在MongoDB的Sharding架构中,每个database中都可以存储两种类型的集合,一种是未分片的集合,一种是通过分片键,被打散的集合。被分片键打散的集合数据可以均匀的分布在各个分片上;而对于未分片的集合,则只会存储在所在的database的Primary Shard中,每个database有且只有一个Primary Shard。简单来说就是,Primary Shard存储了当前数据库未分片的集合。示意图如下:
其中Collection I为分片集合,数据被打散到不同的分片上。Collection 2作为未分片集合所有的所有都只存储在Primary Shard中,这里它的Primary Shard为Shard A。
Primary Shard的选择及问题
当我们通过mongos创建一个database时,mongos会根据当前每个分片中存储的数据量来决定哪个分片为当前数据库的Primary Shard,存储数据量最少的作为当前数据库的主分片。数据量判断依据为listDatabases命令中的totalSize的值。
比如我们新建一个test1库,并在里面创建一个未分片的集合,mongos为它挑选的Primary Shard为shard2:
[direct: mongos] test> use test1; switched to db test1 [direct: mongos] test1> db.foo.insertOne({"name":"aaa"}); { acknowledged: true, insertedId: ObjectId("66c6f060b47ae218b4ef12aa") } [direct: mongos] test1> sh.status() ... { database: { _id: 'test1', primary: 'shard2', partitioned: false, version: { uuid: new UUID("a419673b-944b-4cdd-8d11-f3074bbf43fb"), timestamp: Timestamp({ t: 1724313695, i: 1 }), lastMod: 1 } }, collections: {} }
Primary Shard自动选择存在的问题
问题一
假设有如下需求:有两个专门存储配置集合的database,由于是配置集合,所有数据量比较小,不需要再将其数据打散,但是为了方面管理,需要将这两个配置库存放在同一个分片中。换句话说就是这两个配置库的Primary Shard需要为同一个。
我们知道,mongos在选择Primary Shard的时候是根据当前各个分片现有的数据量来决定的,但是如果当前各个分片的数据量都比较均衡,当我们的业务数据在持续变动的过程中,mongos在选择Primary Shard的时候就会表现出随机性--先后创建的database的Primary Shard极有可能会是不同的分片。
问题二
假设目前需要有一个日志库,然后每个月都会以月份为后缀进行切库,就是说6月份的话我会创建一个叫DB_202406的库,7月份的话会创建一个叫做DB_202407的库,集合的月增量为1个T。由于增量比较大,后面肯定是需要不断加机器扩容的,当单台服务器的磁盘IO能力不是瓶颈的情况下,为了后期加机器扩容时不需要进行历史数据的均衡,所以日志集合的选择了未分片。那么当我进行月底切库,即创建新库的时候,mongos就会判断各个分片上的现有数据量,然后找一个数据量相对较小的分片作为Primary Shard,此时,如果各个分片的服务器磁盘并不是相同大小的,比如说A分片的磁盘大小为10T,B分片磁盘的大小为5T,但是A分片存储的数据为4.8T,B分片存储的数据为4.5T,这时候由于B分片上存储的数据少,mongos会将B分片选为新库的Primary Shard,但是实际情况是B分片所在的主机空闲空间已经完全不足以支持本月的月增数据量了,后面就只能临时扩容本机或删数据或将数据在线同步迁移到有足够空间的新机器上,并进行应用切换。
如何解决
针对上面存在的两个问题,根本原因还是由于在新建库后,mongs自动为当前库选择的Primary Shard可能会出现不合理性,所以我们在进行建库的时候,最好的办法是直接指定新库的Primary Shard,这样就可以规避掉上面两个问题。而且针对第二个问题,还需要做的是当业务上线前需要做好的架构规划和容量规划等。
建库后指定当前库的Primary Shard:
[direct: mongos] test> use DB1 switched to db DB1 [direct: mongos] DB1> sh.enableSharding("DB1","shard1") { ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1724317769, i: 3 }), signature: { hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0), keyId: Long("0") } }, operationTime: Timestamp({ t: 1724317769, i: 1 }) } [direct: mongos] DB1> sh.status() ... { database: { _id: 'DB1', primary: 'shard1', partitioned: false, version: { uuid: new UUID("ec0e50b8-3029-4333-887b-9ca0b54c4e20"), timestamp: Timestamp({ t: 1724317768, i: 1 }), lastMod: 1 } }, collections: {} }
只能在use新库之后,立即指定新库的Primary Shard,不能等创建过集合并写入数据之后再指定,因为那时mongos已经为新库选好了Primary Shard,就不支持再次修改了
[direct: mongos] DB1> sh.enableSharding("DB1","shard3") MongoServerError: Database DB1 could not be created :: caused by :: database already created on a primary which is different from shard1
到此这篇关于MongoDB中的Primary Shard的文章就介绍到这了,更多相关MongoDB Primary Shard内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!