本文主要聊一下開源主流產品的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從新分佈,避免熱點