Java大型互聯網分散式系統各種問題點之分散式消息隊列編程設計

分散式系統(distributed system)是建立在網路之上的軟體系統。正是因為軟體的特性,所以分散式系統具有高度的內聚性和透明性。因此,網路和分散式系統之間的區別更多的在於高層軟體(特別是操作系統),而不是硬體。內聚性是指每一個資料庫分佈節點高度自治,有本地的資料庫管理系統。透明性是指每一個資料庫分佈節點對用戶的應用來說都是透明的,看不出是本地還是遠程。在分散式資料庫系統中,用戶感覺不到數據是分佈的,即用戶不須知道關係是否分割、有無副本、數據存於哪個站點以及事務在哪個站點上執行等。

分散式系統的特點

分散式系統最大的特點是可擴展性,它能夠適應需求變化而擴展。企業級應用需求經常隨時間而不斷變化,這也對企業級應用平台提出了很高的要求。企業級應用平台必須要能適應需求的變化,即具有可擴展性。比如移動互聯網2C應用,隨著互聯網企業的業務規模不斷增大,業務變得越來越複雜,併發用戶請求越來越多,要處理的數據也越來越多,這個時候企業級應用平台必須能夠適應這些變化,支持高併發訪問和海量數據處理。分散式系統有良好的可擴展性,可以通過增加伺服器數量來增強分散式系統整體的處理能力,以應對企業的業務增長帶來的計算需求。

Advertisements

分散式系統的核心理念是讓多台伺服器協同工作,完成單台伺服器無法處理的任務,尤其是高併發或者大數據量的任務。分散式系統由獨立的伺服器通過網路鬆散耦合組成的。每個伺服器都是一台獨立的PC機,伺服器之間通過內部網路連接,內部網路速度一般比較快。因為分散式集群里的伺服器是通過內部網路鬆散耦合,各節點之間的通訊有一定的網路開銷,因此分散式系統在設計上儘可能減少節點間通訊。此外,因為網路傳輸瓶頸,單個節點的性能高低對分散式系統整體性能影響不大。比如,對分散式應用來說,採用不同編程語言開發帶來的單個應用服務的性能差異,跟網路開銷比起來都可以忽略不計。因此,分散式系統每個節點一般不採用高性能的伺服器,而是性能相對一般的普通PC伺服器。提升分散式系統的整體性能是要通過橫向擴展(增加更多的伺服器),而不是縱向擴展(提升每個節點的伺服器性能)。

Advertisements

分散式系統最大的特點是廉價高效:由成本低廉的PC伺服器組成的集群,在性能方面能夠達到或超越大型機的處理性能,在成本上遠低於大型機。這也是分散式系統最吸引人之處。成本低廉的PC伺服器在硬體可靠性方面比大型機相去甚遠,於是分散式系統由軟體來對硬體進行容錯,通過軟體來保證整體系統的高可靠性。

分散式系統最大的好處是實現企業應用服務層面的彈性擴展。應用服務層面的彈性擴展是相對計算資源層面的彈性擴展而言的。一般公有雲服務(IaaS)廠商都會提供計算資源層面的彈性擴展,比如可以很方便地增加或刪除虛擬主機、提升或降低虛擬主機的性能配置等等。但是企業客戶真正需要的是應用服務層面的彈性擴展,即隨著業務量的漲落,後台應用服務的實例能動態變化,這是IaaS廠商還做不到的。比如,某移動互聯網短視頻分享應用,在晚間11點到凌晨1點是訪問高峰,同時在線人數高達幾十萬,這時後台應用服務要擴張到數千個實例才能應付這麼高併發的訪問請求;過了高峰時段,後台應用服務可以收縮到幾十個實例。有了分散式系統,就可以很方便地調度應用服務實例,從幾十個到幾百個甚至上千個,真正實現應用服務的彈性擴展。

分散式環境的各種問題

分散式系統體系結構從其出現之初就伴隨著諸多的難題和挑戰。

通信異常

分散式系統中個計算機之間是通過網路進行通信的。由於網路本身的不可靠性,每次網路通信都會伴隨著網路不可用的風險。即使分散式系統各節點之間的網路通信能夠正常進行,其延時也會遠遠大於單機操作。在分散式系統中,消息延時和消息丟失非常普遍。

網路分區

當網路發生異常情況,可能導致分散式系統中某些節點之間能夠正常通信,而某些節點之間無法通信——該現象就是網路分區,就是俗稱的『腦裂』。當網路分區出現時,分散式系統就會出現局部小集群,小集群內計算機可以相互通信,小集群之間計算機無法通信。這就對分散式一致性提出了非常大的挑戰。

三態

因為在分散式系統中,網路可能會出現各式各樣的問題,因此分散式系統的每一次請求和響應,存在特有的『三態』概念,即成功、失敗與超時。在傳統的單機系統中,應用程序在調用一個函數之後,能夠得到一個非常明確的相應:成功或失敗。而在分散式系統中,由於網路是不可靠的,當網路出現異常的情況下,就可能出現超時現象,發生消息丟失現象。

節點故障

節點故障是分散式環境下一個比較常見的問題,指的是組成分散式系統的伺服器節點出現宕機或『僵死』現象。通常根據經驗來說,每個節點都有可能出現故障,並且每天都在發生。

分散式隊列模型編程和非同步編程

分散式隊列編程模型的通訊機制一般是採用非同步機制,但是它並不等同於非同步編程。

首先,並非所有的非同步編程都需要引入隊列的概念,例如:大部分的操作系統非同步I/O操作都是通過硬體中斷( Hardware Interrupts)來實現的。

其次,非同步編程並不一定需要跨進程,所以其應用場景並不一定是分散式環境。

最後,分散式隊列編程模型強調發送者、接收者和分散式隊列這三個角色共同組成的架構。這三種角色與非同步編程沒有太多關聯。

分散式隊列模式編程和流式編程

隨著Spark Streaming,Apache Storm等流式框架的廣泛應用,流式編程成了當前非常流行的編程模式。但是本文所闡述的分散式隊列編程模型和流式編程並非同一概念。

首先,本文的隊列編程模式不依賴於任何框架,而流式編程是在具體的流式框架內的編程。

其次,分散式隊列編程模型是一個需求解決方案,關注如何根據實際需求進行分散式隊列編程建模。流式框架里的數據流一般都通過隊列傳遞,不過,流式編程的關注點比較聚焦,它關注如何從流式框架里獲取消息流,進行map、reduce、 join等轉型(Transformation)操作、生成新的數據流,最終進行匯總、統計。

緩存優化

處於「處理-轉發」模式下運行的生產者往往被設計成請求驅動型的服務,即每個請求都會觸發一個處理線程,線程處理完后將結果寫入分散式隊列。如果由於某種原因隊列服務不可用,或者性能惡化,隨著新請求的到來,生產者的處理線程就會產生堆積。這可能會導致如下兩個問題:

系統可用性降低。由於每個線程都需要一定的內存開銷,線程過多會使系統內存耗盡,甚至可能產生雪崩效應導致最終完全不可用。

信息丟失。為了避免系統崩潰,工程師可能會給請求驅動型服務設置一個處理線程池,設置最大處理線程數量。這是一種典型的降級策略,目的是為了系統崩潰。但是,後續的請求會因為沒有處理線程而被迫阻塞,最終可能產生信息丟失。例如:對於廣告計費採集,如果採集系統因為線程耗盡而不接收客戶端的計費行為,這些計費行為就會丟失。

緩解這類問題的思路來自於CAP理論,即通過降低一致性來提高可用性。生產者接收線程在收到請求之後第一時間不去處理,直接將請求緩存在內存中(犧牲一致性),而在後台啟動多個處理線程從緩存中讀取請求、進行處理並寫入分散式隊列。與線程所佔用的內存開銷相比,大部分的請求所佔內存幾乎可以忽略。通過在接收請求和處理請求之間增加一層內存緩存,可以大大提高系統的處理吞吐量和可擴展性。這個方案本質上是一個內存生產者消費者模型。批量寫入優化

如何設計一個消息隊列

我們現在明確了消息隊列的使用場景,下一步就是如何設計實現一個消息隊列了。

基於消息的系統模型,不一定需要broker(消息隊列服務端)。市面上的的Akka(actor模型)、ZeroMQ等,其實都是基於消息的系統設計範式,但是沒有broker。

我們之所以要設計一個消息隊列,並且配備broker,無外乎要做兩件事情:

消息的轉儲,在更合適的時間點投遞,或者通過一系列手段輔助消息最終能送達消費機。

規範一種範式和通用的模式,以滿足解耦、最終一致性、錯峰等需求。

掰開了揉碎了看,最簡單的消息隊列可以做成一個消息轉發器,把一次RPC做成兩次RPC。發送者把消息投遞到服務端(以下簡稱broker),服務端再將消息轉發一手到接收端,就是這麼簡單。

總結

以上是對Java大型互聯網分散式系統各種問題點之分散式消息隊列編程設計,分享給大家,希望大家可以了解什麼是Java大型互聯網分散式系統各種問題點之分散式消息隊列編程設計。覺得收穫的話可以點個關注收藏轉發一波喔,謝謝大佬們支持。(吹一波,233~~)這個是我Java內部資料分享交流群:469717771 驗證碼:頭條(06 必過)歡迎大家的加入!!!

Advertisements

你可能會喜歡