在當今資訊爆炸的時代,單台計算機已經無法負載日益增長的業務發展,雖然也有性能強大的超級計算機,但是這種高端機不僅費用高昂,也不靈活,一般的企業是負擔不起的,而且也損失不起,那麼将一群廉價的普通計算機組合起來,讓它們協同工作就像一台超級計算機一樣地對外提供服務,就成了順其自然的設想,但是這又增加了軟體的複雜度,要求開發的軟體需要具備橫向擴充能力,比如:Kafka、Elasticsearch、Zookeeper等就屬于這一類軟體,它們天生都是"分布式的",即可以通過添加機器節點來共同地分攤資料存儲和負載壓力。
分布在不同區域的計算機,彼此之間通過網絡建立通信,互相協作作為一個整體對外提供服務,這就是叢集,如果我們開發的系統具備這樣的能力,那麼理論上就具備無限橫向擴容的能力,系統的吞吐量就會随着機器數增加而增長,那麼未來當系統出現高負載的時候,就可以很好地應對這種情況。
通過上面分析,我們知道實作叢集,其實就是采用多台計算機來共同承擔和負載系統壓力,那麼就涉及到多台計算機需要參與一起處理資料,為了保證可用性,一般都會在每台計算機上備份一份資料,這樣隻要有一個節點保持同步狀态,那麼資料就不會丢失,比如kafka分區多副本、Elasticsearch的副本分片,由于同一資料塊及其副本位于不用的機器,随着時間的推移,再加上不可靠的網絡通信,所有機器上的資料必然會不完全一緻,這個時候假如發生一種極端情況,所有的機器當機了,又如何保證資料不丢失呢(其實隻有兩種方法)?
保證可用性:選擇第一台恢複正常服務的機器(不一定擁有全部資料)作為可信的資料來源,快速恢複叢集,即停機時間優于同步。
保證資料一緻性:等待第一台擁有全部資料的機器恢複正常,再恢複叢集,即同步優于停機時間,比如禁用kafka的unclean leader選舉機制就是這種政策。
其實當大多數機器不可用時,就需要在可用性和一緻性之間進行妥協了,是以另一個更符合分布式系統的Base理論又被創造出來了。
當由多台計算機組成的叢集對外提供服務時,其實就是對外提供讀、寫的能力。
為了将資料合理、均勻地寫到各個機器上,提高叢集寫能力;為了将讀請求負載均衡到不同的節點,提高叢集的讀能力;為了解耦資料存儲和實體節點,提高分布式讀寫并行處理的能力,聰明的工程師引入了一個邏輯資料存儲機關,統稱為資料塊,比如Kafka的分區(partion)、Elasticsearch的分片(shard),這樣的虛拟化大大提高了叢集讀寫的靈活性。
備注:是以啊,名字不重要,知其是以然最重要。
實際上當叢集作為一個整體處理資料時,可能每一個節點都會收到讀寫請求,但是資料又是分散在不同的節點上,是以就需要每個節點都清楚地知道叢集中任意一個資料塊的位置,然後再将請求轉發到相應的節點,這就是“協調節點”的工作。比如:Elasticsearch的master節點管理叢集範圍内的所有變更,主分片管理資料塊範圍内的所有變更。
百度百科:quorum,翻譯法定人數,指舉行會議、通過議案、進行選舉或組織某種專門機構時,法律所規定的必要人數,未達法定人數無效。
由于網絡分區的存在,這個機制被廣泛地應用于分布式系統中,比如叢集節點之間選舉Master;資料塊之間選舉Header等;在分布式存儲中,也被稱為Quorum讀寫機制,即寫入的時候,保證大多數節點都寫入成功(一般的做法會選舉一個主資料塊(header),保證它寫成功,然後再同步到備援的副本資料塊);讀取的時候保證讀取大多數節點的資料(一般的做法是由協調節點分發請求到不同的節點,然後将所有檢索到的資料進行全局彙總排序後再傳回);由于讀寫都是大多數,那麼中間肯定存在最新的重疊資料,這樣就能保證一定能讀到最新的資料。
從上面分析可以得出,隻要大多數節點處于活躍可用狀态,那麼整個叢集的可用性就不會受到影響;隻要大多資料塊處于活躍可用的狀态,那麼就能持續地提供讀寫服務;隻要有一個資料塊完成了同步狀态,那麼資料就不會丢失;這其實就是通過一種備援機制來嘗試處理fail/recover模式的故障,通俗點講就是容忍單點故障,至少需要部署3個節點;容忍2點故障,至少需要部署5個節點,機器節點越多分區容忍性就越強,即通過增加機器數來降低由于機器故障影響服務的機率,頓悟了吧,嘿嘿,是以保證叢集可用的前提就是有奇數個節點、奇數個資料塊保持活躍可用狀态,不然就無法選舉出master或header。
大多數投票機制運用起來也非常靈活,當分布式系統追求強一緻性時,需要等待所有的資料快及其副本全部寫入成功才算完成一次寫操作,即寫全部(write all),可以了解一種事務保證,要麼全部寫入,要麼一個都不寫入,比如:kafka從0.11.0.0 版本開始, 當producer發送消息到多個topic partion時,就運用了這種機制,來保證消息傳遞的exactly-once語義,是不是很帥,而且這種情況下,從任意一個節點都能讀到最新的資料,讀性能最高;當分布式系統追求最終一緻性時,隻需等待主資料塊(leader)寫入成功即可,再由主資料塊通過消息可達的方式同步到副本資料塊。
為了能夠滿足不同場景下對資料可靠性和系統吞吐量的要求,最大化資料持久性和系統可用性,很多元件都提供了配置項,允許使用者定義這個大多數的法定數量,下面我們就來談談一些常用元件的配置:
Elasticsearch

由上圖可以看到,整個叢集由三個運作了Elasticsearch執行個體的節點組成,有兩個主分片,每個分片又有兩個副分片,總共有6個分片拷貝,Elasticsearch内部自動将相同的分片放到了不同的節點,非常合理和理想。
當我們建立一個文檔時:
1、用戶端向 Node 1 發送建立文檔的寫請求。
2、節點使用文檔的 _id 确定文檔屬于分片 0 。請求會被轉發到 Node 3,因為分片 0 的主分片目前被配置設定在 Node 3 上。
3、Node 3 在主分片上面執行請求。如果成功了,它将請求并行轉發到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都報告成功, Node 3 将向協調節點報告成功,協調節點向用戶端報告成功。
這就是Elasticsearch處理寫請求的典型步驟順序,同時每種業務場景對資料可靠性的要求和系統性能也不一樣,是以Elasticsearch提供了Consistence配置項:
1、one:主分片處于活躍可用狀态就可以處理寫請求。
系統吞吐量最高,但資料可能會丢失,對資料可靠性要求不是很高的場景非常适合,比如實時的時序資料處理(日志)。
2、all:主分片和所有副本分片處于活躍可用狀态才允許處理寫請求。
系統吞吐量最低,但資料不會丢失。處理關鍵的業務資料非常合适。
3、quorum:必須有大多數的分片拷貝處于活躍可用狀态才允許處理寫請求。
平衡系統吞吐量和資料可靠性,一般業務系統都使用這個配置。
Kafka
當向Kafka 寫資料時,producers可以通過設定ack來自定義資料可靠性的級别:
0:不等待broker傳回确認消息。
1: leader儲存成功傳回。
-1(all): 所有備份都儲存成功傳回。
備注:預設情況下,為了保證分區的最大可用性,當acks=all時,隻要ISR集合中的副本分區寫入成功,kafka就會傳回消息寫入成功。如果要真正地保證寫全部(write all),那麼我們需要更改配置<code>transaction.state.log.min.isr</code>來指定topic最小的ISR集合大小,即設定ISR集合長度等于topic的分區數。
如果所有的節點都挂掉,還有Unclean leader選舉機制的保證,建議大家下去閱讀kafka《官方指南》設計部分,深入了解kafka是如何通過引入ISR集合來變通大多數投票機制,進而更好地保證消息傳遞的不同語義。
對于分布式系統,自動處理故障的關鍵就是能夠精準地知道節點的存活狀态(alive)。有時候,節點不可用,不一定就是其本身挂掉了,極有可能是暫時的網絡故障;在這種情況下,如果馬上選舉一個master節點,那麼等到網絡通信恢複正常的時候,豈不是同時存在兩個master,這種現象被形象地稱為“叢集腦裂”,先留給大家下去思考吧。呵呵,明天要早起,碎覺了,大家晚安。
備注:設計一個正在高可用的分布式系統,需要考慮的故障情況往往會很複雜,大多數元件都隻是處理了fail/recover模式的故障,即容忍一部分節點不可用,然後等待恢複;并沒有處理拜占庭故障(Byzantine),即節點間的信任問題,也許區塊鍊可以解決吧,大家可以下去多多研究,然後我們一起讨論,共同學習,一起進步。
分享了這麼多,請大家總結一下大多數投票機制的優點和缺點?歡迎評論區留言,哈哈,真的要睡覺了,晚安。
由于昨晚太晚了,第二天又要早起參加團建活動,對于最後就抛出的問題,希望大家下去總結一下大多數投票的優缺點,現在就來補充一下。
大多數投票機制延遲取決于最快的伺服器,即等待資料備份完成的等待時間取決于最快的follower,比如副本因子是3,header占據1位,再有1位最快的follower同步完成,就滿足大多數了。
大多數(n+1)的節點挂掉就無法選舉leader,進而整個叢集徹底失去可用性,比如:為了備援單點故障,通常需要三個節點備份資料,但是當其中兩台挂掉時,整個叢集就挂了。僅僅靠備援資料來避免單點故障是不夠,通常對磁盤空間需求量為2n+1倍,相應地也會導緻寫吞吐量下降2n+1倍,這種高昂的存儲方式并不适合存儲原始資料,這就是為什麼quorum算法更适合共享叢集配置資料,如zookeeper,這也是kafka為什麼要引入一個同步狀态備份集合(ISR),通過降低所需的備份資料而帶來額外的吞吐量和磁盤空間,進而提高kafka處理海量實時資料的能力。
做一個有底蘊的軟體工作者