一直想找时间把搭建公司 MongoDB 集群时分片的选择总结分享一波,总是忙加上再持续学习其他知识,这篇分享一直断断续续的写,今天终于把整篇完成了,和大家一起分享下我关于 MongoDB 分片选择的一些经验,供大家参考。
分享可能有误,欢迎大家指正。
使用环境
选择 Shard Key 一定要根据应用的使用环境来进行判断,否则将事倍功半!
由于使用 MongoDB 数据库的应用是一个基于物联网的应用,因此数据库将存储大量现场 IOT 硬件发回的数据。在应用中有以下一个非常值得关注而且非常重要的的点:
- 查看数据时,会选择某个用户/硬件一段连续时间段内的所有数据去查询,不会选择具体某个时间点去查询数据
以上信息在整个 Shard Key 选择中是非常重要的参考依据。
Shard Key 特点
关于 Shard Key 的介绍,可以查看官方文档。
Shard Key 可以说是 MongoDB 分片的灵魂了,如果分片键没有选好,整个分片集群就没有起到集群本身的作用,所以,这个分片集群基本上就算废了。
shard key 在分片中的主要特点:
数据索引
作为 shard key 首先作用就是作为数据索引,因为建立 shard key 之前的必要条件就是必须是数据索引
不可更改
shard key 是固定的,一旦确定后,将不可进行更改
随机性
shard key 一定要具有一定的随机性。如果没有选择好 shard key,造成顺序性,则数据会落在某个特定的节点中,造成某节点数据过多,而其他节点却没有数据的情况。
一个好的 shard key 应该具备的特点:
key 分布足够离散 (sufficient cardinality)
足够分散才能带来性能上的增加
写请求均匀分布 (evenly distributed write)
数据应该均匀分布在所有的数据节点上
尽量避免 scatter-gather 查询 (targeted read)
避免大范围的扫描查询
现有 Shard Key 类型
MongoDB 支持2种分片方式:
范围分片
通常能很好的支持基于 shard key 的范围查询
Hash 分片
通常能将写入均衡分布到各个 shard,不过对范围查询支持不好
混合片键
是的,您没有看错,的确还有这样一种片键。虽然在官方文档中很容易查到前两种片键类型,但是官方文档也同样提到过混合片键,这种片键综合了前两种片键的优点,某些场景下非常合适。
利弊分析
根据产品的使用场景,需要进行特定的片键选择分析。
以公司 IOT 项目为例,在对采集数据进行 sharding 选择片键时,我们很容易想到:
以
用户编号
范围分片 为片键这个方案我在最开始的时候也是第一个想到的。但是经过思考后,否决掉了。该方案虽然可以解决在查询某个用户数据时不用扫描所有数据节点,但是用因为户数达不到极大的量级,所以这样会使采集的数据在落盘的时候集中在某一个节点的某个数据块中。
所以,该方案不合适。
以
用户编号
哈希分片 为片键这个方案虽然可以解决范围分片带来的集中问题,但是,仍然不能满足应用的需求,因为应用在使用过程中,需要查询某个用户某一个时间段范围内的所有采集到的数据,如果使用这种方案,那么进行数据查询的时候需要对所有节点进行查询扫描。
所以,该方案不合适。
以
created_at
创建时间 范围分片 为片键虽然该方案可以解决连续读取一个时间段内的数据问题,但是新的写入都是连续的时间戳,同样都会请求到同一个 shard,造成写分布不均。
所以,该方案不合适。
以
created_at
创建时间 哈希分片 为片键该方案的利弊刚好和上一个方案相反。
所以,该方案不合适。
以
用户编号
哈希分片 +created_at
范围分片 为组合片键这个方案其实不用分析就知道为什么不合适了,理由同第2个方案。因为当选择 用户编号哈希方案为首的组合片键时,用户编号哈希分片已经可以分片出数据了,MongoDB就不用再考虑后者了,所以造成的影响和第2个方案类似。
所以,该方案不合适。
以
用户编号
+created_at
范围分片 为组合片键同一个 用户编号 的数据能根据时间戳进一步分散到多个数据块中,同时根据 created_at 查询时间范围的数据,能直接利用(
用户编号
+created_at
)复合索引来完成。所以,该方案合适。
以上是我做 MongoDB 集群时片键的选择分析,供大家参考。
PS:您可能会想,为什么不考虑以 created_at
在前的组合片键呢?
在看我的想法之前,您可以自己也思考思考。
其实很简单,因为应用不会在不确定 用户 的情况下去搜索某一个时间段内的数据。
总结
选择 Shard Key 一定要根据应用的使用环境来进行判断,否则将事倍功半!
这个非常重要!