封裝RabbitMQ.NET Library 的一點經驗總結

這篇文章內容會很短,主要是想給你們分享下我最近在作一個簡單的rabbitmq客戶端類庫的封裝的經驗總結,說是簡單其實一點都不簡單。爲了節省時間我主要按照Library的執行順序來介紹,在你看來這裏僅僅是一個簡單的經驗總結,可是在我看來這些經驗只有在你真正的封裝rabbitmq客戶端庫的時候且將你的客戶端安全穩定的發佈上線後纔會真的發現這些問題。html

好比你的庫只是連接單個Node的時候和連接高可用集羣的HAProxy時候是徹底兩回事。當你未能在你的庫裏使用反向注入LOG接口的時候一旦在線上發生網絡解析和序列化等一系列在線問題時候你是多麼無能爲力。當你使用同步循環獲取隊列消息的時候一旦發生異常你的連接就會斷掉等等這些細節。我總結了我在編寫這個library的時候慢慢穩定下來的過程和經驗。至少目前來看網絡上的文章,固然我是指.NET/C#方面的,都沒有講到這些問題,大部分的文章都是簡單的介紹了一個最最基本的使用和最最基本的demo而已,達不到企業級使用的要求。在這個過程當中,感謝個人團隊和給過我指導的同事,讓我明白了一些技術道理。git

好東西不能石沉大海,尤爲是.NET領域更須要這樣的東西來填補這一空缺。廢話很少說了,進入主題,那些編寫框架和組件的大道理這裏就不講了,我只說重點。github

1.發送連接、通道和接受連接、通道要關注點分離

就是說你的接受Channel和發送的Channel要分離開,若是不分開會出現偶發性的消息串掉的錯誤,我這裏如今沒有環境沒法重現截圖。我是在作壓力測試的時候,用了一個Channel的時候Debug拋出來的異常。若是你有潔癖建議把IConnection也分離開。這樣不容易出錯,就算出錯排錯也會很容易。安全

(圖1:分開接受和發送的IConnection、Channel)服務器

還有一點,不要將這些對象直接散落在直接使用的Client類中,要創建起一個使用上下文,就算你暴露在外面的是一個具體的類可是那個類也是一個空殼子。網絡

2.客戶端發送消息的時候要標記上消息的持久化狀態

咱們能夠在建立隊列的時候設置此隊列是持久化的,可是隊列中的消息要在咱們發送某個消息的時候打上須要持久化的狀態標記。多線程

(圖2:標記此消息是須要持久化的)架構

3.要在監聽的線程入口後加try{}catch{}

(圖1:在線程內部方法中加try{}catch{})框架

這個點不少作封裝的人會容易忽視掉,我這裏補充下爲了保持這個文章的完整性。測試

其實在我以前的「.NET應用架構設計—服務端開發多線程使用小結(多線程使用常識)」一文中有講到過。

這個時候你的try{}catch{}實際上是不會捕獲到任何ListenInit方法中的異常的,由於他在另一個線程上下文中執行的。具體原理這裏就不解釋了。可是能夠很容易的理解就是,你這個方法一旦執行就會立馬返回了。

4. 初始化的監聽鏈接的時候要訂閱Shutdown事件記錄下LOG

(圖4:監聽Shutdown事件,記錄下LOG便於排查和監管服務的穩定性)

5. 要在內部定義一個LOG反向注入接口

(圖5:組件內部的LOG接口)

此接口就是你內部用來將信息傳輸出去的渠道,並且這個渠道是活的,有各個應用系統決定怎麼記錄。

簡單處理你還須要一個LOG接口服務定位器對象,要否則你拿不到這個接口實例。

(圖6:LOG location對象)

6. 千萬不要使用while(true)接受消息

若是咱們是使用死循環的方式在接受消息,那麼一旦當你的接受消息的程序出現異常那麼你的while直接就會跳出,你的連接多是還連接在服務器上可是你的channel已經斷開,說白了你的消息是不會接受到的,並且這樣的開發方法很不穩定也不優雅。咱們可使用面向事件的消費者來接受消息。

(圖7:使用Eventing類型的消費者接受消息)

7.設置一次只接受一個消息,而不是直接LOCK住全部的隊列消息

默認狀況下,一個隊列裏無論多少消息當你一個TCP鏈接打上去以後會LOCK住全部的消息,也就是說一個鏈接完全佔用了全部的消息,此時消息不會被其餘集羣的機器消費。

(圖8:一次只取一個消息進行消費)

可是若是你對消息的處理的先後順序有要求就不能這麼作,你須要獨立註冊一個隊列,而後將這樣的一此只消費一個消息配置話。

8.自動從新鏈接,不須要手動處理自動鏈接

(圖9:建立出一個會自動重連的Connection對象)

9.心跳超時時間(集羣、高可用部署時相當重要的設置)

(圖10:設置心跳超時時間)

若是你鏈接單臺節點的時候不設置這個值是沒問題的,可是若是你鏈接的是相似HAProxy虛擬節點的時候就會出現TCP被斷開的可能性。若是你不設置這個心跳超時時間,它默認是不進行心跳保持的,就會出現網絡中的某個設置斷開空閒的TCP鏈接資源。就這個問題一直搞的咱們的團隊到次日兩點鐘。你們要記住這個點。

10.消費失敗的消息要從新放入隊列

(圖11:從新放入隊列,推送給其餘消費着)

總結:

最後,我是基於Rabbitmq.Client 版本3.5.3.0的基礎上開發的,這個你們要注意。版本不同會有必定的差別性。但願此文對你們在使用rabbitmq的同志有一點幫助,謝謝。

github地址:https://github.com/Plen-wang/rabbitmqclient

 

相關文章
相關標籤/搜索