RabbitMQ入門(二、RabbitMQ基本發送方式)

  • 本文出現的代碼只是簡述,詳細代碼之後文章有涉及。

簡單隊列

RabbitMQ中的消息都只能存儲在Queue中,生產者(下圖中的P)生產消息並最終投遞到Queue中,消費者(下圖中的C)可以從Queue中獲取消息並消費。
在這裏插入圖片描述

工作隊列

即單生產者,多個消費者消費隊列的情況。
在這裏插入圖片描述

工作隊列–輪詢分發

即使一個處理快,一個處理慢,消息隊列也還是平均的分發

工作隊列–公平分發(fair dipatch)

  • 消費者關閉自動應答,ack改爲手動;

    每個消費者發送確認消息之前,消息隊列不發送下一個消息到消費者,一次只處理一個消息,限制發送給同一個消費者不得超過一個消息

    生產者(消息隊列)

    //保證一次只分發一個
    int prefetchCount=1;
    channel.baseicQos(prefetchCount)
    

    消費者

    //保證一次只分發一個
    int prefetchCount=1;
    channel.baseicQos(prefetchCount);
    channel.basicAck(envelope.getDeliveryTag(),false); 
    boolean autoAck=false;
    

autoAck爲true時,爲自動確認模式,即一旦rabbitMQ將消息分發給消費者,就會從內存中刪除;這種情況下,如果正在執行的消費者線程掛了,就會丟失正在處理的消息;

autoAck爲false時,如果有一個消費者掛掉,就會交付給其他消費者,rabbitmq支持消息應答,消費者發送一個消息應答,告訴rabbitmq這個消息我已經處理完成,你可以刪了,然後rabbitmq再刪除內存中的消息。

消息應答默認是打開的。

消息的持久化

如果rabbitMq掛了,怎麼辦?

這時候,引入持久化。

//聲明隊列
boolean durable=false;
channel.queueDeclare(QUEUE_NAME,durable,false,false,null);

我們將程序中的boolean durable=false改爲true是不可以的,儘管代碼是正確的,他也不會成功運行;因爲我們已經定義了一個名爲QUEUE_NAME的隊列,這個隊列是未持久化的,rabbitmq不準重新定義(不同參數)一個已存在的隊列。

訂閱模式(Publish /Subscribe)

在這裏插入圖片描述
解讀:

  • 一個生產者,多個消費者
  • 每個消費者都有自己的隊列
  • 生產者沒有直接把消息隊列發送到隊列,而是發送到了交換機、轉發器、exchange
  • 每個隊列都要綁定到交換機上
  • 生產者發送的消息,經過交換機,到達隊列,就能實現一個消息被多個消費者消息

疑問:

  • 如果只聲明交換機,未聲明隊列,此時發送消息,會發現消息丟失了,消息哪去了?

    交換機沒有存儲的能力,在rabbitMq中只有消息隊列有存儲的能力,這時候沒有隊列綁定到交換機上,所以數據丟失了。

Exchange(交換機、轉發器)

兩方面的操作:接收生產者的消息,同時向隊列推送消息

fanout

匿名模式(非路由模式)

//其中第二個參數就爲:routingKey
channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes())

它會把所有發送到該Exchange的消息路由到所有與它綁定的Queue中。

Routing

路由模式

Direct

在這裏插入圖片描述
exchangeType爲direct,它會把消息路由到那些binding key與routing key完全匹配的Queue中。

Topic exchange

將路由鍵和某模式匹配。

前面講到direct類型的Exchange路由規則是完全匹配binding key與routing key,但這種嚴格的匹配方式在很多情況下不能滿足實際業務需求。topic類型的Exchange在匹配規則上進行了擴展,它與direct類型的Exchage相似,也是將消息路由到binding key與routing key相匹配的Queue中,但這裏的匹配規則有些不同,它約定:

  • routing key爲一個句點號“. ”分隔的字符串(我們將被句點號“. ”分隔開的每一段獨立的字符串稱爲一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
  • binding key與routing key一樣也是句點號“. ”分隔的字符串
  • binding key中可以存在兩種特殊字符“*”與“#”,用於做模糊匹配,其中“ * ”用於匹配一個單詞,“ # ”用於匹配多個單詞(可以是零個)
    在這裏插入圖片描述
    (商品:發佈、刪除、修改…)

RabbitMQ的消息確認機制(事務+confirm)

在rabbitmq中可以通過持久化數據,解決rabbitmq服務器異常的數據丟失問題。

問題:生產者將消息發送出去之後,消息到底有沒有到達rabbitmq服務器,默認的情況是不知道的。(之前持久化是解決了:開啓自動確認模式時,消費者突然斷電的清空)。

兩種方式:

  • AMQP實現了事務機制
  • Confirm模式

事務機制

txSelect、txCommit、txRollback

txSelect:用戶將當前channel設置成transation模式

txCommit:用於提交事務

txRollback:回滾事務

channel.TxSelect();//將信道設置爲事務模式
try
{
    //do something
    var message = Encoding.UTF8.GetBytes("TestMsg");
    channel.BasicPublish("normalExchange", "NormalRoutingKey", true, null, message);
    //do something
    channel.TxCommit();//提交事務
}
catch (Exception ex)
{
    //log(ex);
    channel.TxRollback();
}

事務確實能夠解決消息發送方和RabbitMQ之間消息確認的問題,只有消息成功被RabbitMQ接收,事務才能提交成功,否則便可在捕獲異常之後進行事務回滾,與此同時可以進行消息重發。但是使用事務同樣會帶來一些問題。

  • 會阻塞,發佈者必須等待broker處理每個消息。
  • 事務是重量級的,每次提交都需要fsync(),需要耗費大量的時間
  • 事務非常耗性能,會降低RabbitMQ的消息吞吐量。

Confirm模式

這裏就引入了一種輕量級的方式一發送方確認(publisher confirm)機制。生產者將信道設置成confirm確認模式,一旦信道進入confirm模式,所有在該信道上面發佈的消息都會被指派一個唯一的ID( 從1開始),一旦消息被投遞到所有匹配的隊列之後,RabbitMQ就會發送一個確認(BasicAck) 給生產者(包含消息的唯一ID),這就使得生產者知曉消息已經正確到達了目的地了。如果消息和隊列是可持久化的,那麼確認消息會在消息寫入磁盤之後發出。

Comfirm模式的最大好處就是它是異步的。

開啓Confirm模式:

channel.ConfirmSelect();//開啓確認模式

編程模式:

  • 普通,發一條,waitForConfirms()
  • 批量的,發一批
  • 異步confirm模式:提供一個回調方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章