本文歡迎轉載,實屬原創,本文原始連接地址:http://www.cnblogs.com/DjlNet/p/7603554.htmlhtml
既然都是廢話了,因此你們就能夠跳過了,這裏是博主有事沒事兒的一點瞎說哈,國慶節+中秋節一共8天,有些人回家了,有些人堵在路上了,有些人可能還要加班或者值班,233333,博主這裏還好是沒有加班通常也不須要值班,可能偶爾須要的時候遠程瞅瞅就行。相信不少小夥伴,在放假前夕都作好了要去哪裏玩,要去哪裏吃,要怎麼過好節假日,固然也有要看書的,有假期學習計劃,有鍛鍊身體的,說說本身吧,博主算是綜合性了,餐了聚了、黑也開了、電影也看了、書還沒看、計劃學習擱置+延期了、身體也沒啥鍛鍊、劇卻是跟進了一些,看到這裏是否是以爲博主的生活是否是冥冥之中在哪裏見過,對,是的,多多少少量多人都「中招」了(固然了每一個人有本身的理解和生活方式,沒有人能夠批判誰對誰錯,因此,沒有對錯,只有利弊!!!),說着說着博主放下了手中的「屠刀」,陷入了思考,想着不遠千里啊,爲了啥,還不仍是爲了將來,正當博主思考之際,電話響了起來,外賣:帥哥,您的外賣到了,請麻煩下來拿一下!!!,一個叫阿龍的人,內心若有所思的走下樓拿了外賣回到了電腦前面,打開了S7世界賽的畫面津津有味的看起來直播.......以上言語,純屬瞎扯,若有雷同,那也只能這樣了,哈哈!!!sql
再說此框架以前吶,有些前提概念或者知識須要瞭解一下的,念與博主自己這方面知識也有所不足(須要理解充電),因此部分知識只限於提供連接地址和部分理解所悟(可能後面單獨出文再加以敘述說明吧),因此園友如若發現不當之處,可盡情提出出來一塊兒談論即是,因爲園內不少次框架相關文章,可是或多或少都顯得有些零散或者是入門系列不過是咱們做爲參考的輔助資料,博主將會集中式整理一些方便查閱,固然此篇文章或許有些入門知識可是更着重的是劃出博主認爲須要注意的重點項,大體梳理順序邏輯,仍是按照前提概念知識補充、框架文檔與實踐、劃重點與問題探究....接下來咱們一步一步的扒光式的來學習....數據庫
在此以前多多少少就知道一些關於消息隊列方面的東西,博主先前的時候就作過一些MSMQ+WCF的項目實踐,不過吶這種組合在當前的技術流就顯得力不從心,一方面吶部署環境的受限,運維大兄弟對Linux更加的駕輕就熟,再者就是這種組合自己的侷限性和開發的坑略多了些,那麼基於當前的來作消息交互、解耦、限流或者削鋒等一般狀況下選擇無非就是,當前使用較多的消息隊列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,而部分數據庫如Redis、Mysql以及phxsql也可實現消息隊列的功能。因爲咱們主要基於RabbitMQ上面來作說明和研究使用( .NET社區一般的選擇也是目前博主公司的選擇,因此得先從這下手知其一而百通,哈哈 ),其餘狀況這裏博主找到一篇好文: https://cloud.tencent.com/community/article/129032 消息隊列及常見消息隊列介紹 ,文中關於消息隊列的使用場景和各自的優缺點對比說明都有必定的說明,你們能夠跳過去看看,而且文中結尾還有些各自MQ的參考學習連接,也能夠做爲學習途徑......編程
這裏博主以爲仍是有必要備註一下(引用來自於上文連接):消息隊列在實際應用中包括以下四個場景(連接中對每一個場景有舉例分析,可參考):
應用耦合:多應用間經過消息隊列對同一消息進行處理,避免調用接口失敗致使整個過程失敗;
異步處理:多應用對消息隊列中同一消息進行處理,應用間併發處理消息,相比串行處理,減小處理時間;
限流削峯:普遍應用於秒殺或搶購活動中,避免流量過大致使應用系統掛掉的狀況;
消息驅動的系統:系統分爲消息隊列、消息生產者、消息消費者,生產者負責產生消息,消費者(可能有多個)負責對消息進行處理;安全
從官網https://www.rabbitmq.com咱們能夠得知,它已經走過了10個年頭了,是一個在AMQPhttp://www.amqp.org/(高級消息隊列協議)基礎上完成的,可複用的企業消息系統,是當前最主流的消息中間件之一。服務器
這裏說明一下RabbitMQ主要特性:
可靠性: 提供了多種技術可讓你在性能和可靠性之間進行權衡。這些技術包括持久性機制、投遞確認、發佈者證明和高可用性機制;
靈活的路由: 消息在到達隊列前是經過交換機進行路由的。RabbitMQ爲典型的路由邏輯提供了多種內置交換機類型。若是你有更復雜的路由需求,能夠將這些交換機組合起來使用,你甚至能夠實現本身的交換機類型,而且當作RabbitMQ的插件來使用;
消息集羣:在相同局域網中的多個RabbitMQ服務器能夠聚合在一塊兒,做爲一個獨立的邏輯代理來使用;
隊列高可用:隊列能夠在集羣中的機器上進行鏡像,以確保在硬件問題下還保證消息安全;
多種協議的支持:支持多種消息隊列協議;
服務器端用Erlang語言編寫,支持只要是你能想到的全部編程語言;
管理界面: RabbitMQ有一個易用的用戶界面,使得用戶能夠監控和管理消息Broker的許多方面;
跟蹤機制:若是消息異常,RabbitMQ提供消息跟蹤機制,使用者能夠找出發生了什麼;
插件機制:提供了許多插件,來從多方面進行擴展,也能夠編寫本身的插件;
使用RabbitMQ須要:ErLang語言包RabbitMQ安裝包
RabbitMQ能夠運行在Erlang語言所支持的平臺之上:Solaris BSD 、Linux、 MacOSX 、TRU64 、Windows NT/2000/XP/Vista/Windows 7/Windows 八、
Windows Server 2003/2008/20十二、Windows 95, 9八、VxWorks
優勢:
一、因爲erlang語言的特性,mq 性能較好,高併發;
二、健壯、穩定、易用、跨平臺、支持多種語言、文檔齊全;
三、有消息確認機制和持久化機制,可靠性高;
四、高度可定製的路由;管理界面較豐富,在互聯網公司也有較大規模的應用;
五、社區活躍度高;
缺點:
一、儘管結合erlang語言自己的併發優點,性能較好,可是不利於作二次開發和維護;
二、實現了代理架構,意味着消息在發送到客戶端以前能夠在中央節點上排隊。此特性使得RabbitMQ易於使用和部署,可是使得其運行速度較慢,由於中央節點增長了延遲,消息封裝後也比較大;
三、須要學習比較複雜的接口和協議,學習和維護成本較高;
參考連接地址:
RabbitMQ主頁 https://www.rabbitmq.com/
RabbitMQ學習教程 https://www.rabbitmq.com/getstarted.html
專欄:RabbitMQ從入門到精通 http://blog.csdn.net/column/details/rabbitmq.html
RabbitMQ能爲你作些什麼 http://rabbitmq.mr-ping.com/description.html
RabbitMQ指南(1)-特性及功能 https://blog.zenfery.cc/archives/79.html
以上總結來自於連接地址:https://cloud.tencent.com/community/article/129032 因此僅供參考學習網絡
固然這裏博主就選取一些值得借鑑參考的博文來記錄與備份,例如什麼安裝介紹基本使用集羣經驗總結一類的文章:
http://www.cnblogs.com/liqingwen/p/6412089.html [.NET] RabbitMQ 的行爲藝術,此文介紹了RabbitMQ大體組織結構成分職責說明,以及環境搭建梳理和HelloWord、交換機的基本說明,居介紹性質多一些
http://www.cnblogs.com/sheng-jie/p/7192690.html RabbitMQ知多少 ,該文從基本介紹到環境搭建以及後續每一個功能點說明,文章排版閱讀友好性強,居實踐功能點多一些
http://www.cnblogs.com/zhangweizhong/category/855479.html RabbitMQ學習系列文,系列文從介紹到基本使用,以及後面的集羣高階使用,算是一個由淺入深的系列好文
http://www.cnblogs.com/wangiqngpei557/p/6158094.html RabbitMQ 高可用集羣搭建及電商平臺使用經驗總結,從題目就能夠看出是題主在實踐項目中實戰得出經驗總結,想必是值得博主自己閱讀學習的
http://www.cnblogs.com/dongkuo/p/6001791.html 消息隊列——RabbitMQ學習筆記
http://www.cnblogs.com/panzi/p/6337568.html .NET操做RabbitMQ組件EasyNetQ使用中文簡版文檔
http://www.cnblogs.com/stulzq/p/7551819.html .NET Core 使用RabbitMQ
這裏博主列出閱讀過的此類文章,並非在說誰好誰壞,責在學習文中的寫得好的地方順便備份一下,對咱們理解開發有意義的地方是值得借鑑和學習的,同時咱們發如今文末留言中發現,園友在使用時存在多多少少量多問題,至此博主將會以身試法般的帶着文檔去實踐,畢竟實踐是檢驗理論的惟一標準.....架構
這裏可能有人要問了,爲何不使用官方的nuget包吶:RabbitMQ.Client(官方還在積極對.net core作升級去兼容.net standrad,這挺好,https://www.nuget.org/packages/RabbitMQ.Client/5.1.0-pre1),要說爲何,其實無非就是原始的官方包你說要用吧也能夠用,就是須要學習成本,讓小組成員都要熟悉API又是一番功夫且低級API方法不是那麼通俗易懂,固然拉有能力的固然能夠藉助官方包二次封裝以適應本身項目或者Team的需求,前提是對交互機制和對原始API有較爲全面的瞭解,因此綜上所說吶,在社區的支持下提供了 框架:EasyNetQ,從其名即可以知道,方便了咱們使用高階API的同時,依然保留了對原始高級功能點的訪問,因此這也體現框架做者的對框架的理解也基本上足夠咱們當前的使用需求了,固然了此框架自己也是依賴於 RabbitMQ.Client 的也是一個二次封裝的結果,因此吶博主選取它做爲學習或者項目集成方面,都不愧是一個不錯的選擇!相信使用過的老鐵,都知道它的好,但願做者延續出core的版本吧.....同時博主不但願只僅僅是簡單的跟着文檔滾一邊,並且想以一種正確優雅的姿式把此消息隊列框架集成在系統當中,且巧妙的設計以及避開一些坑,實如今業務與消息之間微妙的關係(例如經過事件總線來統籌,MQ消息來傳遞),同時保證消息交互一個不穩定的狀況下,如何實現儘量的消息落地與確保,這也是當今面對分佈式事務的一種婉轉但不失優雅的解決方案.....併發
這裏是博主認爲有必需要視爲重點且須要實驗驗證的點,如若沒有說起的地方,能夠提出來一塊兒討論學習框架
一、發佈者確認(Publisher Confirms):簡而言之就是確保消息的成功投遞,通俗的講就是我要知道,我投遞的消息到底有木有成功被接受。鏈接字符增長 publisherConfirms=true;
便可,這裏博主建議不要爲了那麼一丟丟的確認性能的考慮而放棄發送消息確認配置,同時爲了保證消息的投遞成功,RabbitMQ也推薦使用該方式由於沒有實現事務方式,且發送消息以後無論是同步方法(Publish)仍是異步方法(PublishAsync)在自身內部都會在超時還沒到的時間段內,一直等待消息確認接收的反饋訊息,再而後同步方法纔會返回,異步方法也會返回一個完成狀態的Task對象,固然可能由於網絡或者MQServer服務宕機等一系列問題致使同步異常爆發或者異步返回異常的Task對象,因此還須要對後續異常狀況處理和日誌記錄機制的的實施,至此這種發佈者確認帶來的消息推送保障對於咱們的系統來講很重要,關乎到系統交互的責任歸屬問題(例如:你說你投遞成功了,我咋知道你投遞成功了沒有,我這裏沒收到啊,這樣比較搞笑的對話了)
這裏補充說明一點就是,平常開發中博主見過的消息推送目前的兩種方式:
a、要求消息的發送與業務邏輯耦合在一個數據庫的事務做用域當中,且消息發送須要放在業務邏輯的最後面(你懂的),這樣就造成了一個利用數據庫層面的強制原子操做,包含消息發送日誌記錄看成證據,達到消息和業務綁定關係爲同生共死「要麼都成功,要麼都失敗」,好處:實現了邏輯的一致性以及消息的及時發送,能夠知足某些特殊需求,壞處:消息發送須要遠程服務器交互(內網或者外網)須要等待耗時且必定程度拉低了系統處理能力受MQ消息服務器的影響,而且發送失敗會致使業務處理失敗浪費了前期邏輯處理,因此也不存在消息的重試機制了,直接從新操做業務邏輯就能夠重試發送了;固然依然須要異常處理與日誌記錄
b、將業務邏輯產生的消息歸檔到一個等待發送消息DB(Table)中作持久化處理,而後經過定時器框架配合處理,輪詢取出必定數量應該發送的消息(這裏包括沒發送成功須要重試的消息,一直懟)到MQServer中成功無異常後重置消息的發送標記位flag=true,重試消息的話RetryCount++,這裏固然也是在一個DB事務當中且消息發送依然在尾部邏輯(你懂的),好處:消息發送與業務邏輯分離,職責劃分明確增長了系統各自部分的穩定性不受消息服務影響,相互獨立不受牽制,且已經具有了消息發送日誌記錄(前面說的等待發送消息持久化證實)做爲證據,壞處:消息發送具備必定得延遲性也就是定時器的間隔時間,同理這方式依然須要異常處理與日誌記錄
固然以上兩種方式都是基於額外數據庫事務支持的狀況下(加上PublisherConfirms共同保證消息落地性),至於選擇何種方式或者是說怎麼樣來靈活的組合使用,來應對系統消息發佈的場景,看上面的解釋也能大體有數了吧,其實也須要根據開發時的業務場景、網絡、服務器資源等等綜合考慮,不過通常狀況博主推薦使用方式b便可,通常通常通常狀況下對於消息的及時性要求不高,控制在必定的忍耐程度就好了,也是目前博主採起的方式來操做,不過得注意得時相關與網絡傳輸交互都須要異常處理和日誌記錄來作問題得檢查和恢復得支撐,至於上面兩種方式的代碼集成就比較明顯了,畢竟思路明確了,博主這裏打算後面框架集成部分給出參考吧。
二、prefetchcount:在RabbitMQServer獲取Consumer消費者反饋的ack(確認消費標誌)以前,RabbitMQ服務可以分發消息給消費者的最大值,鏈接字符串配置:prefetchcount=50;
,默認是50,且這些消息處於內存隊列中處於準備狀態,從控制檯界面查看就是(注意紅框處就是設置值,這裏博主測試設置了爲:prefetchcount=5;,而後故意讓消費者延遲反饋ack確認消息回執)
測試代碼以下:
IBus bus = RabbitHutch.CreateBus("host=localhost;virtualHost=/;username=yourname;password=yourpassword;publisherConfirms=true;timeout=10;prefetchcount=5"); bus.Subscribe<MyClass>(string.Empty, x => { Console.WriteLine(x.Text); Task.Delay(TimeSpan.FromSeconds(5)).Wait(); });
固然這個配置是做用於消費者,那麼這裏每一個消費者能夠自定義該配置來覆蓋鏈接字符串中的全局配置,來達到控制個別消費者的細粒度,參考以下代碼與效果圖
,設置0表示不限制能夠無限發送消息(不推薦),設置1表示消費者以公平方式接受消息(多個消費者共享一個隊列的時候,消費順序按照訂閱而定),其實說白了,這個值的設定是要看消息接收方處理能力而定的,因此具體生成環境看狀況而定吧,採用默認設置也能夠。
三、Ack:表示訂閱者接受並處理消息以後回執。
例如:一個訂閱了MyMessage的訂閱者,若是程序崩潰會發生什麼?爲了提升效率,EasyNetQ實現了一個用於訂閱的內部內存隊列。消息經過網絡從RabbitMQ接收並放置在此隊列上。單個訂閱線程依次將消息從隊列中取出,並將它們傳遞給您提供的回調。一旦回調完成,EasyNetQ將發送一個「Ack」回RabbitMQ。在收到「Ack」以前,消息不會從RabbitMQ隊列中刪除。若是您的服務在處理消息時停止,尚未Ack的回傳,消息(以及EasyNetQ內存中隊列中的全部消息)將保留在RabbitMQ隊列中,一旦您的服務從新鏈接,消息將被從新發送,從上而知也知道ACK的做用和意義。
固然消費消息的時候發生異常:若是您的訂閱回調引起EasyNetQException異常,EasyNetQ將會收到正在消費的消息,並將其包裝在特殊的錯誤消息中。錯誤消息將被髮布到EasyNetQ錯誤隊列(名爲EasyNetQ_Default_Error_Queue)。您應該監視任何消息的錯誤隊列。錯誤消息包括從新發布原始消息以及異常類型,消息和堆棧跟蹤所需的全部信息。您可使用EasyNetQ.Hosepipe實用程序從新發布錯誤消息。請參閱下面的EasyNetQ.Hosepipe部分。
這裏默認EasyNetQ已經幫咱們作好了消息處理的部分邏輯,包括異常處理和消息ACK回執,
那麼咱們在生產環境如何保證消費消息作到儘量消息100%落地?
這裏博主的大體解決辦法描述以下:這裏消息體的格式協定以及消息基本驗證什麼的,再也不討論方法之類,就如同API方法參考校驗一個性質,這裏相信大部分訂閱者處理消息都參與了數據庫邏輯,因此這裏博主就必須把傳遞過來的消息持久化到數據庫中當作消費證實,固然這裏又能夠使用數據庫的ACID的事務機制來包裹消息日記錄ConsumerLog以及以前的一些業務邏輯數據庫寫操做或者其餘Web請求邏輯,固然可能會因爲網絡請求或者數據庫自己的問題出現爆發異常,致使事務回滾(業務邏輯同時消費消息日誌記錄失敗,這種就是除自己邏輯異常以外的不可控的異常爆發),那麼這種還須要進一步保證消息落地怎麼辦吶?回答:沒有百分百的保證,首先仍是再一次的向數據庫或者NoSql再次寫入消息,不過這裏是寫入異常消費失敗的消息ConsumerErrorLog(那麼就須要定時器消息重試消費邏輯的機制),若是上述仍是不行(由於這裏還可能仍是失敗)就須要文本日誌來記錄Message消息體作進一步保證了,其次就是Log記錄異常緣由,最最後我還能夠利用上述EasyNetQ提供了EasyNetQException異常機制將消費失敗的消息進一步在EasyNetQ錯誤隊列(名爲EasyNetQ_Default_Error_Queue)也保留一份存檔方便對照查閱,到這裏相信基本上可以儘量保證消息消費的正確姿式了,固然上述思路可能依然並非最合適的,最好是結合本身的狀況進一步定製化本身的消息處理框架吧。
首先須要說明的是未完待續(發現一篇文還不夠說明所有,不出意外近期更新,哈哈),後面做進一步更新,更新內容可能依然來源於文檔劃重點部分,固然園友也能夠說一下注意點和須要試驗證實的,或者關於消息隊列的一些思考和想法。而後大體總結一下上面的內容,咱們從背景介紹與使用場景的說明,到當前主流的消息隊列介紹和對比,而後選取了熱門的RabbitMQ作了進一步的介紹和評比,再者這裏也方便本身查閱收錄一些當前園中的一些相關文章連接地址,再而後直接經過文檔與在使用時比較關心的幾個問題作了說明和可行性實驗的研究,框架文檔基本過了一兩遍了,大體使用與集成博主大體心中有底,畢竟是在站人家的肩膀搞事情。固然就算是基於框架也能夠有考慮的遺留項,因此咱們儘量瞭解RabbitMQ自身的一些原理和對原始Rabbit.Client API有必定了解確定是更加對集成有好處的.....
最後吶,可能此文前部分有些「敷衍」或者「老酒新裝」之意,畢竟瞭解這瓶「老酒」確定是須要些時日才能品出味道的吶,可是博主以爲就算是吧,也是對本身知識的多一層熟悉和鋪墊吧,固然博主是打破砂鍋問到底的那種,在問題上比較糾結,想弄清楚何爲正確姿式!!因此上面的理解基本都是基於博主自己的思考與實驗,可能略顯不對,但凡請指出討論,在此感激涕零,哈哈哈,最最後,若是文章對您或許有那麼一丟丟的幫助,您的評論和點贊都是對博主很大的支持吶!!!O(∩_∩)O嗯!