讀構建可擴展分散式系統:方法與實踐06非同步消息傳遞

来源:https://www.cnblogs.com/lying7/p/18415886
-Advertisement-
Play Games

1. 非同步消息傳遞 1.1. 通信是分散式系統的基礎,也是架構師需要納入其系統設計的主要問題 1.2. 客戶端發送請求並等待伺服器響應 1.2.1. 這就是大多數分散式通信的設計方式,因為客戶端需要得到即時響應後才能繼續 1.2.2. 並非所有系統都有這個要求 1.3. 使用非同步通信的方式,客戶端( ...


1. 非同步消息傳遞

1.1. 通信是分散式系統的基礎,也是架構師需要納入其系統設計的主要問題

1.2. 客戶端發送請求並等待伺服器響應

  • 1.2.1. 這就是大多數分散式通信的設計方式,因為客戶端需要得到即時響應後才能繼續

  • 1.2.2. 並非所有系統都有這個要求

1.3. 使用非同步通信的方式,客戶端(稱為生產者)將其請求發送到中間消息傳遞服務

1.4. 生產者對他們發送的請求“發後即忘”(fire and forget)

  • 1.4.1. 一旦請求被傳遞到消息傳遞服務,生產者就會進入其邏輯中的下一步,並確信它發送的請求最終得到處理

  • 1.4.2. 消息機制提高了系統的響應能力,因為生產者不必等到請求處理完成

1.5. 非同步消息傳遞是可擴展系統架構的一個組成部分

1.6. 消息傳遞機制在經歷請求高峰和低谷的系統中特別有吸引力

  • 1.6.1. 在高峰時段,生產者可以將請求添加到隊列中並快速響應客戶端,而無須等待請求被處理

1.7. 消息隊列可以分佈在多個代理之間以擴展消息吞吐量,也可以複製隊列來提高可用性

1.8. 消息機制並非不存在風險

  • 1.8.1. 將消息副本放在隊列中,如果隊列保留在記憶體中,則消息可能會丟失

1.9. 將消息副本放在隊列中,如果隊列保留在記憶體中,則消息可能會丟失

2. 消息傳遞簡介

2.1. 非同步消息傳遞平臺是一個成熟的技術領域

  • 2.1.1. 久負盛名的IBM MQ系列出現於1993年,至今仍是企業系統的中流砥柱

  • 2.1.2. Java消息傳遞服務(JMS)是一種API級別的規範,由多個JEE供應商實現和支持

  • 2.1.3. RabbitMQ,可以說是部署最廣泛的開源消息傳遞系統

2.2. 消息傳遞原語

  • 2.2.1. 消息隊列

  • 2.2.1.1. 存儲一系列消息的隊列

  • 2.2.2. 生產者

  • 2.2.2.1. 將消息發送到隊列

  • 2.2.2.2. 生產者將消息發送到代理上的命名隊列

  • 2.2.3. 消費者

  • 2.2.3.1. 從隊列中取出消息

  • 2.2.3.2. 多個消費者可以從同一個隊列中獲取消息

  • 2.2.3.3. 消費者獲取消息有兩種行為模式,即拉取或推送

>  2.2.3.3.1. 在拉取(也稱為輪詢)模式中,消費者向代理髮送請求,代理用下一條可供處理的消息進行響應

>  2.2.3.3.2. 在推送模式下,消費者告知代理自己希望從隊列中接收消息

  >   2.2.3.3.2.1. 消費者提供了一個回調函數,當消息可用時應調用該函數

  >   2.2.3.3.2.2. 然後消費者就會阻塞(或執行其他工作)​,消息代理會在有消息可用時將消息傳遞給回調函數進行處理

  >   2.2.3.3.2.3. 使用推送模式更加高效

2.2.3.3.2.3.1. 避免了代理可能被來自多個消費者的請求壓垮,並使代理能更高效地實現消息傳遞

2.2.3.3.2.3.2. 消費者確認後,代理就可以將消息標記為已傳遞,並將其從隊列中刪除

2.2.3.3.2.3.3. 如果使用自動確認,消息傳遞給消費者之後,在消息處理之前代理就會收到確認

  • 2.2.4. 消息代理

  • 2.2.4.1. 消息代理是一個服務,管理著一個或多個隊列

  • 2.2.4.2. 消息代理可以在同一硬體上管理多個隊列

2.3. 通常會有消費者希望確保消息在確認之前得到完全處理

  • 2.3.1. 它將使用手動確認的方式

  • 2.3.2. 可以防止出現消息已經被傳遞給消費者,但由於消費者崩潰而導致消息未被處理的問題

  • 2.3.3. 確實會增加消息確認的延遲

2.4. 無論選擇何種確認模式,未確認的消息都有效地保留在隊列中,並將在稍後的某個時間傳遞給另一個消費者處理

2.5. 消息持久化

  • 2.5.1. 預設情況下,消息隊列通常保存在記憶體中,以便為生產者和消費者提供儘可能快的服務

  • 2.5.2. 只要記憶體充足,在記憶體中管理隊列的開銷就是最小的

  • 2.5.2.1. 如果伺服器崩潰,那麼它確實有丟失消息的風險

  • 2.5.3. 為了防止消息丟失,隊列可以設置成可持久化的

  • 2.5.3.1. 當生產者將消息放入隊列時,只有消息寫入磁碟後操作才會完成

  • 2.5.3.2. 如果消息代理髮生故障,在重新啟動時它可以將隊列內容恢復到失敗前的狀態,並且不會丟失任何消息

  • 2.5.4. 持久隊列會固有地增加發送操作的響應時間,但數據安全性卻得到了提高

  • 2.5.5. 代理通常會在記憶體和磁碟上維護隊列內容,這樣就能在正常操作時以最小的開銷將消息發送給消費者

2.6. 發佈-訂閱

  • 2.6.1. 在發佈-訂閱系統中,消息隊列被稱為主題

  • 2.6.2. 一個主題一般都是一個消息隊列,它會將每個發佈的消息傳遞給多個訂閱者之一

  • 2.6.3. 發佈者與訂閱者分離,訂閱者的數量可以動態變化

  • 2.6.3.1. 須對現有系統進行任何更改即可添加新的訂閱者,架構具有高度的可擴展性

  • 2.6.4. 發佈-訂閱模式給消息代理帶來了額外的性能負擔

  • 2.6.4.1. 利用推送的消息消費模型為發佈-訂閱架構提供了最有效的解決方案

  • 2.6.5. 發佈-訂閱消息傳遞機制是構建分散式事件驅動架構的關鍵組件

  • 2.6.5.1. 在事件驅動的架構中,多個服務可以使用消息代理主題發佈與某些狀態變更相關的事件

  • 2.6.5.2. 服務可以通過訂閱主題來註冊感興趣的各種事件類型

  • 2.6.5.3. 該主題發佈的每個事件都會發送給所有感興趣的消費者服務

2.7. 消息複製

  • 2.7.1. 在非同步系統中,消息代理可能會是一個潛在的故障點

  • 2.7.2. 系統或網路故障可能導致代理不可用,從而使系統無法正常運行

  • 2.7.3. 大多數消息代理都允許在多個代理之間以物理方式複製邏輯隊列和主題,每個代理都在自己的節點上運行

  • 2.7.4. 消息隊列複製的最常見方法是領導者-追隨者(leader-follower)架構

  • 2.7.4.1. 一個代理被指定為領導者,生產者和消費者分別通過該領導者發送和接收消息

  • 2.7.4.2. 追隨者被稱為熱備用,是領導者的副本,如果領導者發生故障,則追隨者頂上

  • 2.7.5. 在故障場景下,生產者和消費者可以通過切換訪問追隨者來繼續操作,稱之為故障轉移

  • 2.7.5.1. 故障轉移在消息代理的客戶端庫中實現,因此對生產者和消費者來說是透明的

  • 2.7.6. 實現一個可以執行隊列複製的代理是一件複雜的事情

  • 2.7.6.1. 不要考慮使用自己的複製方案或任何其他複雜的分散式演算法

  • 2.7.6.2. 你的解決方案將不如現有解決方案有效,開發成本將超出你的預期

3. RabbitMQ

3.1. 是分散式系統中使用最廣泛的消息代理之一

3.2. RabbitMQ代理採用Erlang語言構建,主要為AMQP(Advanced Message Queuing Protocol,高級消息隊列協議)開放標準提供支持

  • 3.2.1. AMQP誕生於金融行業,致力於定義合作協議

  • 3.2.1.1. 它是一種二進位協議,為執行該協議的不同產品提供互操作性

  • 3.2.2. RabbitMQ支持開箱即用,支持AMQP v0-9-1,並通過插件支持v1.0

3.3. 消息、交換機和隊列

  • 3.3.1. 代理基於一個被稱為交換機(exchange)的概念實現了一個消息傳遞模型,它為創建消息傳遞拓撲提供了一種靈活的機制

  • 3.3.2. 交換是對接收生產者消息並傳遞給代理隊列的過程的一種抽象

  • 3.3.3. 直連交換機通常用於根據匹配路由鍵將每條消息傳遞到一個目標隊列

3.4. 分發和併發

  • 3.4.1. 通道不是線程安全的,這意味著每個線程都需要對通道進行獨占訪問

  • 3.4.2. 線程的生命周期和調用由伺服器平臺控制,而不是由你的代碼控制

  • 3.4.3. 輪詢效率很低,因為它涉及繁忙的等待,即使沒有消息可用,也要求消費者不斷詢問消息

  • 3.4.3.1. 高性能系統中不會使用這種方法

  • 3.4.4. 推送模型

3.5. 與大多數消息代理一樣,RabbitMQ在消費速率跟生產速率相當時表現最佳

  • 3.5.1. 當隊列增長到大約有數萬條消息時,管理隊列的線程將承受更多的開銷

  • 3.5.2. 預設情況下,代理使用運行節點40%的可用記憶體

3.6. 數據安全與性能權衡

  • 3.6.1. 所有消息傳遞系統都面臨著性能與可靠性權衡的兩難境地

  • 3.6.2. 核心問題是消息傳遞的可靠性,通常稱為數據安全

3.7. 可用性與性能權衡

  • 3.7.1. 單個代理髮生故障屬於單點故障,因此如果代理崩潰或經歷短暫的網路故障,就會導致系統不可用

  • 3.7.2. 高可用性的典型解決方案是代理和隊列複製

  • 3.7.3. RabbitMQ提供了兩種支持高可用性的方法,分別是鏡像隊列和仲裁隊列

  • 3.7.3.1. 需要部署兩個或多個RabbitMQ代理並配置成一個集群

  • 3.7.3.2. 每個隊列都有一個領導者版本,以及一個或多個追隨者

  • 3.7.3.3. 發佈者向領導者發送消息,領導者負責將每條消息複製給追隨者

  • 3.7.3.4. 消費者也連接到領導者,當領導者收到消息成功處理的應答時,消息也會從追隨者中刪除

  • 3.7.3.5. 由於所有發佈者和消費者的隊列行為都由領導者執行,仲裁隊列和鏡像隊列雖然都提升了可用性,但不支持負載均衡

>  3.7.3.5.1. 消息吞吐量受到領導者副本的性能限制
  • 3.7.3.6. 關鍵的區別在於如何複製消息,以及在領導者發生故障的情況下如何選擇新的領導者
>  3.7.3.6.1. 仲裁本質上意味著超過半數

>  3.7.3.6.2. 如果有五個隊列副本,那麼至少需要三個副本(領導者和兩個追隨者)來持久保存新發佈的消息

>  3.7.3.6.3. 仲裁隊列實現了RAFT演算法以便管理副本,併在領導者不可用時選擇新的領導者

>  3.7.3.6.4. 仲裁隊列必須是持久性的,因此主要適用於數據安全性和可用性優先於性能的用例

  >   3.7.3.6.4.1. 在故障處理方面,它比鏡像隊列的實現更有優勢

4. 消息傳遞模式

4.1. 競爭消費者

  • 4.1.1. 消息傳遞系統的一個常見需求是儘可能快地消費隊列中的消息

4.2. 可用性

  • 4.2.1. 如果一個消費者發生故障,系統仍然可用,這個消費者的消息份額只是簡單地分發給其他競爭消費者

4.3. 故障處理

  • 4.3.1. 如果一個消費者發生故障,它未確認的消息將傳遞給另一個隊列消費者

4.4. 動態負載均衡

  • 4.4.1. 新的消費者可以在高負載期間啟動併在負載減少時停止,而無須更改任何隊列或消費者配置

4.5. 嚴格遵守一次處理原則

  • 4.5.1. 在非同步消息傳遞系統中,重覆處理消息來源於兩個問題

  • 4.5.1.1. 第一個是來自發佈者的重覆發佈

>  4.5.1.1.1. 一些消息代理提供了對這種重覆檢測的支持,從而確保重覆的消息不會被髮布到隊列中

>  4.5.1.1.2. 利用每條消息在客戶端生成的唯一冪等鍵值

  >   4.5.1.1.2.1. 發佈者只需要將特定的消息屬性設置為唯一值

>  4.5.1.1.3. 代理利用緩存來存儲冪等鍵值並檢測重覆項,有效地消除了隊列中的重覆消息,解決了第一個問題

>  4.5.1.1.4. 在消費者端,代理將消息傳遞給消費者後,消費者對消息進行了處理,但之後無法發送應答(消費者崩潰或網路丟失應答)​,就會發生重覆給消費者傳遞消息的情況
  • 4.5.1.2. 第二個是消費者多次消費
>  4.5.1.2.1. 消費者有義務防止重覆處理

>  4.5.1.2.2. 為已處理的消息維護一個緩存或冪等鍵值資料庫

>  4.5.1.2.3. 大多數代理將設置一個消息頭,指示消息是否為重新傳遞

  >   4.5.1.2.3.1. 消費者可以用它來實現冪等性

  >   4.5.1.2.3.2. 它不能保證消費者已經處理了該消息

  >   4.5.1.2.3.3. 它只是告訴你代理已傳遞過該消息並且消息仍未得到應答
  • 4.5.1.3. 兩者都需要解決,以確保每條消息都只處理一次

4.6. 有害消息

  • 4.6.1. 最常見的可能是生產者發送了錯誤的消息,消費者無法處理

  • 4.6.2. 導致消費者崩潰

  • 4.6.2.1. 在研發和測試系統中最為常見

  • 4.6.2.2. 有時這些問題也會流入生產環境,而消費者發生故障肯定會導致一些嚴重的運營難題

  • 4.6.3. 導致消費者拒絕消息,因為它無法成功處理消息負載

  • 4.6.4. 有害消息將被傳遞給另一個消費者,會得到可預測的、不良結果

  • 4.6.4.1. 如果沒辦法檢測到有害消息,則會無限期地傳遞它們

  • 4.6.4.2. 最好的結果是只占用處理能力,減少系統吞吐量

  • 4.6.5. 有害消息處理的方案是限制重新傳遞消息的次數

  • 4.6.5.1. 當達到重新傳遞的限制時,消息會自動轉移到一個收集問題請求的隊列

>  4.6.5.1.1. 這個隊列在傳統上被稱為死信隊列
  • 4.6.6. 每個消息傳遞平臺實現有害消息處理的確切機制都有所不同

  • 4.6.7. 有害消息處理的最後一部分是診斷出消息被重定向到死信隊列的原因

  • 4.6.8. 最重要的是你需要設置某種形式的監視警報給工程師發送消息處理失敗的通知


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. Redis 1.1. 2009年首次發佈 1.1.1. 更註重原始性能和簡單性,而不是數據安全性和一致性 1.2. 主要吸引力在於它能夠同時充當分散式緩存和數據存儲 1.3. 維護一個記憶體中的數據存儲,也稱為數據結構存儲(data structure store) 1.4. 配置Redis將每 ...
  • 大家好,我是湯師爺~ 今天聊聊SaaS業務架構的業務能力分析。 業務能力概述 簡單來說,業務能力是企業“做某事的能力”。 業務能力描述了企業當前和未來應對挑戰的能力,即企業能做什麼或需要做什麼。業務能力建模的關鍵在於定義了企業做什麼,而不是如何做(由業務流程描述)。 以人才招聘為例,大多數公司都需要 ...
  • 1. 強一致性 1.1. 最終一致資料庫通過跨多台機器分區和複製數據集來獲得可擴展性,其代價是要跨副本維持強數據一致性以及允許衝突寫入 1.1.1. 在更新數據對象後,不同的客戶端可能會看到該對象的舊值或新值,直到所有副本都收斂到最新值 1.2. 另一類分散式資料庫提供一種可替代的模型,即強一致性數 ...
  • 1. 最終一致性 1.1. 在一些應用領域,通常談論的是銀行和金融行業,最終一致性根本不合適 1.2. 事實上,最終一致性在銀行業已經使用了很多年 1.2.1. 支票需要幾天時間才能在你的賬戶上進行核對,而且你可以輕鬆地開出比賬戶餘額多的支票 1.2.2. 當處理檢查並建立一致性後,你才能看到一些後 ...
  • 大家好,我是湯師爺~ 今天聊聊SaaS架構中的流程架構分析。 業務流程的概念 業務流程是企業為實現目標而制定的一套系統化的工作方法。它由一系列有序的業務活動組成,按照既定規則將資源(輸入)轉化為有價值的結果(輸出)。這一過程需結合企業的具體情況和可用資源,旨在為客戶創造價值,同時達成企業目標。 通過 ...
  • 1. 可擴展資料庫基礎 1.1. 絕大多數應用程式都是基於關係資料庫技術構建的 1.2. 資料庫必須存儲大量數據,為分佈在全球的客戶端提供快速的查詢響應,並且全天候可用 1.3. NoSQL資料庫採用簡單的數據模型,可以複製和分區以支持海量數據集和請求量 1.4. Facebook以使用MySQL管 ...
  • 1. 微服務 1.1. 微服務的起源可以追溯到2008年左右 1.1.1. 在Amazon,​“兩個比薩原則”成為一個單系統組件團隊規模的管理原則,後來被稱為微服務 1.1.1.1. 每個內部團隊都應該小到可以用兩個比薩餅喂飽 1.1.2. Amazon和Netflix是微服務架構的先驅,他們在20 ...
  • 1. 無伺服器的魅力 1.1. 對於某些應用程式,負載在工作時間可能很高,而在非工作時間可能很低或者不存在 1.2. 其他應用程式後臺流量可能在99%的時間里都很低 1.2.1. 一旦到了一些大型節目的門票發佈時間,負載需求可能會在數小時內飆升至平均水平的10000倍,然後回落至正常水平 1.3.  ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...