日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > > 架構師社區(qū)
[導讀]關于RabbitMQ,你了解多少?

原文:https://sq.163yun.com/blog/article/229026816937607168
作者:Java大蝸牛
關于RabbitMQ
  • 出身:誕生于金融行業(yè)的消息隊列
  • 語言:Erlang
  • 協議:AMQP(Advanced Message Queuing Protocol 高級消息隊列協議)
  • 關鍵詞:內存隊列,高可用,一條消息

隊列結構

深入理解:RabbitMQ的前世今生
  • Producer/Consumer:生產者消費者
  • Exchange:交換器,可以理解為隊列的路由邏輯,交換器主要有三種,圖中是Direct交換器
  • Queue:隊列
  • Binding:綁定關系,實際是交換器上映射隊列的規(guī)則

發(fā)送和消費一條消息

在上圖的模式下,交換器的類型為Direct,偽代碼表示消息的生產和消費

消息生產

#消息發(fā)送方法
#messageBody?消息體
#exchangeName?交換器名稱
#routingKey?路由鍵
publishMsg(messageBody,exchangeName,routingKey){
?......
}
#消息發(fā)送
publishMsg("This?is?a?warning?log","exchange","log.warning");
深入理解:RabbitMQ的前世今生

RoutingKey=log.warning,和隊列A與交換器的綁定一致,所以消息被路由到了隊列A上。

消息消費

對于消息消費而言,消費者直接指定要消費的隊列即可,比如指定消費隊列A的數據。

需要注意的是,在消費者消費完成數據后,返回給RabbitMq ACK消息,RabbitMq會刪掉隊列中的該條信息。

深入理解:RabbitMQ的前世今生

多種消息路由模式

在Exchange這個模塊上,RabbitMq主要支持了Direct,Fanout,Topic三種路由模式,RabbitMq在路由模式上下功夫,也說明了他在設計上想要滿足多樣化的需求。

深入理解:RabbitMQ的前世今生

Direct和Fanout模式比較好理解,類似于單播和廣播模式,Topic模式比較有意思,它支持自定義匹配規(guī)則,按照規(guī)則把所有滿足條件的消息路由到指定隊列,能夠幫助開發(fā)者靈活應對各類需求。

消息的存儲

RabbitMQ的消息默認是在內存里的,實際上不光是消息,Exchange路由等信息實際都在內存中。內存的優(yōu)點是高性能,問題在于故障后無法恢復。所以RabbitMQ也支持持久化的存儲,也就是寫磁盤。

要在RabbitMQ中持久化消息,要同時滿足三個條件:

  1. 消息投體時使用持久化投遞模式
  2. 目標交換器是配置為持久化的
  3. 目標隊列是配置為持久化的

RabbitMQ持久化消息的方式是常見的寫日志方式:

  1. 當一條持久化消息發(fā)送到持久化的Exchange上時,RabbitMQ會在消息提交到日志文件后,才發(fā)送響應。
  2. 一旦這條消息被消費后,RabbitMQ會將會把日志中該條消息標記為等待垃圾收集,之后會從日志中清除。
  3. 如果出現故障,自動重建Exchange,Bindings和Queue,同時通過重播持久化日志來恢復消息。

消息持久化的優(yōu)缺點很明顯,擁有故障恢復能力的同時,也帶來了性能的急劇下降。同時,由于RabbitMQ默認情況下是沒有冗余的,假設一個持久化節(jié)點崩潰,一致到該節(jié)點恢復前,消息和隊列都無法恢復。

消息投遞模式

1.發(fā)后即忘

RabbitMQ默認發(fā)布消息是不會返回任何結果給生產者的,所以存在發(fā)送過程中丟失數據的風險。

2.AMQP事務

AMQP事務保證RabbitMQ不僅收到了消息,并成功將消息路由到了所有匹配的訂閱隊列,AMQP事務將使得生產者和RabbitMQ產生同步。

雖然事務使得生產者可以確定消息已經到達RabbitMQ中的對應隊列,但是卻會降低2~10倍的消息吞吐量。

3.發(fā)送方確認

開啟發(fā)送方確認模式后,消息會有一個唯一的ID,一旦消息被投遞給所有匹配的隊列后,會回調給發(fā)送方應用程序(包含消息的唯一ID),使得生產者知道消息已經安全到達隊列了。

如果消息和隊列是配置成了持久化,這個確認消息只會在隊列將消息寫入磁盤后才會返回。如果RabbitMQ內部發(fā)生了錯誤導致這條消息丟失,那么RabbitMQ會發(fā)送一條nack消息,當然我理解這個是不能保證的。

這種模式由于不存在事務回滾,同時整體仍然是一個異步過程,所以更加輕量級,對服務器性能的影響很小。

RabbitMQ RPC

一般的異步服務間,可能會用兩組隊列實現兩個服務模塊之前的異步通信,有趣的是RabbitMQ就內建了這個功能。

RabbitMQ支持消息應答功能,每個AMQP消息頭中有一個Reply_to字段,通過該字段指定消息返回到的隊列名稱(這是一個私有隊列)消息的生產者可以監(jiān)聽該字段對應的隊列。

深入理解:RabbitMQ的前世今生

RabbitMQ集群

RabbitMQ集群的設計目標:

  1. 允許消費者和生產者在RabbitMQ節(jié)點崩潰的情況下繼續(xù)運行
  2. 能過通過添加節(jié)點來線性擴展消息通信吞吐量

從實際結果看,RabbitMQ完成設計目標上并不十分出色,主要原因在于默認的模式下,RabbitMQ的隊列實例子只存在在一個節(jié)點上(雖然后續(xù)也支持了鏡像隊列),既不能保證該節(jié)點崩潰的情況下隊列還可以繼續(xù)運行,也不能線性擴展該隊列的吞吐量。

集群結構

RabbitMQ內部的元數據主要有:

  1. 隊列元數據-隊列名稱和屬性
  2. 交換器元數據-交換器名稱,類型和屬性
  3. 綁定元數據-路由信息

雖然RabbitMQ的隊列實際只會在一個節(jié)點上,但元數據可以存在各個節(jié)點上。舉個例子來說,當創(chuàng)建一個新的交換器時,RabbitMQ會把該信息同步到所有節(jié)點上,這個時候客戶端不管連接的那個RabbitMQ節(jié)點,都可以訪問到這個新的交換器,也就能找到交換器下的隊列。

深入理解:RabbitMQ的前世今生

如上圖所示,隊列A的實例實際只在一個RabbitMQ節(jié)點上,其它節(jié)點實際存儲的是只想該隊列的指針。

為什么RabbitMQ不在各個節(jié)點間做復制了,《RabbitMQ實戰(zhàn)》給出了兩個原因:

  1. 存儲成本-RabbitMQ作為內存隊列,復制對存儲空間的影響,畢竟內存是昂貴而有限的
  2. 性能損耗-發(fā)布消息需要將消息復制到所有節(jié)點,特別是對于持久化隊列而言,性能的影響會很大

我理解成本這個原因并不完全成立,復制并不一定要復制到所有節(jié)點,比如一個隊列可以只做兩個副本,復制帶來的內存成本可以交給使用方來評估,畢竟在內存中沒有堆積的情況下,實際上隊列是不會占用多大內存的。

還有一點是RabbitMQ本身并沒有保證消息消費的有序性,所以實際上隊列被Partition到各個節(jié)點上,這樣才能真正達到線性擴容的目的(以RabbitMQ的現狀來說,單隊列實際是無法擴容的,只有在業(yè)務層做切分)。

注:RabbitMQ集群中的節(jié)點可以是內存節(jié)點也可以是磁盤節(jié)點,但要求至少有一個磁盤節(jié)點,這樣出現故障時才能恢復數據。

鏡像隊列

鏡像隊列架構

RabbitMQ自己也考慮到了我們之前分析的單節(jié)點長時間故障無法恢復的問題,所以RabbitMQ 2.6.0之后它也支持了鏡像隊列,換個說法也就是副本。

深入理解:RabbitMQ的前世今生

除了發(fā)送消息,所有的操作實際都在主拷貝上,從拷貝實際只是個冷備(默認的情況下所有RabbitMQ節(jié)點上都會有鏡像隊列的拷貝),如果使用消息確認模式,RabbitMQ會在主拷貝和從拷貝都安全的接受到消息時才通知生產者。

從這個結構上來看,如果從拷貝的節(jié)點掛了,實際沒有任何影響,如果主拷貝掛了,那么會有一個從新選主的過程,這也是鏡像隊列的優(yōu)點,除非所有節(jié)點都掛了,才會導致消息丟失。重新選主后,RabbitMQ會給消費者一個消費者取消通知(Consumer Cancellation),讓消費者重連新的主拷貝。

鏡像隊列原理

1.RabbitMQ結構

深入理解:RabbitMQ的前世今生
  • AMQPQueue:負責AMQP協議相關的消息處理,包括接收消息,投遞消息,Confirm消息等
  • BackingQueue:提供AMQQueue調用的接口,完成消息的存儲和持久化工作

BackingQueue由Q1,Q2,Delta,Q3,Q4五個子隊列構成,在Backing中,消息的生命周期有四個狀態(tài):

  1. Alpha:消息的內容和消息索引都在RAM中。(Q1,Q4)
  2. Beta:消息的內容保存在Disk上,消息索引保存在RAM中。(Q2,Q3)
  3. Gamma:消息的內容保存在Disk上,消息索引在DISK和RAM上都有。(Q2,Q3)
  4. Delta:消息內容和索引都在Disk上。(Delta)

這里以持久化消息為例(可以看到非持久化消息的生命周期會簡單很多),從Q1到Q4,消息實際經歷了一個RAM->DISK->RAM這樣的過程,BackingQueue這么設計的目的有點類似于Linux的Swap,當隊列負載很高時,通過將部分消息放到磁盤上來節(jié)省內存空間,當負載降低時,消息又從磁盤回到內存中,讓整個隊列有很好的彈性。因此觸發(fā)消息流動的主要因素是:1.消息被消費;2.內存不足。

RabbitMQ會更具消息的傳輸速度來計算當前內存中允許保存的最大消息數量(Traget_RAM_Count),當:內存中保存的消息數量+等待ACK的消息數量>Target_RAM_Count時,RabbitMQ才會把消息寫到磁盤上,所以說雖然理論上消息會按照Q1->Q2->Delta->Q3->Q4的順序流動,但是并不是每條消息都會經歷所有的子隊列以及對應的生命周期。

從RabbitMQ的Backing Queue結構來看,當內部不足時,消息要經歷多個生命周期,在Disk和RAM之間置換,者實際會降低RabbitMQ的處理性能(后續(xù)的流控就是關聯的解決方法)。

2.鏡像隊列結構

深入理解:RabbitMQ的前世今生

所有對鏡像隊列主拷貝的操作,都會通過Guarented Multicasting(GM)同步到各個Salve節(jié)點,Coodinator負責組播結果的確認。

GM是一種可靠的組播通信協議,保證組組內的存活節(jié)點都收到消息。

深入理解:RabbitMQ的前世今生

GM的主播并不是由Master節(jié)點來負責通知所有Slave的(目的是為了避免Master壓力過大,同時避免Master失效導致消息無法最終Ack),RabbitMQ把一個鏡像隊列的所有節(jié)點組成一個鏈表,由主拷貝發(fā)起,由主拷貝最終確認通知到了所有的Slave,而中間由Slave接力的方式進行消息傳播。

從這個結構來看,消息完成整個鏡像隊列的同步耗時理論上是不低的,但是由于RabbitMQ消息的消息確認本身是異步的模式,所以整體的吞吐量并不會受到太大影響。

流控

當RabbitMQ出現內存(默認是0.4)或者磁盤資源達到閾值時,會觸發(fā)流控機制,阻塞Producer的Connection,讓生產者不能繼續(xù)發(fā)送消息,直到內存或者磁盤資源得到釋放。

RabbitMQ基于Erlang/OTP開發(fā),一個消息的生命周期中,會涉及多個進程間的轉發(fā),這些Erlang進程之間不共享內存,每個進程都有自己獨立的內存空間,如果沒有合適的流控機制,可能會導致某個進程占用內存過大,導致OOM。因此,要保證各個進程占用的內容在一個合理的范圍,RabbitMQ的流控采用了一種信用證機制(Credit),為每個進程維護了四類鍵值對:

  1. {credit_from,From}-該值表示還能向消息接收進程From發(fā)送多少條消息
  2. {credit_to,To}-表示當前進程再接收多少條消息,就要向消息發(fā)送進程增加Credit數量
  3. credit_blocked-表示當前進程被哪些進程block了,比如進程A向B發(fā)送消息,那么當A的進程字典中{credit_from,B}的值為0是,那么A的credit_blocked值為[B]
  4. credit_deferred-消息接收進程向消息發(fā)送進程增加Credit的消息列表,當進程被Block時會記錄消息信息,Unblock后依次發(fā)送這些消息
深入理解:RabbitMQ的前世今生

如圖所示,A進程當前可以發(fā)送給B的消息有100條,每發(fā)一次,值減1,直到為0,A才會被Block住。B消費消息后,會給A增加新的Credit,這樣A才可以持續(xù)的發(fā)送消息。這里只畫了兩個進程,多進程串聯的情況下,這中影響也就是從底向上傳遞的。

想學習Java工程化、分布式架構、高并發(fā)、高性能、深入淺出、微服務架構、Spring,MyBatis,Netty源碼分析等技術可以加群:479499375,群里有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給大家,歡迎進群一起深入交流學習。

總結

注:本文基于的RabbitMQ材料可能較為陳舊,新的RabbitMQ可能會有不同的功能特性

整體來看,RabbitMQ的功能比較豐富(可惜沒有看到延遲,優(yōu)先級等功能),更適用于偏實時的業(yè)務場景,與Kafka這樣的隊列定位上有明顯的區(qū)別。它本身應該是一個簡單健壯的組件,但如果要應用在一個大規(guī)模的分布式系統中,實際還是需要做一些外部的再次開發(fā),以解決我們前面提到的隊列存儲單點,流控等問題。直觀上看它的運維成本是會比較高的,需要使用方有一定的經驗。

特別推薦一個分享架構+算法的優(yōu)質內容,還沒關注的小伙伴,可以長按關注一下:

深入理解:RabbitMQ的前世今生

深入理解:RabbitMQ的前世今生

深入理解:RabbitMQ的前世今生

長按訂閱更多精彩▼

深入理解:RabbitMQ的前世今生

如有收獲,點個在看,誠摯感謝

免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯系該專欄作者,如若文章內容侵犯您的權益,請及時聯系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統 散熱

根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統,而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉

<label id="ml5pk"><ins id="ml5pk"></ins></label>
    <ol id="ml5pk"></ol>