13.4 橫向擴展帶來性能提升
很多NoSQL系統都是基於鍵值模型的,因此其查詢條件也基本上是基於鍵值的查詢,基本不會有對整個數據進行查詢的時候。由於基本上所有的查詢操作都是基本鍵值形式的,因此分片通常也基於數據的鍵來做:鍵的一些屬性會決定這個鍵值對存儲在哪台機器上。下面我們將會對hash分片和范圍分片兩種分片方式進行描述。
3.4.2 通過協調器進行數據分片
由於CouchDB專注於單機性能,沒有提供類似的橫向擴展方案,於是出現了兩個項目:Lounge 和 BigCouch,他們通過提供一個proxy層來對CouchDB中的數據進行分片。在這種架構中,proxy作為CouchDB集群的前端機器,接受和分配請求到后端的多台CouchDB上。后端的CouchDB 之間並沒有交互。協調器會將按操作的key值將請求分配到下層的具體某台機器。 Twitter 自己實現了一個叫Gizzard的協調器,可以實現數據分片和備份功能。Gizzard不關心數據類型,它使用樹結構來存儲數據范圍標識,你可以用它來對SQL或者NoSQL系統進行封裝。
13.4.3 一致性hash環算法
好的hash算法可以使數據保持比較均勻的分布。這使得我們可以按這種分布將數據保存布多台機器上。一致性hash是一種被廣泛應用的技術,其最早在一個叫distributed hash tables (DHTs)的系統中進行使用。那些類Dynamo的應用,比如Cassandra、Voldemort和Riak,基本上都使用了一致性hash算法。
備份數據
一致性hash下的數據備份通常采用下面的方法:將數據冗余的存在其歸屬的節點的順序往下的節點,例如你的冗余系數為3(即數據會在不同節點中保存三份),那么如果通過hash計算你的數據在A區間[7,233],你的數據會被同時保存在A,B,C三個節點上。這樣如果A節點出現故障,那么B,C節點就能處理這部分數據的請求了。而某些設計會使E節點將自己的范圍擴大到A233,以接受對出故障的A節點的請求。
優化的數據分配策略
為了解決由於節點比較少導致數據分配不均的問題,很多DHT系統都實現了一種叫做虛擬節點的技術。例如4個虛擬節點的系統中,A節點可能被虛擬化成A_1,A_2,A_3,A_4這四個虛擬節點,然后對這四個虛擬節點再進行hash運算,A節點負責的key值區間就比較分散了。
13.4.4 連續范圍分區
使用連續范圍分區的方法進行數據分片,需要我們保存一份映射關系表,標明哪一段key值對應存在哪台機器上。和一致性hash類似,連續范圍分區會把key值按連續的范圍分段,每段數據會被指定保存在某個節點上,然后會被冗余備份到其它的節點。和一致性hash不同的是,連續范圍分區使得key值上相鄰的兩個數據在存儲上也基本上是在同一個數據段。這樣數據路由表只需記錄某段數據的開始和結束點[start,end]就可以了。 通過動態調整數據段到機器結點的映射關系,可以更精確的平衡各節點機器負載。如果某個區段的數據負載比較大,那么負載控制器就可以通過縮短其所在節點負責的數據段,或者直接減少其負責的數據分片數目。通過添加這樣一個監控和路由模塊,使我們能夠更好的對數據節點進行負載均衡。
BigTable的處理方式
Google BigTable 論文中描述了一種范圍分區方式,它將數據切分成一個個的tablet數據塊。每個tablet保存一定數量的鍵值對。然后每個Tablet 服務器會存儲多個tablet塊,具體每個Tablet服務器保存的tablet數據塊數,則是由服務器壓力來決定的。 每個tablet大概100-200MB大。如果tablet的尺寸變小,那么兩個tablet可能會合並成一個tablet,同樣的如果一個tablet過大,它也會被分裂成兩個tablet,以保持每個tablet的大小在一定范圍內。在整個系統中有一個master機器,會根據tablet的大小、負載情況以及機器的負載能力等因素動態地調整tablet在各個機器上的分布。
master服務器會把 tablet 的歸屬關系存在元數據表里。當數據量非常大時,這個元數據表實際也會變得非常大,所以歸屬關系表實際上也是被切分成一個個的tablet保存在tablet服務器中的。查詢數據的時候就需要二次查詢。
故障處理
在BigTable中,master機器是一個故障單點,不過系統可以容忍短時間的master故障。另一方面,如果tablet 服務器故障,那么master可以把對其上tablet的所有請求分配到其它機器節點。 為了監測和處理節點故障,BigTable實現了一個叫Chubby的模塊,Chubby是一個分布式的鎖系統,用於管理集群成員及檢測各成員是否存活。ZooKeeper是Chubby的一個開源實現,有很多基於 Hadoop 的項目都使用它來進行二級master和tablet節點的調度。
基於范圍分區的NoSQL項目
HBase 借鑒了BigTable的分層理論來實現范圍分區策略。tablet相關的數據存在HDFS里。HDFS 會處理數據的冗余備份,並負責保證各備份的一致性。而像處理數據請求,修改存儲結構或者執行tablet的分裂和合並這種事,是具體的tablet服務器來負責的。 MongoDB也用了類似於BigTable的方案來實現范圍分區。他用幾台配置機器組成集群來管理數據在節點上的分布。這幾台機器保存着一樣的配置信息,他們采用 two-phase commit 協議來保證數據的一致性。這些配置節點實際上同時扮演了BigTable中的master的路由角色,及Chubby 的高可用性調度器的角色。而MongoDB具體的數據存儲節點是通過其Replica Sets方案來實現數據冗余備份的。 Cassandra 提供了一個有序的分區表,使你可以快速對數據進行范圍查詢。Cassandra也使用了一致性hash算法進行數據分配,但是不同的是,它不是直接按單條數據進行hash,而是對一段范圍內的數據進行hash,也就是說20號數據和21號數據基本上會被分配在同一台機器節點上。 Twitter的Gizzard框架也是通過使用范圍分區來管理數據在多個節點間的備份與分配。
13.4.5 選擇哪種分區策略
如果你需要經常做范圍查詢,需要按順序對key值進行操作,那么你選擇范圍分區會比較好。那如果我不會進行范圍查詢或者順序查詢呢?這時候hash分區相對來說可能更方便一點,而且hash分區時可能通過虛擬結點的設置來解決hash不均的問題。在hash分區中,基本上只要在客戶端執行相應的hash函數就能知道對應的數據存在哪個節點上了。而如果考慮到節點故障后的數據轉移情況,可能獲取到數據存放節點就會麻煩一些了。 范圍分區要求在查詢數據前對配置節點還要進行一次查詢,如果沒有特別好的高可用容災方案,配置節點將會是一個危險的故障單點。當然,你可以把配置節點再進行一層負載均衡來減輕負載。而范圍分區時如果某個節點故障了,它上面的數據可以被分配到多個節點上,而不像在一致性hash時,只能遷移到其順序的后一個節點,造成下一個節點的負載飆升。
未完待續!