探索併發編程(七)------分佈式環境中併發問題

在分佈式環境中,處理併發問題就沒辦法通過操作系統和JVM的工具來解決,那麼在分佈式環境中,可以採取一下策略和方式來處理:

  • 避免併發
  • 時間戳
  • 串行化
  • 數據庫
  • 行鎖
  • 統一觸發途徑

避免併發

在分佈式環境中,如果存在併發問題,那麼很難通過技術去解決,或者解決的代價很大,所以我們首先要想想是不是可以通過某些策略和業務設計來避免併發。比如通過合理的時間調度,避開共享資源的存取衝突。另外,在並行任務設計上可以通過適當的策略,保證任務與任務之間不存在共享資源,比如在以前博文中提到的例子,我們需要用多線程或分佈式集羣來計算一堆客戶的相關統計值,由於客戶的統計值是共享數據,因此會有併發潛在可能。但從業務上我們可以分析出客戶與客戶之間 數據是不共享的,因此可以設計一個規則來保證一個客戶的計算工作和數據訪問只會被一個線程或一臺工作機完成,而不是把一個客戶的計算工作分配給多個線程去 完成。這種規則很容易設計,例如可以採用hash算法。

時間戳

分佈式環境中併發是沒法保證時序的,無論是通過遠程接口的同步調用或異步消息,因此很容易造成某些對時序性有要求的業務在高併發時產生錯誤。比如系統A需要把某個值的變更同步到系統B,由於通知的時序問題會導致一個過期的值覆蓋了有效值。對於這個問題,常用的辦法就是採用時間戳的方式,每次系統A發送變更給系統B的時候需要帶上一個能標示時序的時間戳,系統B接到通知後會拿時間戳與存在的時間戳比較,只有當通知的時間戳大於存在的時間戳,才做更新。這種方式比較簡單,但關鍵在於調用方一般要保證時間戳的時序有效性。

串行化

有的時候可以通過串行化可能產生併發問題操作,犧牲性能和擴展性,來滿足對數據一致性的要求。比如分佈式消息系統就沒法保證消息的有序性,但可以通過變分佈式消息系統爲單一系統就可以保證消息的有序性了。另外,當接收方沒法處理調用有序性,可以通過一個隊列先把調用信息緩存起來,然後再串行地處理這些調用。

數據庫

分佈式環境中的共享資源不能通過Java裏同步方法或加鎖來保證線程安全,但數據庫是分佈式各服務器的共享點,可以通過數據庫的高可靠一致性機制來滿足需求。比如,可以通過唯一性索引來解決併發過程中重複數據的生產或重複任務的執行;另外有些更新計算操作也儘量通過sql來完成,因爲在程序段計算好後再去更新就有可能發生髒複寫問題,但通過一條sql來完成計算和更新就可以通過數據庫的鎖機制來保證update操作的一致性。

行鎖

有的事務比較複雜,無法通過一條sql解決問題,並且有存在併發問題,這時就需要通過行鎖來解決,一般行鎖可以通過以下方式來實現:

  • 對於Oracle數據庫,可以採用select ... for update方式。這種方式會有潛在的危險,就是如果沒有commit就會造成這行數據被鎖住,其他有涉及到這行數據的任務都會被掛起,應該謹慎使用
  • 在表裏添加一個標示鎖的字段,每次操作前,先通過update這個鎖字段來完成類似競爭鎖的操作,操作完成後在update鎖字段復位,標示已歸還鎖。這種方式比較安全,不好的地方在於這些update鎖字段的操作就是額外的性能消耗

統一觸發途徑

當一個數據可能會被多個觸發點或多個業務涉及到,就有併發問題產生的隱患,因此可以通過前期架構和業務設計,儘量統一觸發途徑,觸發途徑少了一是減少併發的可能,也有利於對於併發問題的分析和判斷。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章