golang数据库 MongoDB 分片(11)

Golang 2023/04/23 Golang ,MongoDB

一 分片的概念

当Mongo的数据量非常大之后,建议将数据进行拆分,放置在不同的Mongo服务中,这就是分片。分片机制是MongoDB能够实现分布式数据库服务的重要因素。

MongoDB可以实现自动分片,以前MYSQL时代也有手动分片,比如人工设置一个规则:一个用户表User,有很多user,应用程序在保存user数据时会先进行判断,如果是奇数存储到一台服务器,如果是偶数存储到另外一台服务器,取的时候也按照这样的规则取。人工分片大多依赖于应用程序的代码实现。

MongoDB实现了自动分片,内置了多种分片逻辑,用户无需设计分片方案,当Mongo启用分片后或者增加分片节点时,应用程序代码无需任何更改。

分片机制的重点是:数据的分流、块的拆分、块的迁移。

二 分片操作

工具mongos在查询数据时,会先询问configsvr,得到数据在哪个shard上,configsvr不存储真正的数据,存储的是数据的meta信息(元信息-某条数据在哪个片上)。
分片的要素:

  • 要有N>-2个mongod服务做片节点

  • 要有configsvr维护meta信息

  • 要设定好数据的分片规则,configsvr才能维护

  • 要启动mongos做路由

服务端操作:

step1: 启动两台在不同端口上的mongod
mongod --dbpath /data/mgd1   --logpath /logs/mgd1.log --fork --port 27017
mongod --dbpath /data/mgd2   --logpath /logs/mgd2.log --fork --port 27018

step2:启动一台configsvr
mongod --dbpath /data/svr   --logpath /logs/svr.log --fork --port 27020 --configsvr

step3:配置路由mongos(配置哪台configsvr为这个路由服务)
mongos --dbpath /data/mongos   --logpath /logs/mongos.log --fork --port 30000 --configdb 192.168.1.202:27020
sh.enableSharding("test")           // 指定要分片的数据库
sh.shardCollection('test.user', uid);   //指定分片的片键(按照uid切片存储)

客户端连接

# 此时客户端需要连接30000这个路由端口
mongo 127.0.0.1:30000/test

# 增加片
sh.addShard('192.168.1.202:27017')
sh.addShard('192.168.1.202:27018')
sh.status()

注意:Mongo并不是从单篇文档的级别绝对平均的散落在各个片上,而是N篇文档形成一个块chunk,优先放在某个片上,当这片上的chunk比另一个片的chubk区别比较大时(>=3),会把本片上的chunk移动到另一个片上。
每个chunk默认是64M(db.settings.find()),可以通过修改chunk大小来强制分片(db.settings.save({_id:'chunksize'},{$set:{value:4}}))(这里的db是config服务器)

三 手动分片

可以预定义一个规则,每N调数据形成1个块,预计分片M个chunk,M个chunk分配在不同的片上,以后的数据可以直接插入各自预先分配好的chunk,不再来回移动。

在路由服务器上操作:
sh.shardCollection('test.user',{uid:1})

# 预先在1K,2K...40K这样的界限切好chunk(空的),这些chunk均匀的分配到片上
for(var i = 1; i <= 40; i++>) {sh.splitAt('test.uid', {uid: i*1000})}

# 此时再添加数据,数据会添加到预先分配好的片上

四 分片原理

4.1 数据分流

MongoDB区别于手动分片的核心就是内置了几种数据分流存放的策略:哈希分片、区间分片、标签分片。

MongoDB在进行分片前都需要设置一个片键(shard key),这个片键可以是集合文档中的某个字段或者几个字段组成的一个片键,Mongo分片集群数据库服务是不允许插入没有片键的文档的,然后Mongo根据我们启用的策略来使用片键的值进行对数据进行分配,这样就完成了我们对数据的分流。

常见的三种分片策略:

  • 1 区间分片:这是早期Mongo分片策略,依据片键的值得区域来把数据划分成数据块,因为在Mongo中数据类型之间是有严格次序的,所以能够对片键的值进行一个排序。在排序的基础上,Mongo能获得片键的最大值和最小值,然后依据目前已有的片键和目前有多少台服务器参与分片来进行数据分配。比如设置x字段为片键,Mongo先对x片键进行统计,得到最小值和最大值,如果分片到三个服务器,Mongo可能把区间划分为:x到10,10到20,20到最大值,新文档插入时就会根据这个区间分配。

  • 2 哈希分片:仍然是基于区间分片,只支持单个字段作为片键,哈希分片将提供的片键散列成一个非常大的长整型作为最终的片键。选定片键后,会自动将片键进行散列计算后再进行区间划分。哈希分片的最大好处是保证数据在各个节点分布基本均匀。区间分片时,有可能片键时线性增长的,随着数字id或时间戳的自增,很可能一段时间内的数据都存储在了一个节点上,造成了负载不均。哈希分片以损失查询性能为代价,通过哈希值的随机性,使其数据平均分布在每个数据块中,因此查询也被分配到了不同的片中。

注意:Mongo哈希片键散列化计算会将浮点数截断为64位整数,对于2.3,2.4会得到相同的散列值,所以不要使用不能可靠转化为64位整数的浮点数。

  • 3 标签分片:通过对节点打tag识别标签,可以进行手动分片,比如一些日志集合我们需要存储在一些配置较低的服务器上,那么就可以通过该方式设置。

4.2 chunkSize和块的拆分

数据分流后在分片中是以chunk(块)的形式存在的,每个块的范围是由片键起始值和终止值标识。对一个数据集合进行分片后,无论集合里有什么数据,Mongo都只会创建一个块。

chunkSize是分片集群启动时的一个参数,用于设置块的大小。

4.3 平衡器和块的迁移

只有分片集群中的数据均匀分布,才能发挥集群最大性能,平衡器就是用来设计解决该问题的。

块只是逻辑上的分块,并不是物理的,也就是说块不标识磁盘的连续文档,块能出现在任意分片节点服务器中,当集群中拥有块最多的分片节点服务器与拥有块最少的节点服务器相差的块数过大时(一般是8个),平衡器就会触发数据迁移。


本文地址:https://stayed.cn/item/392

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。