使用 docker-compose 部署多機(jī) RabbitMQ 集群

本文介紹 RabbitMQ 集群的 Docker 化部署,最開始是想通過(guò) DockerSwarm 方式來(lái)部署的,但是 RabbitMQ 節(jié)點(diǎn)加入集群時(shí)一直失敗,在網(wǎng)上找了很多辦法,始終沒有解決這個(gè)問題,無(wú)奈只能放棄。所以最終采用配置 hosts 文件方式來(lái)保證節(jié)點(diǎn)之間的通信,下面來(lái)進(jìn)行詳細(xì)說(shuō)明。

部署環(huán)境

  • 系統(tǒng):CentOS8
  • 兩臺(tái)服務(wù)器:10.1.1.1/10.1.1.2

docker-compose 文件

version: '3'

services:
  rabbit1:
    container_name: rabbit1
    image: rabbitmq:3.7-management-alpine
    restart: always
    hostname: rabbit1
    extra_hosts:
      - "rabbit1:10.1.1.1"
      - "rabbit2:10.1.1.2"
    environment:
      - RABBITMQ_ERLANG_COOKIE=MY_COOKIE
      - RABBITMQ_DEFAULT_USER=MY_USER
      - RABBITMQ_DEFAULT_PASS=MY_PASS
    ports:
      - "4369:4369"
      - "5671:5671"
      - "5672:5672"
      - "15671:15671"
      - "15672:15672"
      - "25672:25672"

這樣,10.1.1.1 上的 docker-compose 文件就寫好了,部署另一臺(tái)時(shí),只要將 rabbit1 改成 rabbit2 就可以了。如果是更多臺(tái)服務(wù)器的話,也是同樣的道理,將 IP 配置到 extra_hosts 參數(shù)下即可。

啟動(dòng)服務(wù)

在兩臺(tái)服務(wù)器上分別執(zhí)行:

# docker-compose up -d

加入集群

如果將 rabbit1 作為主節(jié)點(diǎn)的話,需要在 rabbit2 上執(zhí)行命令,將其加入到集群,如下:

# docker exec -it rabbit2 /bin/bash

rabbit2# rabbitmqctl stop_app
rabbit2# rabbitmqctl reset
rabbit2# rabbitmqctl join_cluster rabbit@rabbit1
rabbit2# rabbitmqctl start_app

默認(rèn)情況下,RabbitMQ 啟動(dòng)后是磁盤節(jié)點(diǎn),如果想以內(nèi)存節(jié)點(diǎn)方式加入,可以加 --ram 參數(shù)。

如果想要修改節(jié)點(diǎn)類型,可以使用命令:

# rabbitmqctl change_cluster_node_type disc(ram)

修改節(jié)點(diǎn)類型之前需要先 rabbitmqctl stop_app。

通過(guò)下面命令來(lái)查看集群狀態(tài):

# rabbitmqctl cluster_status

注意,由于 RAM 節(jié)點(diǎn)僅將內(nèi)部數(shù)據(jù)庫(kù)表存儲(chǔ)在內(nèi)存中,因此在內(nèi)存節(jié)點(diǎn)啟動(dòng)時(shí)必須從其他節(jié)點(diǎn)同步這些數(shù)據(jù),所以一個(gè)集群必須至少包含一個(gè)磁盤節(jié)點(diǎn)。

HAProxy 負(fù)載均衡

ha 同樣采用 Docker 方式來(lái)部署,先看一下 haproxy.cfg 配置文件:

# Simple configuration for an HTTP proxy listening on port 80 on all
# interfaces and forwarding requests to a single backend "servers" with a
# single server "server1" listening on 127.0.0.1:8000

global
    daemon
    maxconn 256

defaults
    mode http
    timeout connect 5000ms
    timeout client 5000ms
    timeout server 5000ms

listen rabbitmq_cluster
    bind 0.0.0.0:5677
    option tcplog
    mode tcp
    balance leastconn
    server  rabbit1 10.1.1.1:5672 weight 1 check inter 2s rise 2 fall 3
    server  rabbit2 10.2.2.2:5672 weight 1 check inter 2s rise 2 fall 3

listen http_front
    bind 0.0.0.0:8002
    stats uri /haproxy?stats

listen rabbitmq_admin
    bind 0.0.0.0:8001
    server rabbit1 10.1.1.1:15672
    server rabbit2 10.1.1.2:15672

再看一下 docker-compose 文件:

version: '3'

services:
  haproxy:
    container_name: rabbit-haproxy
    image: haproxy
    restart: always
    hostname: haproxy
    network_mode: rabbitmq_default
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    ports:
      - "5677:5677"
      - "8001:8001"
      - "8002:8002"

啟動(dòng)之后,就可以通過(guò) ha 的地址來(lái)訪問 RabbitMQ 集群管理頁(yè)面了。

如果公司內(nèi)部有現(xiàn)成的負(fù)載均衡,比如 LVS,那么也可以省略這一步。

其實(shí)到這里,集群就可以正常使用了,但還有很重要的一點(diǎn)需要做些說(shuō)明。

集群模式

普通模式

  • 對(duì)于 Queue 來(lái)說(shuō),消息實(shí)體只存在于其中一個(gè)節(jié)點(diǎn),A、B 兩個(gè)節(jié)點(diǎn)僅有相同的元數(shù)據(jù),即隊(duì)列結(jié)構(gòu)。
  • 當(dāng)消息進(jìn)入 A 節(jié)點(diǎn)的隊(duì)列中后,消費(fèi)者從 B 節(jié)點(diǎn)拉取時(shí),RabbitMQ 會(huì)臨時(shí)在 A、B 間進(jìn)行消息傳輸,把 A 中的消息實(shí)體取出并經(jīng)過(guò) B 發(fā)送給消費(fèi)者。
  • 所以,消費(fèi)者應(yīng)盡量連接每一個(gè)節(jié)點(diǎn),從中取消息。即對(duì)于同一個(gè)邏輯隊(duì)列,要在多個(gè)節(jié)點(diǎn)建立物理隊(duì)列,否則,無(wú)論消費(fèi)者連 A 或者連 B,出口總在 A,會(huì)產(chǎn)生瓶頸。
  • 該模式還存在一個(gè)問題就是當(dāng) A 節(jié)點(diǎn)故障后,B 節(jié)點(diǎn)無(wú)法取到 A 節(jié)點(diǎn)中還未消費(fèi)的消息實(shí)體。
  • 如果做了消息持久化,那么得等 A 節(jié)點(diǎn)恢復(fù),才可被消費(fèi);如果沒有持久化的話,消息會(huì)丟失。

鏡像模式

  • 該模式解決了上述問題,其和普通模式不同之處在于,消息實(shí)體會(huì)主動(dòng)在鏡像節(jié)點(diǎn)間同步,而不是在消費(fèi)者取數(shù)據(jù)時(shí)臨時(shí)拉取。
  • 該模式帶來(lái)的副作用也很明顯,除了降低系統(tǒng)性能外,如果鏡像隊(duì)列數(shù)量過(guò)多,加之大量的消息進(jìn)入,集群內(nèi)部的網(wǎng)絡(luò)帶寬將會(huì)被這種同步通訊大大消耗掉。
  • 所以,在對(duì)可靠性要求較高的場(chǎng)合中適用于該模式。

個(gè)人感覺,在生產(chǎn)環(huán)境中,還是使用鏡像模式比較保險(xiǎn)。

要想使用鏡像模式,不管是通過(guò)管理頁(yè)面,還是命令行方式,只需要簡(jiǎn)單配置即可完成。管理頁(yè)面方式就不過(guò)多介紹了,下面說(shuō)說(shuō)如何通過(guò)命令行來(lái)設(shè)置,一條命令就搞定。

添加:

# rabbitmqctl set_policy -p testvhost testha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
Setting policy "testha" for pattern "^" to "{"ha-mode":"all","ha-sync-mode":"automatic"}" with priority "0" for vhost "testvhost" ...

清除:

# rabbitmqctl clear_policy -p testvhost testha
Clearing policy "testha" on vhost "testvhost" ...

查看:

# rabbitmqctl list_policies -p testvhost
Listing policies for vhost "testvhost" ...
vhost   name    pattern apply-to        definition      priority
testvhost       testha  ^       all     {"ha-mode":"all","ha-sync-mode":"automatic"}    0

參數(shù)說(shuō)明:

  • Virtual host:策略應(yīng)用的 vhost。

  • Name:為策略名稱,可以是任何名稱,但建議使用不帶空格的基于 ASCII 的名稱。

  • Pattern:與一個(gè)或多個(gè) queue(exchange) 名稱匹配的正則表達(dá)式,可以使用任何正則表達(dá)式。只有一個(gè) ^ 代表匹配所有,^test 為匹配名稱為 "test" 的 exchanges 或者 queue。

  • Apply to:Pattern 應(yīng)用對(duì)象。

  • Priority:配置多個(gè)策略時(shí)的優(yōu)先級(jí),值越大,優(yōu)先級(jí)越高。沒有指定優(yōu)先級(jí)的消息會(huì)以 0 優(yōu)先級(jí)對(duì)待,對(duì)于超過(guò)隊(duì)列所定最大優(yōu)先級(jí)的消息,優(yōu)先級(jí)以最大優(yōu)先級(jí)對(duì)待。

  • Definition:鍵/值對(duì),將被插入匹配 queues and exchanges 的可選參數(shù)映射中。

    ha-mode:策略鍵,分為 3 種模式:

    • all :所有的 queue。
    • exctly :部分(需配置 ha-params 參數(shù),此參數(shù)為 int 類型。比如 3,眾多集群中的隨機(jī) 3 臺(tái)機(jī)器)。
    • nodes :指定(需配置 ha-params 參數(shù),此參數(shù)為數(shù)組類型。比如 ["rabbit@rabbit2", "rabbit@rabbit3"] 這樣指定為 rabbit2 與 rabbit3 這兩臺(tái)機(jī)器)。

    ha-sync-mode:隊(duì)列同步:

    • manual:手動(dòng)(默認(rèn)模式)。新的隊(duì)列鏡像將不會(huì)收到現(xiàn)有的消息,它只會(huì)接收新的消息。
    • automatic:自動(dòng)同步。當(dāng)一個(gè)新鏡像加入時(shí),隊(duì)列會(huì)自動(dòng)同步。隊(duì)列同步是一個(gè)阻塞操作。

以上就是本篇全部?jī)?nèi)容,歡迎大家留言交流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容