RabbitMQ高可用之鏡像隊列和實戰應用篇

部署單節點

Erlang: v22+
rabbitmq: v3.7.15
windows

  • http://erlang.org/download/otp_win64_22.0.exe

  • https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.15/rabbitmq-server-3.7.15.exe

linux

  • wget https://github.com/rabbitmq/erlang-rpm/releases/download/v21.3.8.3/erlang-21.3.8.3-1.el7.x86_64.rpm

  • wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.15/rabbitmq-server-3.7.15-1.el7.noarch.rpm

yum install -y erlang-21.3.8.3-1.el7.x86_64.rpm

yum install -y rabbitmq-server-3.7.15-1.el7.noarch.rpm

安裝

node1(種子節點)在windows安裝並且啓動
node2 在centerOS7安裝並且啓動

rabbit1 rabbit2需要在各環境配置好hosts(即主機名和ip的映射),用於集羣服務發現

配置文件

支持2種風格格式,後綴.conf(key=value) .config([].)

Generic UNIX: $RABBITMQ_HOME/etc/rabbitmq/
Debian: /etc/rabbitmq/
RPM: /etc/rabbitmq/
Mac OS (Homebrew): ${install_prefix}/etc/rabbitmq/, the Homebrew cellar prefix is usually /usr/local
Windows: %APPDATA%\RabbitMQ\

通過環境變量重寫配置文件位置
RABBITMQ_CONFIG_FILE

開啓web管理後臺

rabbitmq-plugins enable rabbitmq_management
訪問地址127.0.0.1:15672
username:guest
password:guset

添加自定義用戶

默認guest只能訪問127.0.0.1,或者關閉限制,在config中調整屬性爲loopback_users.guest = false

centerOS7防火牆配置

firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --reload

cookie文件內容保持一致

把其中一個拷貝過去,保證一樣,不然在加入集羣時報錯:連接成功但是認證失敗

C:\Windows\System32\config\systemprofile.erlang.cookie

/var/lib/rabbitmq/.erlang.cookie

登錄待入集羣節點

# on rabbit2 
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit2 ...done.

rabbitmqctl reset
# => Resetting node rabbit@rabbit2 ...

rabbitmqctl join_cluster rabbit@rabbit1
# => Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.

rabbitmqctl start_app
# => Starting node rabbit@rabbit2 ...done.

驗證集羣狀態

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
# => ...done.

至此,普通集羣搭建完成。所有發佈的消息,權限信息都會自動同步到集羣的任意節點。

  • 主節點監控信息(種子節點)
    在這裏插入圖片描述
  • 集羣節點(非種子節點)
    在這裏插入圖片描述

普通集羣缺點

主節點的不可用時,分支節點的隊列也不可用。
因爲普通集羣任意一個節點在收到publish消息時,會轉發到home節點(創建隊列的節點)進行操作(投遞,消費,創建等),分支節點只有隊列的元數據,沒有實際存儲和投遞的功能。

高可用隊列

在這裏插入圖片描述

  • 綠色隊列由於增加了ha策略,所以具備了主從複製+選主的特性。遵循CP原則,強一致性

  • 紅色隊列是普通隊列。只有owner(創建隊列的節點也叫home
    node)能收發、持久消息。即使路由到非owner也會被locate回owner節點。並且owner一旦宕機,非owner節點隊列也會失效(不能收發消息)

  • 每個rabbitMQ Server節點都是對等的,主從的概念是相對queue而言的

可以通過策略給指定隊列建立鏡像,達到主從複製的目的,同時有自動選主(一旦主不可用,會選擇集羣的其他節點的鏡像隊列爲master)的功能。
解決了上述普通隊列集羣的問題。
在這裏插入圖片描述
在這裏插入圖片描述

內存節點

默認都是磁盤節點,可以通過cmd手工更新。
RAM節點只將元數據保存在內存中。由於RAM節點不必像磁盤節點那樣向磁盤寫入數據,因此它們可以執行得更好。但是,請注意,由於持久隊列數據總是存儲在磁盤上,因此性能改進只會影響資源管理(例如,添加/刪除隊列、交換或vhosts),而不會影響發佈或消耗速度。

RAM節點是一個高級用例;在設置第一個集羣時,您不應該使用它們。您應該有足夠的磁盤節點來處理您的冗餘需求,然後在必要時爲擴展添加額外的RAM節點。

只包含RAM節點的集羣是脆弱的;如果集羣停止,您將無法再次啓動它,並且將丟失所有數據。rabbitmq在許多情況下都會阻止只創建RAM節點集羣,但它不能絕對阻止。

分區問題

集羣節點分散在2個網絡中,A網(node1,node2,node3),B網(node4,node5,node6)。
AB通過交換機互聯,一旦AB網絡不通,由於rabbitmq默認60s健康檢測,勢必導致2個子網分裂爲2個集羣,各自選主,引發了腦裂問題。

Network partition

節點之間認爲對方宕機是建立在互相不能聯繫的固定週期上的,默認是60s。同時會在運行節點上剔除故障節點,即使恢復聯繫後,依然認爲對方是宕機的,所以這時會產生分區。換句話說,一個集羣分裂爲多個了,鏡像隊列會去各自選主,這就是腦裂。

Nodes determine if its peer is down if another node is unable to contact it for a period of time, 60 seconds by default. If two nodes come back into contact, both having thought the other is down, the nodes will determine that a partition has occurred.

Recovering From a Split-Brain
從腦裂中恢復,第一步選擇一個信任的節點,換句話說這個決定是非常重要的;
任何在其他分區上的改變會造成數據丟失。

To recover from a split-brain, first choose one partition which you trust the most. This partition will become the authority for the state of the system (schema, messages) to use; any changes which have occurred on other partitions will be lost.
Stop all nodes in the other partitions, then start them all up again. When they rejoin the cluster they will restore state from the trusted partition.

分區策略

  • ignore
  • pause_minority
  • pause_if_all_down
  • autoheal

假設是3:3的集羣(換句話說,分區數量對等–> A(a,b,c),B(c,d,f) )
如果使用pause_minority,會導致全部不可用,因爲沒有少數派。

建議使用的策略配置:

loopback_users.guest = false

cluster_partition_handling = pause_if_all_down

## Recovery strategy. Can be either 'autoheal' or 'ignore'
cluster_partition_handling.pause_if_all_down.recover = ignore

## Node names to check,每個分區選一個代表,如果都故障,則暫停
cluster_partition_handling.pause_if_all_down.nodes.1 = rabbit@DEV-b
cluster_partition_handling.pause_if_all_down.nodes.2 = rabbit@DEV-d

監控集羣

  • Web-Managementi-UI
  • http API
  • cmd

java客戶端接入

amqp-client v4.0.3

single node

ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
factory.setAutomaticRecoveryEnabled(true);
// connection that will recover automatically
Connection conn = factory.newConnection();

cluster

ConnectionFactory factory = new ConnectionFactory();

Address[] addresses = {new Address("192.168.1.4"), new Address("192.168.1.5")};
factory.newConnection(addresses);

spring mvc

maven dependency

		<dependency>
			<groupId>org.springframework.amqp</groupId>
			<artifactId>spring-rabbit</artifactId>
			<version>1.7.6.RELEASE</version>
		</dependency>

xml conf

http://www.springframework.org/schema/rabbit/spring-rabbit-1.7.xsd
<rabbit:connection-factory id="connectionFactory" addresses="${mq.hosts}" 
username="${mq.username}" password="${mq.password}"/>

spring boot

maven dependency

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>

application.properties

spring.rabbitmq.addresses=192.168.103.34:5672,192.168.73.129:5672

Auto recovery

在這裏插入圖片描述

  • 客戶端在啓動時默認選擇一個最優節點建立連接鏈路。
  • 一旦節點故障(如離線/宕機),則進行嘗試連接第二個節點,以此類推。
  • Java rabbitmqClient版本需要4.0+
  • spring AMQP建議用spring的client recovery機制(基本上和第三點類似,因爲spring的恢復機制比rabbitMQclient先推出),版本1.7.6+

參考資料:
https://github.com/spring-projects/spring-amqp/issues/1029
https://github.com/rabbitmq/rabbitmq-java-client/issues/138
https://github.com/rabbitmq/rabbitmq-java-client/issues/153
https://github.com/rabbitmq/rabbitmq-java-client/pull/169
https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/195

Idempotence

冪等性

所有投遞的消息必須有一個與業務無關的id(分佈式id生成策略保證)。
舉例:給這個id建立唯一索引列,在插入數據報duplicate key異常時,直接確認,不執行業務邏輯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章