本文主要聊一下开源主流产品的partition方式。html
通常来讲,数据库的繁忙体如今:不一样用户须要访问数据集中的不一样部分,这种状况下,咱们把数据的各个部分存放在不一样的服务器/节点中,每一个服务器/节点负责自身数据的读取与写入操做,以此实现横向扩展,这种技术成为分片,即sharding。node
理想状况下,不一样的节点服务于不一样的用户,每一个用户只须要与一个节点通讯,而且很快就能得到服务器的响应。固然理想状况比较罕见,为了得到近乎理想的效果,必须保证须要同时访问的那些数据都存放在同一个节点上,并且节点必须排布好这些数据块,使得访问速度最优。git
分片能够极大地提升读取性能,但对于要频繁写的应用,帮助不大。另外,分片对改善故障恢复能力并无帮助,可是它减小了故障范围,只有访问这个节点的那些用户才会受影响,其他用户能够正常访问。虽然数据缺失了一部分,可是仍是其他部分仍是能够正常运转。github
怎样存放数据,才能保证用户基本上只须要从一个节点获取它。若是使用的是面向聚合的数据库而非面向元组的数据库,那么就很是容易解决了。之因此设计聚合这一结构,就是为了把那些常常须要同时访问的数据存放在一块儿。所以,能够把聚合做为分布数据的单元。redis
另外还要考虑的是:如何保持负载均衡。即如何把聚合数据均匀地分布在各个节点中,让它们须要处理的负载量相等。负载分布状况可能随着时间变化,所以须要一些领域特定的规则。好比有的须要按字典顺序,有的须要按逆域名序列等。
不少NoSQL都提供自动分片(auto-sharding)功能,可让数据库本身负责把数据分布到各个分片,而且将数据访问请求引导到适当的分片上。算法
在动态增减机器或partition的状况下,若是从新rebalance,使数据分布均匀或者避免热点访问mongodb
这里主要分为两大类,一类是哈希分片(hash based partitionning
),一类是范围分片(range based partitioning
)数据库
hash based partitionning
)经过哈希函数来进行数据分片,主要有Round Robbin、虚拟桶、一致性哈希三种算法。segmentfault
A、Round Robbin
俗称哈希取模算法,H(key) = hash(key) mode K(其中对物理机进行从0到K-1编号,key为某个记录的主键,H(key)为存储该数据的物理机编号)。好处是简单,缺点是增减机器要从新hash,缺少灵活性。它其实是将物理机和数据分片两个功能点合二为一了,于是缺少灵活性。
B、虚拟桶
membase在待存储记录和物理机之间引入了虚拟桶,造成两级映射。其中key-partition映射采用哈希函数,partition-machine采用表格管理实现。新加入机器时,只须要将原来一些虚拟桶划分给新的机器,只要修改partition-machine映射便可,具备灵活性。
C、一致性哈希
一致性哈希是分布式哈希表的一种实现算法,将哈希数值空间按照大小组成一个首尾相接的环状序列,对于每台机器,能够根据IP和端口号通过哈希函数映射到哈希数值空间内。经过有向环顺序查找或路由表(Finger Table)来查找。对于一致性哈希可能形成的各个节点负载不均衡的状况,能够采用虚拟节点的方式来解决。一个物理机节点虚拟成若干虚拟节点,映射到环状结构的不一样位置。缓存
哈希分片的好处是可使数据均匀分布,可是可能形成数据无序不方便range
mongo2.4版本+支持hash partition
range based partitioning
)这个是根据key排序来分布的,好比字典按24个首字母来分,这个的好处是方便range,可是容易形成数据分布不均匀以及热点访问问题(好比个别节点的数据访问量/查询/计算量大,形成负载特别高
)。
Bigtable,hbase、2.4版本以前的mongo都使用此方式。
secondary indexes
)除了数据自己要分片外,索引也须要分片。比较著名的两个反向索引分片策略就是document-based partitioning以及term-based partitioning。而后再此两个基本的策略之上衍生出了hybrid的方案。
document-based partitioning
)也称做document-based partitioning.在每一个partition本地维护一份关于本地数据的反向索引。这种方式的话,主要使用的是scatter/gather模式,即每次查询须要发送请求给全部的partition,而后每一个partition根据本地的索引检索返回,以后汇总得出结果。
mongo,cassandra,es,solr采用此方案
term-based partitioning
)也称做term-based partitioning,这种方式的话,建立的索引不是基于partition的部分数据,而是基于全部数据来索引的。只不过这些全局索引使用range-based partitioning的方式再分布到各个节点上。
dynamodb,riak支持此方案
当partition所在节点坏掉,或者新增机器的时候,这个时候就涉及到partition的rebalance。原来本应该请求这个node的,如今都须要转移请求另一个node的过程叫作rebalancing。
模数固定
)即key-machine的直接映射,这个的缺点就是:增减机器要从新hash,缺少灵活性。
partition hashing,固定partition数目
)为了提高直接哈希的灵活性,引入了两级映射,即key-partition,partition-matchine/node这样两级,经过partition来解耦key跟machine/node的关联。对于新加入机器时,只须要将原来各个node的一些partition划分给新的机器,只要修改partition-machine映射便可,具备灵活性。
Elasticsearch采用此方案,在建立索引的时候需指定shard/partition数目以及replication的数目
Couchbase引入了vBucket的概念在这里能够理解为虚拟的paritition。
partition的数目是动态变化的,根据设定的partition大小的阈值,来进行动态的分裂或合并。
hbase采用的就是这种方式
hash ring
)一致性哈希与前二者有些不一样,由于该算法把machine/node也一块儿进行了hash,而后与key的哈希值一块儿进行区间匹配,来肯定key落在哪一个machine/node上面。分布式缓存用到的比较多,好比redis就是用了一致性哈希。
具体以下:
不过引入虚拟节点也会有问题,当新增machine的时候,也就至关于新增多个vnode分散到环上,可是这样子就会形成更多的范围的key须要rebalance。
一、提高单调性(经过环形算法减小增减节点时cache的迁移成本) 二、提高平衡性(经过虚拟节点,尽量减小节点增减带来的cache分布不均匀问题)
产品 | partition方式 | 索引分片策略 |
---|---|---|
redis | 一致性哈希 | - |
elasticsearch | 固定partition两级映射 | local index |
mongo | 2.4版本以前是范围分片,2.4+支持hash分片 | local index |
kafka | 固定partition | - |
kafka的key到partition的映射高版本支持自定义策略,若是cluster增减node,对以前建立的topic不生效,须要调用reassign-partitions从新分布,避免热点