<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      RabbitMQ真實(shí)生產(chǎn)故障問題還原與分析

      RabbitMQ生產(chǎn)故障問題分析

        由某一次真實(shí)生產(chǎn)環(huán)境rabbitMQ故障引發(fā)血案,下面復(fù)盤問題發(fā)生原因以及問題解決方法。

      1、    問題引發(fā)

        由某個(gè)服務(wù)BI-collector-xx隊(duì)列出現(xiàn)阻塞,影響很整個(gè)rabbitMQ集群服務(wù)不可用,多個(gè)應(yīng)用MQ生產(chǎn)者服務(wù)出現(xiàn)假死狀態(tài),系統(tǒng)影響面較廣,業(yè)務(wù)影響很大。當(dāng)時(shí)為了應(yīng)急處理,恢復(fù)系統(tǒng)可用,運(yùn)維相對粗暴的把一堆阻塞隊(duì)列信息清空,然后重啟整個(gè)集群。

      在復(fù)盤整個(gè)故障過程中,我心中有不少疑惑,至少存在以下幾個(gè)問題點(diǎn):

      1. 為什么出現(xiàn)隊(duì)列阻塞?
      2. 某個(gè)隊(duì)列出現(xiàn)阻塞為什么會影響到其他隊(duì)列的運(yùn)行(即多隊(duì)列間相互影響)?
      3. 某個(gè)應(yīng)用MQ隊(duì)列出現(xiàn)問題,為什么會導(dǎo)致應(yīng)用不可用呢?

       

      2、    試驗(yàn)隊(duì)列阻塞

      某天周末在家里,找個(gè)測試環(huán)境,安裝rabbitmq嘗試重現(xiàn)這過程,并做模擬測試。

      寫兩個(gè)測試應(yīng)用Demo(假設(shè)是兩個(gè)項(xiàng)目應(yīng)用)分別有生產(chǎn)者和消費(fèi)者,并分別使用隊(duì)列testA和testB。

      為了盡可能還原生產(chǎn)的情況,一開始測試使用了同一個(gè)vhost,后面分別設(shè)置不同vhost。

       

      生產(chǎn)者A,示例代碼如下

       

      消費(fèi)者A

       

      MQ配置

       

       

      生產(chǎn)者B,每次生產(chǎn)10萬條消息

       

      消費(fèi)者B,代碼故意寫錯(cuò)(模擬出現(xiàn)異常的情況),不是正常的json串導(dǎo)致解釋json時(shí)拋出異常

       

       

      先了解一下Rabbitmq客戶端啟動連接工作過程,通過wireshark抓包分析,如下

       

      先對AMQP做一個(gè)簡單的介紹,請求的AMQP協(xié)議方法信息,AMQP協(xié)議方法包含類名+方法名+參數(shù),這一列主要展示了類名和方法名

      • Connection.Start:請求服務(wù)端開始建立連接
      • Channel.Open請求服務(wù)端建立信道
      • Queue.Declare聲明隊(duì)列
      • Basic.Consume開始一個(gè)消費(fèi)者,請求指定隊(duì)列的消息

       

      詳細(xì)方法可以查看amqp官網(wǎng)https://www.rabbitmq.com/amqp-0-9-1-reference.html

       

      工作過程分析:

      Basic.Publish 客戶端發(fā)送Basic.Publish方法請求,將消息發(fā)布到exchangerabbitmq server會根據(jù)路由規(guī)則轉(zhuǎn)發(fā)到隊(duì)列中;

      Basic.Deliver 服務(wù)端發(fā)送Basic.Deliver方法請求,投遞消息到監(jiān)聽隊(duì)列的客戶端消費(fèi)者;

      Basic.Ack 客戶端發(fā)送Basic.Ack方法請求,告知rabbimq server,消息已接收處理。

       

      兩個(gè)應(yīng)用程序啟動后,通過rabbitmq管理控制臺可以觀察一些參數(shù)和監(jiān)控指標(biāo)

       

       

       

       

       

      一開始A應(yīng)用生產(chǎn)和消費(fèi)都是正常的。

      B消費(fèi)端錯(cuò)誤代碼異常,狂刷報(bào)錯(cuò)信息

       

       

       

       

       

      經(jīng)過大概30分鐘運(yùn)行,觀察A生產(chǎn)者應(yīng)用控制臺也有出現(xiàn)異常信息

       

       

      查看服務(wù)端連接狀態(tài)出現(xiàn)blocked情況,與生產(chǎn)故障發(fā)生情景很類似。

       

       

      此時(shí)客戶端即本機(jī)器,CPU和內(nèi)存上漲明顯,風(fēng)扇聲音很響,明顯卡頓,再過30分鐘應(yīng)用基本不可用狀態(tài)。

       

      分析原因

      上面錯(cuò)誤代碼展示了消費(fèi)者B無法ack,由于沒有進(jìn)行ack導(dǎo)致隊(duì)里阻塞。那么問題來了,這是為什么呢?其實(shí)這是RabbitMQ的一種保護(hù)機(jī)制。防止當(dāng)消息激增的時(shí)候,海量的消息進(jìn)入consumer而引發(fā)consumer宕機(jī)。

      ?RabbitMQ提供了一種QOS(服務(wù)質(zhì)量保證)功能,即在非自動確認(rèn)的消息的前提下,限制信道上的消費(fèi)者所能保持的最大未確認(rèn)的數(shù)量。可以通過設(shè)置prefetchCount實(shí)現(xiàn),自動確認(rèn)prefetchCount設(shè)置無效。

      舉例說明:可以理解為在consumer前面加了一個(gè)緩沖容器,容器能容納最大的消息數(shù)量就是PrefetchCount。如果容器沒有滿RabbitMQ就會將消息投遞到容器內(nèi),如果滿了就不投遞了。當(dāng)consumer對消息進(jìn)行ack以后就會將此消息移除,從而放入新的消息。

      通過上面的配置發(fā)現(xiàn)prefetch初始我只配置了2,并且concurrency配置的只有1,所以當(dāng)我發(fā)送了2條錯(cuò)誤消息以后,由于解析失敗這2條消息一直沒有被ack。將緩沖區(qū)沾滿了,這個(gè)時(shí)候RabbitMQ認(rèn)為這個(gè)consumer已經(jīng)沒有消費(fèi)能力了就不繼續(xù)給它推送消息了,所以就造成了隊(duì)列阻塞。

      判斷隊(duì)列是否有阻塞的風(fēng)險(xiǎn)。

      ??當(dāng)ack模式為manual,并且線上出現(xiàn)了unacked消息,這個(gè)時(shí)候不用慌。由于QOS是限制信道channel上的消費(fèi)者所能保持的最大未確認(rèn)的數(shù)量。所以允許出現(xiàn)unacked的數(shù)量可以通過channelCount * prefetchCount * 消費(fèi)節(jié)點(diǎn)數(shù)量得出。

      channlCount就是由concurrency,max-concurrency決定的。

      • min = concurrency * prefetch * 消費(fèi)節(jié)點(diǎn)數(shù)量
      • max = max-concurrency * prefetch * 消費(fèi)節(jié)點(diǎn)數(shù)量

      由此可以得出結(jié)論

      • unacked_msg_count < min 隊(duì)列不會阻塞。但需要及時(shí)處理unacked的消息。
      • unacked_msg_count >= min 可能會出現(xiàn)堵塞。
      • unacked_msg_count >= max 隊(duì)列一定阻塞。

      重點(diǎn)注意

      1unacked的消息在consumer切斷連接后(如重啟)再連接,會自動回到隊(duì)頭。

      2、若將ack模式改成auto自動,這樣會使QOS不生效。會出現(xiàn)大量消息涌入consumer從而可能造成consumer宕機(jī)風(fēng)險(xiǎn)。

       

      再回看程序配置,做一些分析和調(diào)整

       

       

       

      對B消費(fèi)端問題代碼加個(gè)try-catch-finally,不管中間有何問題,都進(jìn)行消息簽收ACK。

       

       

      代碼調(diào)整之后,兩個(gè)隊(duì)列正常運(yùn)行,客戶端兩個(gè)應(yīng)用也正常運(yùn)行。

       

       

       

      經(jīng)過一段時(shí)間消費(fèi),B消費(fèi)者端已經(jīng)把堆積的消息消費(fèi)完了。

       

       

      3、    第三個(gè)問題原因分析

      還是查看抓包信息

       

      Basic.Reject: 客戶端發(fā)送Basic.Reject方法請求,表示無法處理消息,拒絕消息,此時(shí)的requeue參數(shù)為true,將消息返回原來的隊(duì)列;

      Basic.Deliver: 服務(wù)端調(diào)用Basic.Deliver方法,和第一次Basic.Deliver方法不同的是,此時(shí)的redeliver參數(shù)為true,表示重新投遞消息到監(jiān)聽隊(duì)列的消費(fèi)者,然后這兩步會一直重復(fù)下去。

      RabbitMQ消息監(jiān)聽程序異常時(shí),consumer會向rabbitmq server發(fā)送Basic.Reject,表示消息拒絕接受,由于Spring默認(rèn)requeue-rejected配置為true,消息會重新入隊(duì),然后rabbitmq server重新投遞。就相當(dāng)于死循環(huán)了,所以容易導(dǎo)致消費(fèi)端資源占用過高,特別是TCP連接數(shù)、線程數(shù)、IO飆升,如果個(gè)別程序帶事務(wù)或數(shù)據(jù)庫操作等連接資源得不到釋放也會占滿,導(dǎo)致應(yīng)用假死狀態(tài)(出現(xiàn)問題的時(shí)候,查看問題應(yīng)用出現(xiàn)大量的connection timeout錯(cuò)誤報(bào)錯(cuò)日志)。

      因此針對性的,有些業(yè)務(wù)場景(不強(qiáng)調(diào)數(shù)據(jù)強(qiáng)一致性的場景,比如日志收集)可以設(shè)置default-requeue-rejected: false即可。

      factory.setDefaultRequeueRejected(false);

        會根據(jù)異常類型選擇直接丟棄或加入dead-letter-exchange中。

       

      消費(fèi)者端正確的使用手動確認(rèn)示例結(jié)構(gòu)代碼,很重要!

       

      try {
          // 業(yè)務(wù)邏輯。
      }catch (Exception e){
          // 輸出錯(cuò)誤日志。
      }finally {
          // 消息簽收。
      }

       

        

      4、    驗(yàn)證隊(duì)列設(shè)置最大長度限制

       

      設(shè)置queueLengthLimit隊(duì)列最大長度限制 x-max-length=5

       

       

       

      生產(chǎn)者原本想要生產(chǎn)10條消息

       

       

       

       

      由于受到隊(duì)列最大長度限制,實(shí)際上只有5條入隊(duì)列里面。

       

      消費(fèi)者拿出來的消息,僅有5條,從NO.6~NO.10

       

       

       

       

      改變消費(fèi)者程序,讓生產(chǎn)者一直產(chǎn)生消息,消費(fèi)者消費(fèi)速度明顯趕不上生產(chǎn)者的生產(chǎn)速度

       

       

       

      從消費(fèi)端來看消息是隨機(jī)性入隊(duì)的,隊(duì)列里面一直最多5條消息,發(fā)再多也進(jìn)不了,消息者和生產(chǎn)者也不會發(fā)生什么異常,只是消息會隨機(jī)性丟失(并沒有全部入隊(duì))。

       

       

      運(yùn)行情況良好,除了消息沒有全部入隊(duì)列 ,沒有出現(xiàn)異常情況

       

       

      消費(fèi)比較慢,本機(jī)器CPU和內(nèi)存各項(xiàng)指標(biāo)正常,沒有異常。

       

      搞一個(gè)異常情況出現(xiàn)unack,最大隊(duì)列長度限制,是不算unack數(shù)量的,如下圖所示

       

       

       

      異常之后,此觀察MQ監(jiān)控管理后臺

       

      生產(chǎn)者不停一直在生產(chǎn)消息,運(yùn)行30分鐘,觀察生產(chǎn)者應(yīng)用也是正常的的,就是消息入不了隊(duì)列。

       

       

       

       

      5、  檢查實(shí)際的業(yè)務(wù)端代碼

       

      再看我們業(yè)務(wù)系統(tǒng)消費(fèi)端代碼,消費(fèi)端各種不規(guī)范寫法都有,以下例舉幾個(gè)典型

      1、手動簽收有ACK,但是沒有try-catch-finally結(jié)構(gòu),消費(fèi)端業(yè)務(wù)代碼如下:

       

       

      2、有try-catch-finally結(jié)構(gòu),但是deliverTag是一個(gè)固定值0,一樣的會出問題。

       

       

      3、自動簽收確認(rèn)的,大量消息的時(shí)候,容易搞死消費(fèi)端應(yīng)用。

       


       

       

      6、    總結(jié)

      • 生產(chǎn)環(huán)境不建議使用自動ack模式,這樣會使QOS無法生效。
      • 在使用手動ack的時(shí)候,需要非常注意消息簽收,業(yè)務(wù)代碼使用try-catch-finally處理結(jié)構(gòu),防止業(yè)務(wù)代碼異常時(shí)無法簽收。
      • 規(guī)范約束mq客戶端代碼,正確的使用Rabbitmq配置。
      • 不同業(yè)務(wù)項(xiàng)目設(shè)置不同的vhost可以隔離一些影響,提升rabbitmq資源使用。
      • 考慮設(shè)置dead-letter-exchange,當(dāng)設(shè)置了 requeue=false時(shí),可以放入dead-letter-exchange,可以快速排查定位問題。
      • Exchange和隊(duì)列的最大長度限制可以是限制消息的數(shù)量(參數(shù):x-max-length),或者是消息的總字節(jié)數(shù)(總字節(jié)數(shù)表示的是所有的消息體的字節(jié)數(shù),忽略消息的屬性和任何頭部信息),又或者兩者都進(jìn)行了限制,兩者取小值生效,只有處于ready狀態(tài)的消息被計(jì)數(shù)未被確認(rèn)的消息不會被計(jì)數(shù)受到limit的限制。最大隊(duì)列設(shè)置可以限制生產(chǎn)端,但會造成消息丟失風(fēng)險(xiǎn),最大消息數(shù)量限制,不能完全解決隊(duì)列阻塞問題。
      • 盡量使用Direct-exchange,Direct 類型的 Exchange 投遞消息是最快的。
        • Direct:處理路由鍵,需要將一個(gè)隊(duì)列綁定到交換機(jī)上,要求該消息與一個(gè)特定的路由鍵完全匹配。這是一個(gè)完整的匹配。如果一個(gè)隊(duì)列綁定到該交換機(jī)上要求路由鍵為“A”,則只有路由鍵為“A”的消息才被轉(zhuǎn)發(fā),不會轉(zhuǎn)發(fā)路由鍵為"B",只會轉(zhuǎn)發(fā)路由鍵為“A”;
        • Topic:將路由鍵和某模式進(jìn)行匹配。此時(shí)隊(duì)列需要綁定要一個(gè)模式上。符號“#”匹配一個(gè)或多個(gè)詞,符號“*”只能匹配一個(gè)詞;
        • Fanout:不處理路由鍵。只需要簡單的將隊(duì)列綁定到交換機(jī)上。一個(gè)發(fā)送到該類型交換機(jī)的消息都會被廣播到與該交換機(jī)綁定的所有隊(duì)列上;
        • Headers:不處理路由鍵,而是根據(jù)發(fā)送的消息內(nèi)容中的 headers 屬性進(jìn)行匹配。在綁定 Queue 與 Exchange 時(shí)指定一組鍵值對;當(dāng)消息發(fā)送到 RabbitMQ 時(shí)會取到該消息的 headers 與 Exchange 綁定時(shí)指定的鍵值對進(jìn)行匹配;如果完全匹配則消息會路由到該隊(duì)列,否則不會路由到該隊(duì)列。

       

      寫在最后,RabbitMQ集群做為整個(gè)平臺關(guān)鍵部件,它的好處自然不用再說,但是它也不是萬金油,一旦巖機(jī)影響很大,后果比較嚴(yán)重。怎么用好它?我們有必要正確深入的認(rèn)識并使用它,首先得擺好正確的姿勢(寫正確的客戶端代碼、嚴(yán)謹(jǐn)?shù)呐渲茫荒茈S意,否則后果很嚴(yán)重。希望經(jīng)過此故障經(jīng)驗(yàn)教訓(xùn)能與君共勉,同時(shí)也希望我的總結(jié)能夠給大家一點(diǎn)幫助和啟發(fā),權(quán)當(dāng)拋磚引玉。

      posted on 2023-03-05 00:25  陳國利  閱讀(50364)  評論(10)    收藏  舉報(bào)

      主站蜘蛛池模板: 国产亚洲欧美在线观看三区| 99久久免费精品色老| 国产99视频精品免费视频36| 亚洲精品午夜精品| 国产精品av中文字幕| 久久一卡二卡三卡四卡| 日本三线免费视频观看| A男人的天堂久久A毛片| 国精品午夜福利视频不卡| 日韩欧美一卡2卡3卡4卡无卡免费2020| 国产精品免费AⅤ片在线观看| 国产色无码专区在线观看| 色综合色狠狠天天综合网| 郸城县| 亚洲偷自拍另类一区二区| 午夜福利国产精品视频| 18禁午夜宅男成年网站| 亚洲综合一区二区三区不卡| 又大又硬又爽免费视频| 极品无码国模国产在线观看| 激情伊人五月天久久综合| 成人无码潮喷在线观看| 四虎影视库国产精品一区| 久久精品国产亚洲夜色AV网站| 色综合人人超人人超级国碰| 中国少妇人妻xxxxx| 久久综合精品成人一本| 微山县| 在线a级毛片无码免费真人| 黄色三级亚洲男人的天堂| 永久免费无码国产| 成人小说亚洲一区二区三区| 两性午夜刺激性视频| 日本高清久久一区二区三区| 视频二区中文字幕在线| 午夜国产精品福利一二| 日韩精品一区二区三区久| 亚洲成av人片色午夜乱码| 国产成人无码AV片在线观看不卡| 天堂…中文在线最新版在线| 亚洲天堂激情av在线|