RabbitMQ核心元件及應用場景

檸檬樹開花了發表於2019-05-23

一、適用場景

1.解耦
2.最終一致性
3.廣播
4.錯峰與流控(秒殺業務用於流量削峰場景)

秒殺場景

二、核心元件,關鍵點(交換器、佇列、繫結)

RabbitMQ核心元件及應用場景

AMPQ訊息路由必要三部分:交換器、佇列、繫結。

Java核心元件:ConnectionFactory、Connection、Channel、Delivery、DeliverCallback、CancelCallback

佇列

1. 建立連線
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("admin");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
2. 宣告佇列

如果在同一條通道上訂閱了另一個佇列,那就不能再宣告佇列,必須先取消訂閱。

Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
                             Map<String, Object> arguments) throws IOException;

queue:需要指定佇列名稱,如果不指定,MQ會隨機分配一個並在queue.declare命令中返回,

durable:佇列將在伺服器重啟後存在。

exclusive:為true時,佇列變成私有的。

autoDelete: 為true時,當最後一個消費者取消訂閱時,佇列自動移除。

3. 消費者通過AMQP的basic.consume命令訂閱訊息,將通道置為接收模式。

Java程式碼Channel:

String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException;
4. 當有多個消費者存在時,佇列裡的訊息將以迴圈的方式傳送給消費者。消費者接收到訊息後必須進行確認,可通過basic.ack顯示確認:

Java程式碼Channel:

void basicAck(long deliveryTag, boolean multiple) throws IOException;

上面的手動確認,第二個引數為true,批量確認;如果為false,會一次確認一條。當有耗時任務時,可以利用手動確認延遲確認訊息,防止訊息大量湧入應用導致過載。
也可以在訂閱佇列時就將basicConsume方法的autoAck引數設定為true,開啟自動確認。確認成功後rabbitmq會從佇列中刪除訊息。

5. 如果在確認過程中和rabbitmq伺服器斷鏈,那麼這條訊息就會傳送給下一個消費者。可以使用basic.reject拒絕訊息:

Java程式碼Channel:

void basicReject(long deliveryTag, boolean requeue) throws IOException;

第二個引數requeue設定為true,訊息會重新排隊併傳送給下一個消費者;為false則會丟棄該條訊息。可以利用此性質丟棄錯誤格式的訊息。

6. 釋出訊息
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;

exchange:第一個引數是交換的名稱。空字串表示預設或無名交換,訊息通過routingKey路由到指定佇列。

交換器和繫結

1. 交換器一共有四種型別:fanout、direct 、topic、headers。

Java中Channel申明交換器:

Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException;

BuiltinExchangeType對應有四種列舉型別:

DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers");
2. 佇列通過路由鍵(routing key)繫結到交換器。
channel.queueBind(String queue, String exchange, String routingKey)

RabbitMQ中訊息傳遞模型的核心思想是生產者永遠不會將任何訊息直接傳送到佇列。實際上,生產者甚至不知道訊息是否會被傳遞到哪個佇列。

不指定佇列名時,通過伺服器隨機生成佇列名稱:

String queueName = channel.queueDeclare().getQueue();

不傳引數時,queueDeclare生成一個非持久的,獨佔的自動刪除佇列

在linux伺服器上可以通過命令檢視所有交換器:

rabbitmqctl list_exchanges
3. fanout廣播方式

RabbitMQ核心元件及應用場景

廣播方式會將訊息投遞給所有附加在此交換器的佇列。

4. direct模式

RabbitMQ核心元件及應用場景

direct型別在繫結時設定一個routing_key,訊息的routing_key匹配時, 才會被交換器投遞到繫結的佇列中去.

5. topic模式

RabbitMQ核心元件及應用場景

按規則投遞,通過萬用字元#和*組合

*(星號)可以替代一個單詞。

#(hash)可以替換零個或多個單詞。

持久化

將佇列和交換器的durable屬性設定為true

申明佇列時:

channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
                             Map<String, Object> arguments) throws IOException;

申明交換器時:

channel.exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException;

投遞訊息時將投遞模式(delivery mode)設定為2,Java程式碼中MessageProperties.PERSISTENT_TEXT_PLAIN來設定:

channel.basicPublish(EXCHANGE_NAME, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"));

在MessageProperties原始碼中如下所示:

/** Content-type "text/plain", deliveryMode 2 (persistent), priority zero */
public static final BasicProperties PERSISTENT_TEXT_PLAIN =
    new BasicProperties("text/plain",
                        null,
                        null,
                        2,
                        0, null, null, null,
                        null, null, null, null,
                        null, null);

實現事務功能(傳送方確認)

使用事務會使rabbitmq的效能大大降低,為了避免這個問題,rabbitmq支援:傳送方確認模式。通過這個模式來保證訊息的投遞。當生產者P投遞訊息後會等待消費者C傳送確認,P收到確認後可以呼叫回撥函式處理相關業務。在生產者P等待確認的同時也可以繼續傳送下一條訊息。

伺服器管理

1、虛擬主機vhost

rabbitmq支援建立虛擬主機,預設的虛擬主機為“/”,預設使用者guest;當在rabbitmq叢集中建立虛擬主機時,整個叢集都會建立。

2、錯誤日誌檢視

rabbitmq的日誌檔案在/var/log/rabbitmq/下的rabbit@[localhost].log

3、rabbitmq配置檔案

配置檔案在rpm安裝/usr/share/doc/rabbitmq-server-3.6.5/rabbitmq.config.example,複製一份:

cp /usr/share/doc/rabbitmq-server-3.5.3/rabbitmq.config.example /etc/rabbitmq.config

參考官網配置:https://www.rabbitmq.com/configure.html#configuration-file

三、底層原理,主要實現

應用程式和rabbitmq伺服器之間建立一條tcp連線,tcp連線開啟後,應用程式就可以和rabbitmq建立多條AMQP通道,通道是建立在tcp連線上的虛擬連線。

四、同類技術產品比較

RabbitMQ核心元件及應用場景

1.ActiveMQ

優點

單機吞吐量:萬級
topic數量都吞吐量的影響:
時效性:ms級
可用性:高,基於主從架構實現高可用性
訊息可靠性:有較低的概率丟失資料
功能支援:MQ領域的功能極其完備
缺點:

官方社群現在對ActiveMQ 5.x維護越來越少,較少在大規模吞吐的場景中使用。

2.Kafka

號稱大資料的殺手鐗,談到大資料領域內的訊息傳輸,則繞不開Kafka,這款為大資料而生的訊息中介軟體,以其百萬級TPS的吞吐量名聲大噪,迅速成為大資料領域的寵兒,在資料採集、傳輸、儲存的過程中發揮著舉足輕重的作用。

Apache Kafka它最初由LinkedIn公司基於獨特的設計實現為一個分散式的提交日誌系統( a distributed commit log),之後成為Apache專案的一部分。

目前已經被LinkedIn,Uber, Twitter, Netflix等大公司所採納。

優點

效能卓越,單機寫入TPS約在百萬條/秒,最大的優點,就是吞吐量高。
時效性:ms級
可用性:非常高,kafka是分散式的,一個資料多個副本,少數機器當機,不會丟失資料,不會導致不可用
消費者採用Pull方式獲取訊息, 訊息有序, 通過控制能夠保證所有訊息被消費且僅被消費一次;
有優秀的第三方Kafka Web管理介面Kafka-Manager;
在日誌領域比較成熟,被多家公司和多個開源專案使用;
功能支援:功能較為簡單,主要支援簡單的MQ功能,在大資料領域的實時計算以及日誌採集被大規模使用
缺點:

Kafka單機超過64個佇列/分割槽,Load會發生明顯的飆高現象,佇列越多,load越高,傳送訊息響應時間變長
使用短輪詢方式,實時性取決於輪詢間隔時間;
消費失敗不支援重試;
支援訊息順序,但是一臺代理當機後,就會產生訊息亂序;
社群更新較慢;

3.RabbitMQ

RabbitMQ 2007年釋出,是一個在AMQP(高階訊息佇列協議)基礎上完成的,可複用的企業訊息系統,是當前最主流的訊息中介軟體之一。

RabbitMQ優點:

由於erlang語言的特性,mq 效能較好,高併發;
吞吐量到萬級,MQ功能比較完備
健壯、穩定、易用、跨平臺、支援多種語言、文件齊全;
開源提供的管理介面非常棒,用起來很好用
社群活躍度高;
RabbitMQ缺點:

erlang開發,很難去看懂原始碼,基本職能依賴於開源社群的快速維護和修復bug,不利於做二次開發和維護。
RabbitMQ確實吞吐量會低一些,這是因為他做的實現機制比較重。
需要學習比較複雜的介面和協議,學習和維護成本較高。

4.RocketMQ

RocketMQ出自 阿里公司的開源產品,用 Java 語言實現,在設計時參考了 Kafka,並做出了自己的一些改進。

RocketMQ在阿里集團被廣泛應用在訂單,交易,充值,流計算,訊息推送,日誌流式處理,binglog分發等場景。

RocketMQ優點:

單機吞吐量:十萬級
可用性:非常高,分散式架構
訊息可靠性:經過引數優化配置,訊息可以做到0丟失
功能支援:MQ功能較為完善,還是分散式的,擴充套件性好
支援10億級別的訊息堆積,不會因為堆積導致效能下降
原始碼是java,我們可以自己閱讀原始碼,定製自己公司的MQ,可以掌控
RocketMQ缺點:

支援的客戶端語言不多,目前是java及c++,其中c++不成熟;
社群活躍度一般
沒有在 mq 核心中去實現JMS等介面,有些系統要遷移需要修改大量程式碼

github程式碼

https://github.com/LighterTang/RabbitMQUtils/tree/master/rabbitmq_base/src/main/java/com/mq/mqutils/mqdoc

參考資料

https://www.rabbitmq.com

http://youzhixueyuan.com/comparison-of-kafka-rocketmq-rabbitmq.html

相關文章