聊聊partition的方式

本文主要聊一下开源主流产品的partition方式。html

partition

通常来讲,数据库的繁忙体如今:不一样用户须要访问数据集中的不一样部分,这种状况下,咱们把数据的各个部分存放在不一样的服务器/节点中,每一个服务器/节点负责自身数据的读取与写入操做,以此实现横向扩展,这种技术成为分片,即sharding。node

理想状况下,不一样的节点服务于不一样的用户,每一个用户只须要与一个节点通讯,而且很快就能得到服务器的响应。固然理想状况比较罕见,为了得到近乎理想的效果,必须保证须要同时访问的那些数据都存放在同一个节点上,并且节点必须排布好这些数据块,使得访问速度最优。git

分片能够极大地提升读取性能,但对于要频繁写的应用,帮助不大。另外,分片对改善故障恢复能力并无帮助,可是它减小了故障范围,只有访问这个节点的那些用户才会受影响,其他用户能够正常访问。虽然数据缺失了一部分,可是仍是其他部分仍是能够正常运转。github

问题点

1.怎样分片/路由

怎样存放数据,才能保证用户基本上只须要从一个节点获取它。若是使用的是面向聚合的数据库而非面向元组的数据库,那么就很是容易解决了。之因此设计聚合这一结构,就是为了把那些常常须要同时访问的数据存放在一块儿。所以,能够把聚合做为分布数据的单元。redis

另外还要考虑的是:如何保持负载均衡。即如何把聚合数据均匀地分布在各个节点中,让它们须要处理的负载量相等。负载分布状况可能随着时间变化,所以须要一些领域特定的规则。好比有的须要按字典顺序,有的须要按逆域名序列等。
不少NoSQL都提供自动分片(auto-sharding)功能,可让数据库本身负责把数据分布到各个分片,而且将数据访问请求引导到适当的分片上。算法

2.怎样rebalance

在动态增减机器或partition的状况下,若是从新rebalance,使数据分布均匀或者避免热点访问mongodb

分片方式

这里主要分为两大类,一类是哈希分片(hash based partitionning),一类是范围分片(range based partitioning)数据库

1.哈希分片(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

2.范围分片(range based partitioning)

这个是根据key排序来分布的,好比字典按24个首字母来分,这个的好处是方便range,可是容易形成数据分布不均匀以及热点访问问题(好比个别节点的数据访问量/查询/计算量大,形成负载特别高)。

Bigtable,hbase、2.4版本以前的mongo都使用此方式。

索引分片策略(secondary indexes)

除了数据自己要分片外,索引也须要分片。比较著名的两个反向索引分片策略就是document-based partitioning以及term-based partitioning。而后再此两个基本的策略之上衍生出了hybrid的方案。

1.local index(document-based partitioning)

也称做document-based partitioning.在每一个partition本地维护一份关于本地数据的反向索引。这种方式的话,主要使用的是scatter/gather模式,即每次查询须要发送请求给全部的partition,而后每一个partition根据本地的索引检索返回,以后汇总得出结果。

  • 好处
    简单好维护
  • 缺点
    查询比较费劲,好比有n个partition,要查top k,则每一个partition都要查top k,总共须要n*k份文档被汇总。

mongo,cassandra,es,solr采用此方案

2.global index(term-based partitioning)

也称做term-based partitioning,这种方式的话,建立的索引不是基于partition的部分数据,而是基于全部数据来索引的。只不过这些全局索引使用range-based partitioning的方式再分布到各个节点上。

  • 好处
    读取效率高,由于索引是有序的,基于range parititioning,很是快速找到索引,并且这些索引是全局的,立马就能够定位到文档的位置。
  • 缺点
    写入成本比较高,每一个文档的写入都须要维护/更新全局的索引。另一个缺点就是range-partitioning自己的带来的缺点,容易形成数据分布不均匀,形成热点,影响吞吐量。

dynamodb,riak支持此方案

rebalance

当partition所在节点坏掉,或者新增机器的时候,这个时候就涉及到partition的rebalance。原来本应该请求这个node的,如今都须要转移请求另一个node的过程叫作rebalancing。

rebalancing的目标

  • 均分数据存储以及读写请求,避免热点
  • rebalancing期间不影响正常读写
  • 要尽可能快并且尽可能少的网络及IO负载来完成

rebalance策略

直接哈希(模数固定)

即key-machine的直接映射,这个的缺点就是:增减机器要从新hash,缺少灵活性。

两级映射(partition hashing,固定partition数目)

为了提高直接哈希的灵活性,引入了两级映射,即key-partition,partition-matchine/node这样两级,经过partition来解耦key跟machine/node的关联。对于新加入机器时,只须要将原来各个node的一些partition划分给新的机器,只要修改partition-machine映射便可,具备灵活性。

  • 好处
    相对于直接哈希来说,节点增减的时候,只须要调整partiton-matchine的映射关系,客户端无需从新路由。
  • 缺点
    固定partition的话,须要一个合理的数目,每一个partition大小须要合理肯定。至关于这些固定数目的partition要均分整个数据集。若是数据集不断增加的话,若是原来partition个数太少,则每一个partition大小则不断增长,形成节点恢复/rebalance相对耗时。若是原来partition个数太多,而数据集后续增加很少,则可能形成有些partition的数据量过少,没法达到均分效果。

Elasticsearch采用此方案,在建立索引的时候需指定shard/partition数目以及replication的数目
Couchbase引入了vBucket的概念在这里能够理解为虚拟的paritition。

动态partition

partition的数目是动态变化的,根据设定的partition大小的阈值,来进行动态的分裂或合并。

hbase采用的就是这种方式

一致性哈希(hash ring)

一致性哈希与前二者有些不一样,由于该算法把machine/node也一块儿进行了hash,而后与key的哈希值一块儿进行区间匹配,来肯定key落在哪一个machine/node上面。分布式缓存用到的比较多,好比redis就是用了一致性哈希。

具体以下:

  • 将环形空间总共分红2^32个区
  • 将key跟machine采用某种哈希算法转化为一个32位的二进制数,而后落到对应的区间范围内
  • 每个key的顺时针方向最近节点,就是key所归属的存储节点。
  • 好处
    节点增减的时候,整个环形空间的映射仍然会保持一致性哈希的顺时针规则,因此有一小部分key的归属会受到影响。当节点挂掉的时候,至关于缓存未命中,下次访问的时候从新缓存。
  • 缺点
    使用通常的hash函数的话,machine的映射分布很是不均匀,可能形成热点,对于这种状况,引入虚拟节点来解决。也就是借鉴了两级映射的模式,key-vnode,vnode-machine。将一个machine映射为多个vnode,而后分散到环形结构上,这样可使得vnode分布均匀,而后最后每一个machine的存储也相对均匀。

不过引入虚拟节点也会有问题,当新增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从新分布,避免热点

doc

相关文章
相关标签/搜索