《設計數據密集型應用/DDIA》精要翻譯(六) :分佈式系統中的問題

這一章我們會討論分佈式系統中一些常見的問題,在下一章中我們會討論這些問題的解決辦法。

1.故障與部分失敗

在分佈式系統中,系統的部分組件常常會以以某種未知的方式被破壞,我們稱之爲部分失敗/部分故障。而我們的目標就是在不可靠的組件上構建一個可靠的系統。

爲了容忍部分失敗:

  • 第一步是檢測失敗:大多數系統利用超時來判斷節點是否可用,但是超時機制沒辦法區分是網絡失效還是節點宕機
  • 在檢測到失敗之後,如何使系統去容忍失敗也是個大問題:節點間通信的唯一方法是通過不可靠的網絡發送信息,不能由一個節點來做決策,因此我們需要一致性協議算法來幫助我們完成這個目標。

2.不可靠的網絡

在分佈式系統中,節點與節點間的網絡通信是不可靠的,它表現在:

  • 網絡分區:網絡的一部分發生了故障而被切斷
  • 延遲問題:TCP協議雖然提供了數據校驗、超時重傳等機制,但是沒辦法保證數據包在一定時間內保證到達,這種延遲可能是無限的。

3.不可靠的時鐘

在分佈式系統中,時鐘是一個非常重要且棘手的問題:

  • 節點與節點間的通信是有延遲的,我們很難確定多個節點間事件的順序問題
  • 每臺機器都有自己的時鐘(硬件設備),這些設備不都是完全準確的

時鐘分爲兩種,單調時鐘與Time-of-Day時鐘:

  • 單調時鐘一般用於計算持續時間,如Java中的System.nanoTime()
  • Time-of-Day時鐘根據某個日曆返回當前的日期和時間,一般依賴於NTP服務器或其他外部時間源

時鐘不同步導致的問題

時鐘的不同步會導致很多問題,比如前面的博客中,我們談到多主備份數據庫解決寫入衝突的一個常見辦法是LWW,即最後寫入者勝出,在時鐘不同步的情況下可能會導致如下問題:

ClientA在node1上寫入x=1,並同步到node3。 ClientB在node3上寫入x=x+1,也同步到node2。但是B的寫入同步比A的更早到達,從而導致在node2上x+1的操作消失了。

進程的暫停問題

假設在一個分佈式數據庫中,節點通過選舉方式成爲leader(只有leader能接受寫請求),並獲得一個租約,且同一時間只有一個節點能獲得租約。假設有這麼一段代碼:

while (true) {
     request = getIncomingRequest();
     // Ensure that the lease always has at least 10 seconds remaining
     if (lease.expiryTimeMillis - System.currentTimeMillis() < 10000) {   
         lease = lease.renew();
      }
     if (lease.isValid()) { 
         process(request);
     }
}

這段代碼的問題:

如果當前線程在lease.isValid()之後暫停了15秒,然後才繼續運行process(request),而這時候租約可能已經到期了,它已經不再是leader了!

那麼這個進程爲什麼要暫停這麼久呢? 可能的原因如下:

  • GC運行了很久
  • 虛擬機被掛起,當前所有進程被暫停並把內存內容保存到磁盤
  • 進程接收到了SIGSTOP信號,暫停使用CPU週期;之後又接收到SIGCONT信號才恢復
  • 執行了同步訪問磁盤的操作,如果磁盤需要走網絡(比如EBS),可能延遲很大
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章