我的RabbitMq的知識概要【筆記】

基礎知識

  1. 此消息隊列爲RabbitMq消息隊列

  2. rabbitMq主要涉及到[隊列,生產者,消費者]

  3. 生產者和消費者都可以創建隊列

  4. 隊列可以多次創建,但是如果第二次創建的時候,參數與之前的不一樣,雖然現實成功,但是參數不會改變

  5. 生產者把消息(同時帶上routing key)發送Exchange

  6. rabbitmq數據具有數據緩存機制,沒有消費者消費時,會進行暫時緩存。

  7. 如果程序有bug,忘記ask,那麼RabbitMqServer不會將消息再次發送給它,因爲服務器任務這個消費者處理有限

  8. 概念說明

    概念 說明
    Broker 它提供一種傳輸服務,它的角色就是維護一條從生產者到消費者的路線,保證數據能按照指定的方式進行傳輸,
    Exchange 消息交換機,它指定消息按什麼規則,路由到哪個隊列。
    Queue 消息的載體,每個消息都會被投到一個或多個隊列。
    Binding 綁定,它的作用就是把exchange和queue按照路由規則綁定起來.
    Routing Key 路由關鍵字,exchange根據這個關鍵字進行消息投遞。
    vhost 虛擬主機,一個broker裏可以有多個vhost,用作不同用戶的權限分離。
    Producer 消息生產者,就是投遞消息的程序.
    Consumer 消息消費者,就是接受消息的程序.
    Channel 消息通道,在客戶端的每個連接裏,可建立多個channel.
  9. 可以使用hannel.ExchangeDeclare進行exchange持久化,channel.QueueDeclare隊列持久化,在投遞時指定delivery_mode => 2(1是非持久化)消息持久化

    • 如果exchange和queue都是持久化的,那麼它們之間的binding也是持久化的,如果exchange和queue兩者之間有一個持久化,一個非持久化,則不允許建立綁定.
    • 注意:一旦創建了隊列和交換機,就不能修改其標誌了,例如,創建了一個non-durable的隊列,然後想把它改變成durable的,唯一的辦法就是刪除這個隊列然後重現創建。
  10. 任務分發機制

    • Round-robin dispathching循環分發
      • RabbbitMQ的分發機制非常適合擴展,而且它是專門爲併發程序設計的,如果現在load加重,那麼只需要創建更多的Consumer來進行任務處理。
    • Message acknowledgment消息確認
      • 消息發送之後,消息需要對消息進行消息發送成功與否進行確認,如果消息服務器關閉,此時還沒有ask,則此消息重新發送
  11. 消息分發機制

    • Fair dispath 公平分發
      • 分發機制不是那麼優雅,默認狀態下,RabbitMQ將第n個Message分發給第n個Consumer。n是取餘後的,它不管Consumer是否還有unacked Message,只是按照這個默認的機制進行分發.
      • 那麼如果有個Consumer工作比較重,那麼就會導致有的Consumer基本沒事可做,有的Consumer卻毫無休息的機會,那麼,Rabbit是如何處理這種問題呢?
      • 通過basic.qos方法設置prefetch_count=1,這樣RabbitMQ就會使得每個Consumer在同一個時間點最多處理一個Message,換句話說,在接收到該Consumer的ack前,它不會將新的Message分發給它
        channel.basic_qos(prefetch_count=1),當然也可以在配置文件中配置
  12. 交換路由的幾種類型

    • Direct Exchange:直接匹配,通過Exchange名稱+RountingKey來發送與接收消息.【如果路由鍵完全匹配的話,消息纔會被投放到相應的隊列。】
    • Fanout Exchange:廣播訂閱,向所有的消費者發佈消息,但是隻有消費者將隊列綁定到該路由器才能收到消息,忽略Routing Key【當發送一條消息到fanout交換器上時,它會把消息投放到所有附加在此交換器上的隊列。】
    • Topic Exchange:主題匹配訂閱,這裏的主題指的是RoutingKey,RoutingKey可以採用通配符,如:或#,RoutingKey命名採用.來分隔多個詞,只有消息這將隊列綁定到該路由器且指定RoutingKey符合匹配規則時才能收到消息【設置模糊的綁定方式,“”操作符將“.”視爲分隔符,匹配單個字符;“#”操作符沒有分塊的概念,它將任意“.”均視爲關鍵字的匹配部分,能夠匹配多個字符。】
  13. RabbitMq的五種隊列模式

    • 一個生產者對應一個消費者【生產者將消息發送到“hello”隊列。消費者從該隊列接收消息。】
    • work 模式【一個生產者對應多個消費者,但是隻能有一個消費者獲得消息!!!】
      • 消費者1和消費者2獲取到的消息內容是不同的,也就是說同一個消息只能被一個消費者獲取。
      • 【channel.basicQos(1);】增加如上代碼,表示同一時刻服務器只會發送一條消息給消費者。可以實現能者多勞,即讓效率高的去消費更高的信息
      • 效率高的消費者消費消息多。可以用來進行負載均衡。
    • 發佈/訂閱模式【一個消費者將消息首先發送到交換器,交換器綁定到多個隊列,然後被監聽該隊列的消費者所接收並消費。】
      • 交換器,在RabbitMQ中,交換器主要有四種類型:direct、fanout、topic、headers
      • 此模式用到的交換機是->fanout
      • (就是一條消息發送到一個綁定着兩個不同的隊列的交換機上,交換機會把消息發送到這兩個隊列上)消費1和消費者2都消費了該消息,這是因爲消費者1和消費者2都監聽了被同一個交換器綁定的隊列。如果消息發送到沒有隊列綁定的交換器時,消息將丟失,因爲交換器沒有存儲消息的能力,消息只能存儲在隊列中。
      • 應用場景:比如一個商城系統需要在管理員上傳商品新的圖片時,前臺系統必須更新圖片,日誌系統必須記錄相應的日誌,那麼就可以將兩個隊列綁定到圖片上傳交換器上,一個用於前臺系統更新圖片,另一個用於日誌系統記錄日誌。
    • 路由模式【生產者將消息發送到direct交換器,在綁定隊列和交換器的時候有一個路由key,生產者發送的消息會指定一個路由key,那麼消息只會發送到相應key相同的隊列,接着監聽該隊列的消費者消費消息。】
      • 此模式用到的交換機是->direct
      • 應用場景:利用消費者能夠有選擇性的接收消息的特性,比如我們商城系統的後臺管理系統對於商品進行修改、刪除、新增操作都需要更新前臺系統的界面展示,而查詢操作確不需要,那麼這兩個隊列分開接收消息就比較好。
    • 主題模式【上面的路由模式是根據路由key進行完整的匹配(完全相等才發送消息),這裏的通配符模式通俗的來講就是模糊匹配。符號"#“表示匹配一個或多個詞,符號”*"表示匹配一個詞。】
      • 此模式用到的交換機是->topic
      • 生產者發送消息綁定的路由key爲update.Name;消費者1監聽的隊列和交換器綁定路由key爲update.#;消費者2監聽的隊列和交換器綁定路由key爲select.#。很顯然,消費者1會接收到消息,而消費者2接收不到。
    • 其他說明
      • 但是實際上只有三種,第一種簡單隊列,第二種工作模式,剩下的三種都是和交換器綁定的合起來稱爲一種,這小節我們就來詳細介紹交換器。
      • 前面三種分別對應路由模式、發佈訂閱模式和通配符模式,headers 交換器允許匹配 AMQP 消息的 header 而非路由鍵,除此之外,header 交換器和 direct 交換器完全一致,但是性能卻差很多,因此基本上不會用到該交換器

生產者與消費者

  1. 擴展知識

    • @Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)這個是說在每次注入的時候回自動創建一個新的bean實例
      @Scope(value=ConfigurableBeanFactory.SCOPE_SINGLETON)單例模式,在整個應用中只能創建一個實例
      @Scope(value=WebApplicationContext.SCOPE_GLOBAL_SESSION)全局session中的一般不常用
      @Scope(value=WebApplicationContext.SCOPE_APPLICATION)在一個web應用中只創建一個實例
      @Scope(value=WebApplicationContext.SCOPE_REQUEST)在一個請求中創建一個實例
      @Scope(value=WebApplicationContext.SCOPE_SESSION)每次創建一個會話中創建一個實例
      • 這個是隻有在用戶訪問系統時纔會創建,也就是說,當Spring啓動時容器中是沒有的,這時候另一個類依賴此bean是不可以的,這是可以指定以下屬性進行代理注入,帶當前類是接口是可使用INTERFACES創建一個JDK代理模式,這是一個類時,可使用TARGET_CLASS基於類的代理模式
      • 裏面還有個屬性
        proxyMode=ScopedProxyMode.INTERFACES創建一個JDK代理模式
        proxyMode=ScopedProxyMode.TARGET_CLASS基於類的代理模式
        proxyMode=ScopedProxyMode.NO(默認)不進行代理
  2. 延遲隊列的實現

  3. 定義隊列時參數說明

參數 說明
queue - 隊列名稱
passive false 隊列不存在則創建,存在則直接成功
durable true 隊列持久化
exclusive false 排他,指定該選項爲true則隊列只對當前連接有效,連接斷開後自動刪除
no-wait false 該方法需要應答確認
auto-delete false 當不再使用時,是否自動刪除
  1. 配置模板暫存相關文章
    server.port=6006
    spring.application.name=springboot_rabbitmq
    #rabbitmq config
    #spring.rabbitmq.addresses=單機,集羣多個地址以,號隔開
    spring.rabbitmq.host=localhost
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=tanjie
    spring.rabbitmq.password=tanjie666
    spring.rabbitmq.virtual-host=/
    #開啓rabbitmq的confirm機制,如果消息沒有到達exchange,或者exchange在ack生產者的時候,生產者沒有收到,那麼生產者會進行重發
    #如果設置爲false,經過測試,不會進行回調
    spring.rabbitmq.publisher-confirms=true
    #開啓rabbitmq的生產端{template}重試機制,默認是false,默認重試3次
    spring.rabbitmq.template.retry.enabled=true
    #關閉消息的強制路由,當生產者將消息發到exchange,如果沒有queue進行綁定, 禁止broker發送basic.return,表示當前消息無人消費
    #因爲我們配置了消息的持久性,就算沒有消費者,消息也在磁盤,默認就是false
    spring.rabbitmq.template.mandatory=false
    #開啓rabbitmq的消費者{listener}重試機制,該重試機制需要設置爲自動ack,本次方案和PHP保持一致,如果消費者消費失敗後,手動將消息放入死信隊列等待消息被重新消費
    # 默認該配置爲false,設置爲true的意思是,如果消費者消費失敗了,rabbitmq server會自動重試3次
    #spring.rabbitmq.listener.simple.retry.enabled=true
    #消費端採用手動應答
    spring.rabbitmq.listener.simple.acknowledge-mode=manual
    #默認緩存模式是channel,在springboot裏面,比如在框架rabbitmqTemplate中使用的通道將會可靠地返回到緩存中
    #spring.rabbitmq.cache.connection.mode=channel
    #設置默認通道緩存的大小
    #spring.rabbitmq.cache.channel.size=10
    #配置生產者的配置,包括exchange,routingkey等
    java.rabbitmq.send.service.exchange=scm3.materials
    java.rabbitmq.send.service.rountkey=direct_rounting_key
    #配置supply監聽信息
    java.rabbitmq.consumer.service.retry.exchange=scm3.materials.retry
    java.rabbitmq.consumer.service.fail.exchange=scm3.materials.fail
    java.rabbitmq.consumer.service.supply.retry.routingkey=material@supply
    #配置user監聽信息
    java.rabbitmq.consumer.service.user.retry.routingkey=material@user
  1. 隊列的一些key的說明

  2. 延遲重試死信隊列原理圖

    1. 生產者發佈消息到主Exchange
    2. 主Exchange根據Routing Key將消息分發到對應的消息隊列
    3. 多個消費者的worker進程同時對隊列中的消息進行消費,因此它們之間採用“競爭”的方式來爭取消息的消費
    4. 消息消費後,不管成功失敗,都要返回ACK消費確認消息給隊列,避免消息消費確認機制導致重複投遞,同時,如果消息處理成功,則結束流程,否則進入重試階段
    5. 如果重試次數小於設定的最大重試次數(默認爲3次),則將消息重新投遞到Retry Exchange的重試隊列
    6. 重試隊列不需要消費者直接訂閱,它會等待消息的有效時間過期之後,重新將消息投遞給Dead Letter Exchange,我們在這裏將其設置爲主Exchange,實現延時後重新投遞消息,這樣消費者就可以重新消費消息
    7. 如果三次以上都是消費失敗,則認爲消息無法被處理,直接將消息投遞給Failed Exchange的Failed Queue,這時候應用可以觸發報警機制,以通知相關責任人處理
    8. 等待人工介入處理(解決bug)之後,重新將消息投遞到主Exchange,這樣就可以重新消費了
  3. 基礎配置示例

spring:
  rabbitmq:
    host: rabbit地址
    port: 5673
    username: guest
    password: guest
    virtual-host: /
    listener:
      simple:
        retry:
          max-attempts: 5 #最大重試次數
          initial-interval: 1000ms #重試間隔時間(單位毫秒)
          enabled: true #是否開啓消費者重試(爲false時關閉消費者重試,這時消費端代碼異常會一直重複收到消息)
        default-requeue-rejected: false   #重試次數超過上面的設置之後是否丟棄(false不丟棄時需要寫相應代碼將該消息加入死信隊列)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章