消息隊(duì)列之 RabbitMQ

關(guān)于消息隊(duì)列,從前年開始斷斷續(xù)續(xù)看了些資料啥辨,想寫很久了,但一直沒(méi)騰出空盯腌,近來(lái)分別碰到幾個(gè)朋友聊這塊的技術(shù)選型溉知,是時(shí)候把這塊的知識(shí)整理記錄一下了。

市面上的消息隊(duì)列產(chǎn)品有很多腊嗡,比如老牌的 ActiveMQ着倾、RabbitMQ 拾酝,目前我看最火的 Kafka 燕少,還有 ZeroMQ ,去年底阿里巴巴捐贈(zèng)給 Apache 的 RocketMQ 蒿囤,連 redis 這樣的 NoSQL 數(shù)據(jù)庫(kù)也支持 MQ 功能客们。總之這塊知名的產(chǎn)品就有十幾種材诽,就我自己的使用經(jīng)驗(yàn)和興趣只打算談?wù)?RabbitMQ底挫、Kafka 和 ActiveMQ ,本文先講 RabbitMQ 脸侥,在此之前先看下消息隊(duì)列的相關(guān)概念建邓。

什么叫消息隊(duì)列

消息(Message)是指在應(yīng)用間傳送的數(shù)據(jù)。消息可以非常簡(jiǎn)單睁枕,比如只包含文本字符串官边,也可以更復(fù)雜,可能包含嵌入對(duì)象外遇。

消息隊(duì)列(Message Queue)是一種應(yīng)用間的通信方式注簿,消息發(fā)送后可以立即返回,由消息系統(tǒng)來(lái)確保消息的可靠傳遞跳仿。消息發(fā)布者只管把消息發(fā)布到 MQ 中而不用管誰(shuí)來(lái)取诡渴,消息使用者只管從 MQ 中取消息而不管是誰(shuí)發(fā)布的。這樣發(fā)布者和使用者都不用知道對(duì)方的存在菲语。

為何用消息隊(duì)列

從上面的描述中可以看出消息隊(duì)列是一種應(yīng)用間的異步協(xié)作機(jī)制妄辩,那什么時(shí)候需要使用 MQ 呢惑灵?

以常見(jiàn)的訂單系統(tǒng)為例,用戶點(diǎn)擊【下單】按鈕之后的業(yè)務(wù)邏輯可能包括:扣減庫(kù)存眼耀、生成相應(yīng)單據(jù)泣棋、發(fā)紅包、發(fā)短信通知畔塔。在業(yè)務(wù)發(fā)展初期這些邏輯可能放在一起同步執(zhí)行潭辈,隨著業(yè)務(wù)的發(fā)展訂單量增長(zhǎng),需要提升系統(tǒng)服務(wù)的性能澈吨,這時(shí)可以將一些不需要立即生效的操作拆分出來(lái)異步執(zhí)行把敢,比如發(fā)放紅包、發(fā)短信通知等谅辣。這種場(chǎng)景下就可以用 MQ 修赞,在下單的主流程(比如扣減庫(kù)存、生成相應(yīng)單據(jù))完成之后發(fā)送一條消息到 MQ 讓主流程快速完結(jié)桑阶,而由另外的單獨(dú)線程拉取MQ的消息(或者由 MQ 推送消息)柏副,當(dāng)發(fā)現(xiàn) MQ 中有發(fā)紅包或發(fā)短信之類的消息時(shí),執(zhí)行相應(yīng)的業(yè)務(wù)邏輯蚣录。

以上是用于業(yè)務(wù)解耦的情況割择,其它常見(jiàn)場(chǎng)景包括最終一致性、廣播萎河、錯(cuò)峰流控等等荔泳。

RabbitMQ 特點(diǎn)

RabbitMQ 是一個(gè)由 Erlang 語(yǔ)言開發(fā)的 AMQP 的開源實(shí)現(xiàn)。

AMQP :Advanced Message Queue虐杯,高級(jí)消息隊(duì)列協(xié)議玛歌。它是應(yīng)用層協(xié)議的一個(gè)開放標(biāo)準(zhǔn),為面向消息的中間件設(shè)計(jì)擎椰,基于此協(xié)議的客戶端與消息中間件可傳遞消息支子,并不受產(chǎn)品、開發(fā)語(yǔ)言等條件的限制达舒。

RabbitMQ 最初起源于金融系統(tǒng)值朋,用于在分布式系統(tǒng)中存儲(chǔ)轉(zhuǎn)發(fā)消息,在易用性休弃、擴(kuò)展性吞歼、高可用性等方面表現(xiàn)不俗。具體特點(diǎn)包括:

  1. 可靠性(Reliability)
    RabbitMQ 使用一些機(jī)制來(lái)保證可靠性塔猾,如持久化篙骡、傳輸確認(rèn)、發(fā)布確認(rèn)。

  2. 靈活的路由(Flexible Routing)
    在消息進(jìn)入隊(duì)列之前糯俗,通過(guò) Exchange 來(lái)路由消息的尿褪。對(duì)于典型的路由功能,RabbitMQ 已經(jīng)提供了一些內(nèi)置的 Exchange 來(lái)實(shí)現(xiàn)得湘。針對(duì)更復(fù)雜的路由功能杖玲,可以將多個(gè) Exchange 綁定在一起,也通過(guò)插件機(jī)制實(shí)現(xiàn)自己的 Exchange 淘正。

  3. 消息集群(Clustering)
    多個(gè) RabbitMQ 服務(wù)器可以組成一個(gè)集群摆马,形成一個(gè)邏輯 Broker 。

  4. 高可用(Highly Available Queues)
    隊(duì)列可以在集群中的機(jī)器上進(jìn)行鏡像鸿吆,使得在部分節(jié)點(diǎn)出問(wèn)題的情況下隊(duì)列仍然可用囤采。

  5. 多種協(xié)議(Multi-protocol)
    RabbitMQ 支持多種消息隊(duì)列協(xié)議,比如 STOMP惩淳、MQTT 等等蕉毯。

  6. 多語(yǔ)言客戶端(Many Clients)
    RabbitMQ 幾乎支持所有常用語(yǔ)言,比如 Java思犁、.NET代虾、Ruby 等等。

  7. 管理界面(Management UI)
    RabbitMQ 提供了一個(gè)易用的用戶界面激蹲,使得用戶可以監(jiān)控和管理消息 Broker 的許多方面棉磨。

  8. 跟蹤機(jī)制(Tracing)
    如果消息異常,RabbitMQ 提供了消息跟蹤機(jī)制托呕,使用者可以找出發(fā)生了什么含蓉。

  9. 插件機(jī)制(Plugin System)
    RabbitMQ 提供了許多插件,來(lái)從多方面進(jìn)行擴(kuò)展项郊,也可以編寫自己的插件。

RabbitMQ 中的概念模型

消息模型

所有 MQ 產(chǎn)品從模型抽象上來(lái)說(shuō)都是一樣的過(guò)程:
消費(fèi)者(consumer)訂閱某個(gè)隊(duì)列斟赚。生產(chǎn)者(producer)創(chuàng)建消息着降,然后發(fā)布到隊(duì)列(queue)中,最后將消息發(fā)送到監(jiān)聽(tīng)的消費(fèi)者拗军。

image.png
RabbitMQ 基本概念

上面只是最簡(jiǎn)單抽象的描述任洞,具體到 RabbitMQ 則有更詳細(xì)的概念需要解釋。上面介紹過(guò) RabbitMQ 是 AMQP 協(xié)議的一個(gè)開源實(shí)現(xiàn)发侵,所以其內(nèi)部實(shí)際上也是 AMQP 中的基本概念:

image.png
  1. Message
    消息交掏,消息是不具名的,它由消息頭和消息體組成刃鳄。消息體是不透明的盅弛,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對(duì)于其他消息的優(yōu)先權(quán))挪鹏、delivery-mode(指出該消息可能需要持久性存儲(chǔ))等见秽。
  2. Publisher
    消息的生產(chǎn)者,也是一個(gè)向交換器發(fā)布消息的客戶端應(yīng)用程序讨盒。
  3. Exchange
    交換器解取,用來(lái)接收生產(chǎn)者發(fā)送的消息并將這些消息路由給服務(wù)器中的隊(duì)列。
  4. Binding
    綁定返顺,用于消息隊(duì)列和交換器之間的關(guān)聯(lián)禀苦。一個(gè)綁定就是基于路由鍵將交換器和消息隊(duì)列連接起來(lái)的路由規(guī)則,所以可以將交換器理解成一個(gè)由綁定構(gòu)成的路由表遂鹊。
  5. Queue
    消息隊(duì)列伦忠,用來(lái)保存消息直到發(fā)送給消費(fèi)者。它是消息的容器稿辙,也是消息的終點(diǎn)昆码。一個(gè)消息可投入一個(gè)或多個(gè)隊(duì)列。消息一直在隊(duì)列里面邻储,等待消費(fèi)者連接到這個(gè)隊(duì)列將其取走赋咽。
  6. Connection
    網(wǎng)絡(luò)連接,比如一個(gè)TCP連接吨娜。
  7. Channel
    信道脓匿,多路復(fù)用連接中的一條獨(dú)立的雙向數(shù)據(jù)流通道。信道是建立在真實(shí)的TCP連接內(nèi)地虛擬連接宦赠,AMQP 命令都是通過(guò)信道發(fā)出去的陪毡,不管是發(fā)布消息、訂閱隊(duì)列還是接收消息勾扭,這些動(dòng)作都是通過(guò)信道完成毡琉。因?yàn)閷?duì)于操作系統(tǒng)來(lái)說(shuō)建立和銷毀 TCP 都是非常昂貴的開銷,所以引入了信道的概念妙色,以復(fù)用一條 TCP 連接桅滋。
  8. Consumer
    消息的消費(fèi)者,表示一個(gè)從消息隊(duì)列中取得消息的客戶端應(yīng)用程序身辨。
  9. Virtual Host
    虛擬主機(jī)丐谋,表示一批交換器、消息隊(duì)列和相關(guān)對(duì)象煌珊。虛擬主機(jī)是共享相同的身份認(rèn)證和加密環(huán)境的獨(dú)立服務(wù)器域号俐。每個(gè) vhost 本質(zhì)上就是一個(gè) mini 版的 RabbitMQ 服務(wù)器,擁有自己的隊(duì)列定庵、交換器吏饿、綁定和權(quán)限機(jī)制踪危。vhost 是 AMQP 概念的基礎(chǔ),必須在連接時(shí)指定找岖,RabbitMQ 默認(rèn)的 vhost 是 / 陨倡。
  10. Broker
    表示消息隊(duì)列服務(wù)器實(shí)體。
AMQP 中的消息路由

AMQP 中消息的路由過(guò)程和 Java 開發(fā)者熟悉的 JMS 存在一些差別许布,AMQP 中增加了 Exchange 和 Binding 的角色兴革。生產(chǎn)者把消息發(fā)布到 Exchange 上,消息最終到達(dá)隊(duì)列并被消費(fèi)者接收蜜唾,而 Binding 決定交換器的消息應(yīng)該發(fā)送到那個(gè)隊(duì)列杂曲。

image.png
Exchange 類型

Exchange分發(fā)消息時(shí)根據(jù)類型的不同分發(fā)策略有區(qū)別,目前共四種類型:direct袁余、fanout擎勘、topic、headers 颖榜。headers 匹配 AMQP 消息的 header 而不是路由鍵棚饵,此外 headers 交換器和 direct 交換器完全一致,但性能差很多掩完,目前幾乎用不到了噪漾,所以直接看另外三種類型:

  1. direct
image.png
消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致, 交換器就將消息發(fā)到對(duì)應(yīng)的隊(duì)列中且蓬。路由鍵與隊(duì)列名完全匹配欣硼,如果一個(gè)隊(duì)列綁定到交換機(jī)要求路由鍵為“dog”,則只轉(zhuǎn)發(fā) routing key 標(biāo)記為“dog”的消息恶阴,不會(huì)轉(zhuǎn)發(fā)“dog.puppy”诈胜,也不會(huì)轉(zhuǎn)發(fā)“dog.guard”等等。它是完全匹配冯事、單播的模式焦匈。
  1. fanout

    image.png
每個(gè)發(fā)到 fanout 類型交換器的消息都會(huì)分到所有綁定的隊(duì)列上去。fanout 交換器不處理路由鍵桅咆,只是簡(jiǎn)單的將隊(duì)列綁定到交換器上括授,每個(gè)發(fā)送到交換器的消息都會(huì)被轉(zhuǎn)發(fā)到與該交換器綁定的所有隊(duì)列上。很像子網(wǎng)廣播岩饼,每臺(tái)子網(wǎng)內(nèi)的主機(jī)都獲得了一份復(fù)制的消息。fanout 類型轉(zhuǎn)發(fā)消息是最快的薛夜。
  1. topic
image.png
topic 交換器通過(guò)模式匹配分配消息的路由鍵屬性籍茧,將路由鍵和某個(gè)模式進(jìn)行匹配,此時(shí)隊(duì)列需要綁定到一個(gè)模式上梯澜。它將路由鍵和綁定鍵的字符串切分成單詞寞冯,這些單詞之間用點(diǎn)隔開渴析。它同樣也會(huì)識(shí)別兩個(gè)通配符:符號(hào)“#”和符號(hào)“*”。#匹配0個(gè)或多個(gè)單詞吮龄,*匹配不多不少一個(gè)單詞俭茧。

RabbitMQ 安裝

一般來(lái)說(shuō)安裝 RabbitMQ 之前要安裝 Erlang ,可以去Erlang官網(wǎng)下載漓帚。接著去RabbitMQ官網(wǎng)下載安裝包母债,之后解壓縮即可。根據(jù)操作系統(tǒng)不同官網(wǎng)提供了相應(yīng)的安裝說(shuō)明:Windows尝抖、Debian / Ubuntu毡们、RPM-based LinuxMac

如果是Mac 用戶昧辽,個(gè)人推薦使用 HomeBrew 來(lái)安裝衙熔,安裝前要先更新 brew:

brew update

接著安裝 rabbitmq 服務(wù)器:

brew install rabbitmq

這樣 RabbitMQ 就安裝好了,安裝過(guò)程中會(huì)自動(dòng)其所依賴的 Erlang 搅荞。

RabbitMQ 運(yùn)行和管理

  1. 啟動(dòng)
    啟動(dòng)很簡(jiǎn)單红氯,找到安裝后的 RabbitMQ 所在目錄下的 sbin 目錄,可以看到該目錄下有6個(gè)以 rabbitmq 開頭的可執(zhí)行文件咕痛,直接執(zhí)行 rabbitmq-server 即可痢甘,下面將 RabbitMQ 的安裝位置以 . 代替,啟動(dòng)命令就是:
./sbin/rabbitmq-server

啟動(dòng)正常的話會(huì)看到一些啟動(dòng)過(guò)程信息和最后的 completed with 7 plugins暇检,這也說(shuō)明啟動(dòng)的時(shí)候默認(rèn)加載了7個(gè)插件产阱。

[圖片上傳失敗...(image-773384-1537453710252)]

  1. 后臺(tái)啟動(dòng)
    如果想讓 RabbitMQ 以守護(hù)程序的方式在后臺(tái)運(yùn)行,可以在啟動(dòng)的時(shí)候加上 -detached 參數(shù):
./sbin/rabbitmq-server -detached

  1. 查詢服務(wù)器狀態(tài)
    sbin 目錄下有個(gè)特別重要的文件叫 rabbitmqctl 块仆,它提供了 RabbitMQ 管理需要的幾乎一站式解決方案构蹬,絕大部分的運(yùn)維命令它都可以提供。
    查詢 RabbitMQ 服務(wù)器的狀態(tài)信息可以用參數(shù) status :
./sbin/rabbitmqctl status

該命令將輸出服務(wù)器的很多信息悔据,比如 RabbitMQ 和 Erlang 的版本庄敛、OS 名稱、內(nèi)存等等

  1. 關(guān)閉 RabbitMQ 節(jié)點(diǎn)
    我們知道 RabbitMQ 是用 Erlang 語(yǔ)言寫的科汗,在Erlang 中有兩個(gè)概念:節(jié)點(diǎn)和應(yīng)用程序藻烤。節(jié)點(diǎn)就是 Erlang 虛擬機(jī)的每個(gè)實(shí)例,而多個(gè) Erlang 應(yīng)用程序可以運(yùn)行在同一個(gè)節(jié)點(diǎn)之上头滔。節(jié)點(diǎn)之間可以進(jìn)行本地通信(不管他們是不是運(yùn)行在同一臺(tái)服務(wù)器之上)怖亭。比如一個(gè)運(yùn)行在節(jié)點(diǎn)A上的應(yīng)用程序可以調(diào)用節(jié)點(diǎn)B上應(yīng)用程序的方法,就好像調(diào)用本地函數(shù)一樣坤检。如果應(yīng)用程序由于某些原因奔潰兴猩,Erlang 節(jié)點(diǎn)會(huì)自動(dòng)嘗試重啟應(yīng)用程序。
    如果要關(guān)閉整個(gè) RabbitMQ 節(jié)點(diǎn)可以用參數(shù) stop :
./sbin/rabbitmqctl stop

它會(huì)和本地節(jié)點(diǎn)通信并指示其干凈的關(guān)閉早歇,也可以指定關(guān)閉不同的節(jié)點(diǎn)倾芝,包括遠(yuǎn)程節(jié)點(diǎn)讨勤,只需要傳入?yún)?shù) -n :

./sbin/rabbitmqctl -n rabbit@server.example.com stop 

-n node 默認(rèn) node 名稱是 rabbit@server ,如果你的主機(jī)名是 server.example.com 晨另,那么 node 名稱就是 rabbit@server.example.com 潭千。

  1. 關(guān)閉 RabbitMQ 應(yīng)用程序
    如果只想關(guān)閉應(yīng)用程序,同時(shí)保持 Erlang 節(jié)點(diǎn)運(yùn)行則可以用 stop_app:
./sbin/rabbitmqctl stop_app

這個(gè)命令在后面要講的集群模式中將會(huì)很有用借尿。

  1. 啟動(dòng) RabbitMQ 應(yīng)用程序
./sbin/rabbitmqctl start_app

  1. 重置 RabbitMQ 節(jié)點(diǎn)
./sbin/rabbitmqctl reset

該命令將清除所有的隊(duì)列刨晴。

  1. 查看已聲明的隊(duì)列
./sbin/rabbitmqctl list_queues

  1. 查看交換器
./sbin/rabbitmqctl list_exchanges

該命令還可以附加參數(shù),比如列出交換器的名稱垛玻、類型割捅、是否持久化、是否自動(dòng)刪除:

./sbin/rabbitmqctl list_exchanges name type durable auto_delete

  1. 查看綁定
./sbin/rabbitmqctl list_bindings

Java 客戶端訪問(wèn)

RabbitMQ 支持多種語(yǔ)言訪問(wèn)帚桩,以 Java 為例看下一般使用 RabbitMQ 的步驟亿驾。

  1. maven工程的pom文件中添加依賴
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>4.1.0</version>
</dependency>

  1. 消息生產(chǎn)者
package org.study.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {
        //創(chuàng)建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        factory.setUsername("guest");
        factory.setPassword("guest");
        //設(shè)置 RabbitMQ 地址
        factory.setHost("localhost");
        //建立到代理服務(wù)器到連接
        Connection conn = factory.newConnection();
        //獲得信道
        Channel channel = conn.createChannel();
        //聲明交換器
        String exchangeName = "hello-exchange";
        channel.exchangeDeclare(exchangeName, "direct", true);

        String routingKey = "hola";
        //發(fā)布消息
        byte[] messageBodyBytes = "quit".getBytes();
        channel.basicPublish(exchangeName, routingKey, null, messageBodyBytes);

        channel.close();
        conn.close();
    }
}

  1. 消息消費(fèi)者
package org.study.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setUsername("guest");
        factory.setPassword("guest");
        factory.setHost("localhost");
        //建立到代理服務(wù)器到連接
        Connection conn = factory.newConnection();
        //獲得信道
        final Channel channel = conn.createChannel();
        //聲明交換器
        String exchangeName = "hello-exchange";
        channel.exchangeDeclare(exchangeName, "direct", true);
        //聲明隊(duì)列
        String queueName = channel.queueDeclare().getQueue();
        String routingKey = "hola";
        //綁定隊(duì)列,通過(guò)鍵 hola 將隊(duì)列和交換器綁定起來(lái)
        channel.queueBind(queueName, exchangeName, routingKey);

        while(true) {
            //消費(fèi)消息
            boolean autoAck = false;
            String consumerTag = "";
            channel.basicConsume(queueName, autoAck, consumerTag, new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag,
                                           Envelope envelope,
                                           AMQP.BasicProperties properties,
                                           byte[] body) throws IOException {
                    String routingKey = envelope.getRoutingKey();
                    String contentType = properties.getContentType();
                    System.out.println("消費(fèi)的路由鍵:" + routingKey);
                    System.out.println("消費(fèi)的內(nèi)容類型:" + contentType);
                    long deliveryTag = envelope.getDeliveryTag();
                    //確認(rèn)消息
                    channel.basicAck(deliveryTag, false);
                    System.out.println("消費(fèi)的消息體內(nèi)容:");
                    String bodyStr = new String(body, "UTF-8");
                    System.out.println(bodyStr);

                }
            });
        }
    }
}

  1. 啟動(dòng) RabbitMQ 服務(wù)器
./sbin/rabbitmq-server

  1. 運(yùn)行 Consumer
    先運(yùn)行 Consumer 账嚎,這樣當(dāng)生產(chǎn)者發(fā)送消息的時(shí)候能在消費(fèi)者后端看到消息記錄莫瞬。

  2. 運(yùn)行 Producer
    接著運(yùn)行 Producer ,發(fā)布一條消息,在 Consumer 的控制臺(tái)能看到接收的消息:

    image.png

RabbitMQ 集群

RabbitMQ 最優(yōu)秀的功能之一就是內(nèi)建集群郭蕉,這個(gè)功能設(shè)計(jì)的目的是允許消費(fèi)者和生產(chǎn)者在節(jié)點(diǎn)崩潰的情況下繼續(xù)運(yùn)行疼邀,以及通過(guò)添加更多的節(jié)點(diǎn)來(lái)線性擴(kuò)展消息通信吞吐量。RabbitMQ 內(nèi)部利用 Erlang 提供的分布式通信框架 OTP 來(lái)滿足上述需求召锈,使客戶端在失去一個(gè) RabbitMQ 節(jié)點(diǎn)連接的情況下旁振,還是能夠重新連接到集群中的任何其他節(jié)點(diǎn)繼續(xù)生產(chǎn)、消費(fèi)消息涨岁。

RabbitMQ 集群中的一些概念

RabbitMQ 會(huì)始終記錄以下四種類型的內(nèi)部元數(shù)據(jù):

  1. 隊(duì)列元數(shù)據(jù)
    包括隊(duì)列名稱和它們的屬性拐袜,比如是否可持久化,是否自動(dòng)刪除
  2. 交換器元數(shù)據(jù)
    交換器名稱梢薪、類型蹬铺、屬性
  3. 綁定元數(shù)據(jù)
    內(nèi)部是一張表格記錄如何將消息路由到隊(duì)列
  4. vhost 元數(shù)據(jù)
    為 vhost 內(nèi)部的隊(duì)列、交換器秉撇、綁定提供命名空間和安全屬性

在單一節(jié)點(diǎn)中甜攀,RabbitMQ 會(huì)將所有這些信息存儲(chǔ)在內(nèi)存中,同時(shí)將標(biāo)記為可持久化的隊(duì)列琐馆、交換器规阀、綁定存儲(chǔ)到硬盤上。存到硬盤上可以確保隊(duì)列和交換器在節(jié)點(diǎn)重啟后能夠重建瘦麸。而在集群模式下同樣也提供兩種選擇:存到硬盤上(獨(dú)立節(jié)點(diǎn)的默認(rèn)設(shè)置)姥敛,存在內(nèi)存中。

如果在集群中創(chuàng)建隊(duì)列瞎暑,集群只會(huì)在單個(gè)節(jié)點(diǎn)而不是所有節(jié)點(diǎn)上創(chuàng)建完整的隊(duì)列信息(元數(shù)據(jù)彤敛、狀態(tài)、內(nèi)容)了赌。結(jié)果是只有隊(duì)列的所有者節(jié)點(diǎn)知道有關(guān)隊(duì)列的所有信息墨榄,因此當(dāng)集群節(jié)點(diǎn)崩潰時(shí),該節(jié)點(diǎn)的隊(duì)列和綁定就消失了勿她,并且任何匹配該隊(duì)列的綁定的新消息也丟失了袄秩。還好RabbitMQ 2.6.0之后提供了鏡像隊(duì)列以避免集群節(jié)點(diǎn)故障導(dǎo)致的隊(duì)列內(nèi)容不可用。

RabbitMQ 集群中可以共享 user逢并、vhost之剧、exchange等,所有的數(shù)據(jù)和狀態(tài)都是必須在所有節(jié)點(diǎn)上復(fù)制的砍聊,例外就是上面所說(shuō)的消息隊(duì)列背稼。RabbitMQ 節(jié)點(diǎn)可以動(dòng)態(tài)的加入到集群中。

當(dāng)在集群中聲明隊(duì)列玻蝌、交換器蟹肘、綁定的時(shí)候,這些操作會(huì)直到所有集群節(jié)點(diǎn)都成功提交元數(shù)據(jù)變更后才返回俯树。集群中有內(nèi)存節(jié)點(diǎn)和磁盤節(jié)點(diǎn)兩種類型帘腹,內(nèi)存節(jié)點(diǎn)雖然不寫入磁盤,但是它的執(zhí)行比磁盤節(jié)點(diǎn)要好许饿。內(nèi)存節(jié)點(diǎn)可以提供出色的性能阳欲,磁盤節(jié)點(diǎn)能保障配置信息在節(jié)點(diǎn)重啟后仍然可用,那集群中如何平衡這兩者呢陋率?

RabbitMQ 只要求集群中至少有一個(gè)磁盤節(jié)點(diǎn)球化,所有其他節(jié)點(diǎn)可以是內(nèi)存節(jié)點(diǎn),當(dāng)節(jié)點(diǎn)加入火離開集群時(shí)翘贮,它們必須要將該變更通知到至少一個(gè)磁盤節(jié)點(diǎn)赊窥。如果只有一個(gè)磁盤節(jié)點(diǎn),剛好又是該節(jié)點(diǎn)崩潰了狸页,那么集群可以繼續(xù)路由消息锨能,但不能創(chuàng)建隊(duì)列、創(chuàng)建交換器芍耘、創(chuàng)建綁定址遇、添加用戶、更改權(quán)限斋竞、添加或刪除集群節(jié)點(diǎn)倔约。換句話說(shuō)集群中的唯一磁盤節(jié)點(diǎn)崩潰的話,集群仍然可以運(yùn)行坝初,但知道該節(jié)點(diǎn)恢復(fù)浸剩,否則無(wú)法更改任何東西钾军。

RabbitMQ 集群配置和啟動(dòng)

如果是在一臺(tái)機(jī)器上同時(shí)啟動(dòng)多個(gè) RabbitMQ 節(jié)點(diǎn)來(lái)組建集群的話,只用上面介紹的方式啟動(dòng)第二绢要、第三個(gè)節(jié)點(diǎn)將會(huì)因?yàn)楣?jié)點(diǎn)名稱和端口沖突導(dǎo)致啟動(dòng)失敗吏恭。所以在每次調(diào)用 rabbitmq-server 命令前,設(shè)置環(huán)境變量 RABBITMQ_NODENAME 和 RABBITMQ_NODE_PORT 來(lái)明確指定唯一的節(jié)點(diǎn)名稱和端口重罪。下面的例子端口號(hào)從5672開始樱哼,每個(gè)新啟動(dòng)的節(jié)點(diǎn)都加1,節(jié)點(diǎn)也分別命名為test_rabbit_1剿配、test_rabbit_2搅幅、test_rabbit_3。

啟動(dòng)第1個(gè)節(jié)點(diǎn):

RABBITMQ_NODENAME=test_rabbit_1 RABBITMQ_NODE_PORT=5672 ./sbin/rabbitmq-server -detached

啟動(dòng)第2個(gè)節(jié)點(diǎn):

RABBITMQ_NODENAME=test_rabbit_2 RABBITMQ_NODE_PORT=5673 ./sbin/rabbitmq-server -detached

啟動(dòng)第2個(gè)節(jié)點(diǎn)前建議將 RabbitMQ 默認(rèn)激活的插件關(guān)掉呼胚,否則會(huì)存在使用了某個(gè)插件的端口號(hào)沖突茄唐,導(dǎo)致節(jié)點(diǎn)啟動(dòng)不成功。

現(xiàn)在第2個(gè)節(jié)點(diǎn)和第1個(gè)節(jié)點(diǎn)都是獨(dú)立節(jié)點(diǎn)砸讳,它們并不知道其他節(jié)點(diǎn)的存在琢融。集群中除第一個(gè)節(jié)點(diǎn)外后加入的節(jié)點(diǎn)需要獲取集群中的元數(shù)據(jù),所以要先停止 Erlang 節(jié)點(diǎn)上運(yùn)行的 RabbitMQ 應(yīng)用程序簿寂,并重置該節(jié)點(diǎn)元數(shù)據(jù)漾抬,再加入并且獲取集群的元數(shù)據(jù),最后重新啟動(dòng) RabbitMQ 應(yīng)用程序常遂。

停止第2個(gè)節(jié)點(diǎn)的應(yīng)用程序:

./sbin/rabbitmqctl -n test_rabbit_2 stop_app

重置第2個(gè)節(jié)點(diǎn)元數(shù)據(jù):

./sbin/rabbitmqctl -n test_rabbit_2 reset

第2節(jié)點(diǎn)加入第1個(gè)節(jié)點(diǎn)組成的集群:

./sbin/rabbitmqctl -n test_rabbit_2 join_cluster test_rabbit_1@localhost

啟動(dòng)第2個(gè)節(jié)點(diǎn)的應(yīng)用程序

./sbin/rabbitmqctl -n test_rabbit_2 start_app

第3個(gè)節(jié)點(diǎn)的配置過(guò)程和第2個(gè)節(jié)點(diǎn)類似:

RABBITMQ_NODENAME=test_rabbit_3 RABBITMQ_NODE_PORT=5674 ./sbin/rabbitmq-server -detached

./sbin/rabbitmqctl -n test_rabbit_3 stop_app

./sbin/rabbitmqctl -n test_rabbit_3 reset

./sbin/rabbitmqctl -n test_rabbit_3 join_cluster test_rabbit_1@localhost

./sbin/rabbitmqctl -n test_rabbit_3 start_app

RabbitMQ 集群運(yùn)維

停止某個(gè)指定的節(jié)點(diǎn)纳令,比如停止第2個(gè)節(jié)點(diǎn):

RABBITMQ_NODENAME=test_rabbit_2 ./sbin/rabbitmqctl stop

查看節(jié)點(diǎn)3的集群狀態(tài):

./sbin/rabbitmqctl -n test_rabbit_3 cluster_status
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市克胳,隨后出現(xiàn)的幾起案子平绩,更是在濱河造成了極大的恐慌,老刑警劉巖漠另,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捏雌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡笆搓,警方通過(guò)查閱死者的電腦和手機(jī)性湿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)满败,“玉大人肤频,你說(shuō)我怎么就攤上這事∷隳” “怎么了宵荒?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我报咳,道長(zhǎng)侠讯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任少孝,我火速辦了婚禮继低,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稍走。我一直安慰自己,他們只是感情好柴底,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布婿脸。 她就那樣靜靜地躺著,像睡著了一般柄驻。 火紅的嫁衣襯著肌膚如雪狐树。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天鸿脓,我揣著相機(jī)與錄音抑钟,去河邊找鬼。 笑死野哭,一個(gè)胖子當(dāng)著我的面吹牛在塔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拨黔,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蛔溃,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了篱蝇?” 一聲冷哼從身側(cè)響起贺待,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎零截,沒(méi)想到半個(gè)月后麸塞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涧衙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年哪工,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绍撞。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡正勒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出傻铣,到底是詐尸還是另有隱情章贞,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站鸭限,受9級(jí)特大地震影響蜕径,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜败京,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一兜喻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赡麦,春花似錦朴皆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至晶姊,卻和暖如春扒接,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背们衙。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工钾怔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蒙挑。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓宗侦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親脆荷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凝垛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 關(guān)于消息隊(duì)列,從前年開始斷斷續(xù)續(xù)看了些資料蜓谋,想寫很久了梦皮,但一直沒(méi)騰出空,近來(lái)分別碰到幾個(gè)朋友聊這塊的技術(shù)選型桃焕,是時(shí)...
    預(yù)流閱讀 584,647評(píng)論 51 786
  • 簡(jiǎn)介: MQ全稱為Message Queue, 消息隊(duì)列(MQ)是一種應(yīng)用程序?qū)?yīng)用程序的通信方法剑肯。應(yīng)用程序通過(guò)讀...
    黑客和白帽子的故事閱讀 833評(píng)論 0 0
  • 利用RabbitMQ集群橫向擴(kuò)展能力,均衡流量壓力观堂,讓消息集群的秒級(jí)服務(wù)能力達(dá)到百萬(wàn)让网,Google曾做過(guò)此類實(shí)驗(yàn);...
    有貨技術(shù)閱讀 3,463評(píng)論 0 1
  • rabbitMQ是一款基于AMQP協(xié)議的消息中間件师痕,它能夠在應(yīng)用之間提供可靠的消息傳輸溃睹。在易用性,擴(kuò)展性胰坟,高可用性...
    點(diǎn)融黑幫閱讀 2,997評(píng)論 3 41
  • 時(shí)間是種不可復(fù)制的東西因篇,浪費(fèi)了就沒(méi)有了,看著即將老去的父母,和越來(lái)越大的孩子竞滓,把時(shí)間浪費(fèi)掉這樣真的好嗎8篮稹? 每天在...
    李子_3bfc閱讀 398評(píng)論 0 0