当数据量很庞大时,需要分区,即将数据拆分成多个数据块,分布在多个机器上。分区可以让数据和查询负载均衡地分布在所有节点上,还可以提高扩展性。
分区数据也需要多个副本,因此分区通常和同步结合使用。一个机器既可以同时是分区1的主节点,和分区2的从节点。
1 分区方案
基于 key-range
一种分区方案是,为每个区间分配一段连续的键区间,且分配应尽可能地平均。以字典为例,以B开头的页数远大于以Z开头的,所以以单词首字母进行分区显然不是一个好的划分方法。分区的边界要适应数据本身的分布特征。
有时候仅使用数据中的一个项(例如时间戳)进行分区可能会不均衡(比如白天数据多,夜晚数据少),可以使用多个项。
基于 key hash
另一种方案是对 key 做哈希,并为每个分区分配一个哈希范围。考虑到节点加入和删除的数据迁移,通常使用一致性哈希,而不是简单的哈希后取模。
相较基于 key-range,基于 key hash 丧失了良好的区间查询性能。这部分内容可以和 第三章 存储与检索 中索引的结构照应。
复合主键
一个折中的解决方案是复合主键。复合主键由多个项组成,只有第一项用于哈希分区,其它项用作组合索引以便进行区间查询。
2 索引分区
数据可以通过分区,存储在多个节点上,但是索引应该如何分布?一个 item 的索引,应该分布在各个分区中,每个分区仅仅维护本分区数据的索引(本地索引)?还是每个一个分区负责存储和更新若干个 item 的全部索引(全局索引)?
本地索引写的开销很小,但是读会很费劲,因为需要遍历所有分区的索引,再聚合。
全局索引恰好相反,读开销很小,但是更新数据时,需要将不同分区的索引都进行更新。因此,全局索引的更新一般都是异步的。
3 分区均衡
分区负载不均衡,导致热点分区负载过大。需要一些措施均衡分区负载。
应用层均衡
例如某个键成了热点,可以在键结尾处加上不同的随机数作为后缀,成为新的键,分配到不同的分区。不过读取时需要遍历带全部后缀的键,会有额外开销。
固定数量分区
分区均衡需要考虑的主要一点就是减少数据迁移。如果所有键都哈希后取模节点数量映射到某一分区,那么一个节点加入后,所有键对应的分区号都会变化,数据迁移的成本过高。
一种简单的方案是固定数量分区。创建远超实际节点数的分区数,并为每个节点分配多个分区。当某个节点加入时,迁移其它节点的若干个分区到新节点上。这样只需要改变分区与节点的对应关系。
按节点比例分区
固定数量分区需要在初始时定好分区数量,有时候很难决定,过小可能不够用,过大会增重管理开销。另一种方案是按节点比例分区,即每个节点拥有固定数量的分区,当节点数量增加时,分区容量会变小。
4 路由方案
当客户端发送一个请求时,它应当发送到哪个节点上?这实际上是一个服务发现问题。键值到节点的路由逻辑可以放在节点处,客户端,或者单独抽离一个路由层。