一文帶你入門RabbitMQ消息隊列
基礎概念
什么是消息隊列
消息隊列是一種用于在應用程序之間傳遞消息的通信方式,消息隊列允許應用程序異步的發送和接收消息,并且不需要直接連接到對方。
消息指的是兩個應用間傳遞的數據。數據的類型有很多種形式,可能只包含文本字符串,也可能包含嵌入對象。
隊列指的是存儲數據的介質,遵循先進先出的規則。
圖片
為什么使用消息隊列
解耦
在傳統模式下,假設新增物流系統模塊,則需要訂單系統新增調用物流系統的代碼邏輯。假設庫存系統異常,訂單系統調用出錯,會導致整個服務不可用。為了降低這種強耦合,就可以使用MQ,系統訂單系統只需要把數據發送到MQ,其他系統如果需要數據,則從MQ中獲取即可。
- 傳統模式
圖片
畫板
- 消息隊列模式
畫板
異步
如圖所示。進行用戶注冊時,會進行寫入數據庫、發送郵件、發送短信操作。同步請求的話,響應時間就是所有操作步驟時間的總和,也就是1s。如果使用MQ,用戶模塊發送數據到MQ,然后就可以返回響應給客戶端,不需要再等待系統其他操作的響應,可以大大地提高性能。對于一些非必要的業務,比如發送短信,發送郵件等等,就可以采用MQ。
- 傳統模式
畫板
- 消息隊列模式
畫板
削峰
假設系統A在某一段時間請求數暴增,有5000個請求發送過來,系統A這時就會發送5000條SQL進入MySQL進行執行,MySQL對于如此龐大的請求當然處理不過來,MySQL就會崩潰,導致系統癱瘓。如果使用MQ,系統A不再是直接發送SQL到數據庫,而是把數據發送到MQ,MQ短時間積壓數據是可以接受的,然后由消費者每次拉取2000條進行處理,防止在請求峰值時期大量的請求直接發送到MySQL導致系統崩潰。
- 傳統模式
畫板
- 消息隊列模式
畫板
RabbitMQ的特點
RabbitMQ是一款使用Erlang語言開發的,實現AMQP(高級消息隊列協議)的開源消息中間件。
- 可靠性。支持持久化,傳輸確認,發布確認等保證了MQ的可靠性。
- 靈活的分發消息策略。這應該是RabbitMQ的一大特點。在消息進入MQ前由Exchange(交換機)進行路由消息。分發消息策略有:簡單模式、工作隊列模式、發布訂閱模式、路由模式、通配符模式。
- 支持集群。多臺RabbitMQ服務器可以組成一個集群,形成一個邏輯Broker。
- 多種協議。RabbitMQ支持多種消息隊列協議,比如 STOMP、MQTT 等等。
- 支持多種語言客戶端。RabbitMQ幾乎支持所有常用編程語言,包括 Java、.NET、Ruby 等等。
- 可視化管理界面。RabbitMQ提供了一個易用的用戶界面,使得用戶可以監控和管理消息 Broker。
- 插件機制。RabbitMQ提供了許多插件,可以通過插件進行擴展,也可以編寫自己的插件。
消息隊列中間件對比
目前在市面上比較主流的MQ中間件主要有,ActiveMQ、RabbitMQ、Kafka、RocketMQ 等這幾種,對比如下表:
特性 | ActiveMQ | RabbitMQ | Kafka | RocketMQ |
所屬社區/公司 | Apache | Mozilla Public License | Apache | Apache/Ali |
單機呑吐量 | 萬級 | 萬級 | 幾十萬級 | 十萬級 |
時效性 | 毫秒級 | 微秒級 | 毫秒級 | 毫秒級 |
可用性 | 主從 | 主從 | 分布式 | 分布式 |
功能特性 | MQ領域功能極其完備 | 基于erlang開發,所以并發能力很強,性能極其好,延時很低 | 功能較為簡單,主要支持簡單的MQ功能,在大數據領域的實時計算以及日志采集被大規模使用 | MQ功能比較完備,擴展性佳 |
消息可靠性 | 有較低的概率丟失數據 | 基本不丟 | 經過參數優化配置,可以做到 0 丟失 | 同 Kafka |
事務 | 支持 | 不支持 | 支持 | 支持 |
broker端消息過濾 | 支持 | 不支持 | 不支持 | 可以支持Tag標簽過濾和SQL表達式過濾 |
消息查詢 | 支持 | 根據消息id查詢 | 不支持 | 支持Message id或Key查詢 |
消息回溯 | 支持 | 不支持 | 理論上可以支持時間或offset回溯,但是得修改代碼。 | 支持按時間來回溯消息,精度毫秒,例如從一天之前的某時某分某秒開始重新消費消息。 |
路由邏輯 | 無 | 基于交換機,可配置復雜路由邏輯 | 根據topic | 根據topic,可以配置過濾消費 |
持久化 | 內存、文件、數據庫 | 隊列基于內存,只能少量堆積 | 磁盤,大量堆積 | 磁盤,大量堆積 |
順序消息 | 支持 | 不支持 | 支持 | 支持 |
社區活躍度 | 低 | 中 | 高 | 高 |
適用場景 | 解耦和異步調用,較少在大規模吞吐的場景中使用 | 數據量小對時效性要求高的場景中使用 | 大數據類的系統來進行實時數據計算、日志采集等場景。 | 目前在阿里被廣泛應用在訂單、交易、充值、流計算、消息推送、日志流式處理、binglog分發消息等場景。 |
RabbitMQ原理
內部結構
RabbitMQ 本質是 AMQP 協議的一個開源實現,在詳細介紹 RabbitMQ 之前,我們先來看一下 AMQP 的內部結構圖
圖片
- Publisher:消息的生產者,也是一個向交換器發布消息的客戶端應用程序
- Exchange:交換器,用來接收生產者發送的消息并將這些消息路由給服務器中的隊列
- Binding:綁定,用于將消息隊列和交換器之間建立關聯。一個綁定就是基于路由鍵將交換器和消息隊列連接起來的路由規則,所以可以將它理解成一個由綁定構成的路由表。
- Queue:消息隊列,用來保存消息直到發送給消費者
- Connection:網絡連接,比如一個 TCP 連接
- Channel:信道,多路復用連接中的一條獨立的雙向數據流通道
- Consumer:消息的消費者,表示一個從消息隊列中取得消息的客戶端應用程序
- Virtual Host:虛擬主機,表示一批交換器、消息隊列和相關對象。虛擬主機是共享相同的身份認證和加密環境的獨立服務器域。每個 vhost 本質上就是一個 mini 版的 RabbitMQ 服務器,擁有自己的隊列、交換器、綁定和權限機制。vhost 是 AMQP 概念的基礎,必須在連接時指定,RabbitMQ 默認的 vhost 是 /
- Broker:表示消息隊列服務器實體
- Message:消息實體,它由消息頭和消息體組成。消息頭主要由路由鍵、交換器、隊列、priority(相對于其他消息的優先權)、delivery-mode(指出該消息可能需要持久性存儲)等屬性組成,而消息體就是指具體的業務對象。
相比傳統的 JMS 模型,AMQP 主要多了 Exchange、Binding 這個新概念。
在 AMQP 模型中,消息的生產者不是直接將消息發送到Queue隊列,而是將消息發送到Exchange交換器,其中還新加了一個中間層Binding綁定,作用就是通過路由鍵Key將交換器和隊列建立綁定關系。
圖片
就好比類似**用戶表和角色表,中間通過用戶角色表**來將用戶和角色建立關系,從而實現關系綁定,在 RabbitMQ 中,消息生產者不直接跟隊列建立關系,而是將消息發送到交換器之后,由交換器通過已經建立好的綁定關系,將消息發送到對應的隊列!
RabbitMQ 最終的架構模型,核心部分就變成如下圖所示:
圖片
從圖中很容易看出,與 JMS 模型最明顯的差別就是消息的生產者不直接將消息發送給隊列,而是由Binding綁定決定交換器的消息應該發送到哪個隊列,進一步實現了在消息的推送方面,更加靈活!
交換器分發策略
當消息的生產者將消息發送到交換器之后,是不會存儲消息的,而是通過中間層綁定關系將消息分發到不同的隊列上,其中交換器的分發策略分為四種:Direct、Topic、Headers、Fanout!
- Direct:直連類型,即在綁定時設定一個 routing_key, 消息的 routing_key 匹配時, 才會被交換器投送到綁定的隊列中去,原則是先匹配、后投送;
- Topic:按照規則轉發類型,支持通配符匹配,和 Direct 功能一樣,但是在匹配 routing_key的時候,更加靈活,支持通配符匹配,原則也是先匹配、后投送;
- Headers:頭部信息匹配轉發類型,根據消息頭部中的 header attribute 參數類型,將消息轉發到對應的隊列,原則也是先匹配、后投送;
- Fanout:廣播類型,將消息轉發到所有與該交互機綁定的隊列上,不關心 routing_key;
Direct
Direct 是 RabbitMQ 默認的交換機模式,也是最簡單的模式,消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致, 交換器就將消息發到對應的隊列中。
如果傳入的 routing key 為 black,不會轉發到black.green。Direct 類型交換器是完全匹配、單播的模式。
圖片
Topic
Topic 類型交換器轉發消息和 Direct 一樣,不同的是:它支持通配符轉發,相比 Direct 類型更加靈活!
兩種通配符:*只能匹配一個單詞,#可以匹配零個或多個。
如果傳入的 routing key 為 black#,不僅會轉發到black,也會轉發到black.green。
圖片
Headers
headers 也是根據規則匹配, 相比 direct 和 topic 固定地使用 routing_key , headers 則是通過一個自定義匹配規則的消息頭部類進行匹配。
在隊列與交換器綁定時,會設定一組鍵值對規則,消息中也包括一組鍵值對( headers 屬性),當這些鍵值對有一對, 或全部匹配時,消息被投送到對應隊列。
此外 headers 交換器和 direct 交換器完全一致,但性能差很多,目前幾乎用不到了。
圖片
Fanout
Fanout 類型交換器與上面幾個不同,不管路由鍵或者是路由模式,會把消息發給綁定給它的全部隊列,如果配置了 routing_key 會被忽略,也被成為消息廣播模式。很像子網廣播,每臺子網內的主機都獲得了一份復制的消息
fanout 類型轉發消息在四種類型中是最快的。
單節點部署
docker部署
參考文檔:https://hub.docker.com/_/rabbitmq
docker run -d --name RabbitMQ -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 -p 15672:15672 rabbitmq:4.0-management
然后打開瀏覽器訪問服務器ip:15672,輸入我們創建的賬號密碼登錄即可。
rpm部署
安裝Erlang
RabbitMQ是采用 Erlang語言開發的,所以系統環境必須提供 Erlang環境,需要是安裝 Erlang
Erlang和RabbitMQ版本對照:https://www.rabbitmq.com/which-erlang.html
本次安裝4.0版本的RabbitMQ,需要的Erlang版本為26.2,
下載地址:https://packagecloud.io/rabbitmq/erlang
[root@tiaoban ~]# wget https://packagecloud.io/rabbitmq/erlang/packages/el/8/erlang-26.2.5.3-1.el8.x86_64.rpm/download.rpm -O ./erlang-26.2.5.3-1.el8.x86_64.rpm
[root@tiaoban ~]# ls
erlang-26.2.5.3-1.el8.x86_64.rpm
# 安裝erlang
[root@tiaoban ~]# rpm -ivh erlang-26.2.5.3-1.el8.x86_64.rpm
警告:erlang-26.2.5.3-1.el8.x86_64.rpm: 頭V4 RSA/SHA256 Signature, 密鑰 ID 6026dfca: NOKEY
Verifying... ################################# [100%]
準備中... ################################# [100%]
正在升級/安裝...
1:erlang-26.2.5.3-1.el8 ################################# [100%]
# 驗證
[root@tiaoban ~]# erl -v
Erlang/OTP 26 [erts-14.2.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]
Eshell V14.2.5.3 (press Ctrl+G to abort, type help(). for help)
1>
安裝RabbitMQ
下載地址:https://www.rabbitmq.com/docs/install-rpm
在RabiitMQ安裝過程中需要依賴socat和logrotate插件,首先安裝該插件
[root@tiaoban ~]# dnf -y install socat logrotate
安裝RabbitMQ
[root@tiaoban ~]# wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v4.0.1/rabbitmq-server-4.0.1-1.el8.noarch.rpm
[root@tiaoban ~]# ls
erlang-26.2.5.3-1.el8.x86_64.rpm k8s rabbitmq-server-4.0.1-1.el8.noarch.rpm
[root@tiaoban ~]# rpm -ivh rabbitmq-server-4.0.1-1.el8.noarch.rpm
警告:rabbitmq-server-4.0.1-1.el8.noarch.rpm: 頭V4 RSA/SHA512 Signature, 密鑰 ID 6026dfca: NOKEY
Verifying... ################################# [100%]
準備中... ################################# [100%]
正在升級/安裝...
1:rabbitmq-server-4.0.1-1.el8 ################################# [100%]
[/usr/lib/tmpfiles.d/rabbitmq-server.conf:1] Line references path below legacy directory /var/run/, updating /var/run/rabbitmq → /run/rabbitmq; please update the tmpfiles.d/ drop-in file accordingly.
啟動RabbitMQ服務
[root@tiaoban ~]# systemctl start rabbitmq-server
[root@tiaoban ~]# systemctl enable rabbitmq-server
Created symlink /etc/systemd/system/multi-user.target.wants/rabbitmq-server.service → /usr/lib/systemd/system/rabbitmq-server.service.
[root@tiaoban ~]# systemctl status rabbitmq-server
默認情況下,rabbitmq沒有安裝web端的客戶端軟件,需要安裝才可以生效
[root@tiaoban ~]# rabbitmq-plugins enable rabbitmq_management
訪問服務器ip:15672,就可以看到管理界面
圖片
高可用集群部署
高可用集群方案
RabbitMQ的集群主要有兩種模式:普通集群模式和克隆隊列模式。
普通集群模式:集群中各個節點之間只會相互同步元數據,消息數據不會被同步。不論是生產者還是消費者,假如連接到的節點上沒有存儲隊列數據,那么內部會將其轉發到存儲隊列數據的節點上進行存儲。雖然說內部可以實現轉發,但是因為消息僅僅只是存儲在一個節點,所以這種普通集群模式并沒有達到高可用的目的。
克隆隊列模式:集群中各個節點之間不僅僅會同步元數據,消息內容也會在鏡像節點間同步,可用性更高。這種方案提升了可用性的同時,因為同步數據之間也會帶來網絡開銷從而在一定程度上會影響到性能。
程序通過訪問 KeepAlived 提供的 VIP(虛擬 ip)指定到其中一個Haproxy,然后 Haproxy 將訪問請求代理到其管理的多個 Rabbitmq Server 中的一個,從而實現了高可用、負載均衡的功能。
圖片
集群角色規劃
通過hk1和hk2兩臺服務,部署HA-proxy和KeepAlived實現高可用和負載均衡服務,通過VIP 192.168.10.90對外提供服務,所有請求反向代理至mq1、mq2、mq3組成的RabbitMQ集群。
服務器IP | hostname | 節點服務 |
192.168.10.90 | vip | |
192.168.10.91 | hk1 | HA proxy、KeepAlived |
192.168.10.92 | hk2 | HA proxy、KeepAlived |
192.168.10.93 | mq1 | RabbitMQ |
192.168.10.94 | mq2 | RabbitMQ |
192.168.10.95 | mq3 | RabbitMQ |
Rabbit MQ集群部署
MQ集群節點修改hosts解析和主機名(每臺mq節點執行)
[root@mq1 ~]# cat /etc/hosts
192.168.10.93 mq1
192.168.10.94 mq2
192.168.10.95 mq3
部署Erlang和RabbitMQ服務(每臺mq節點執行)
參考上文單節點部署流程,此處不再贅述。
啟動RabbitMQ服務(每臺mq節點執行)
[root@mq1 ~]# systemctl enable rabbitmq-server --now
RabbitMQ集群節點需要共享一個Erlang cookie,默認存儲在/var/lib/rabbitmq/.erlang.cookie。需要在所有節點上保持該文件一致:(mq1節點執行)
[root@mq1 ~]# ls /var/lib/rabbitmq/.erlang.cookie
/var/lib/rabbitmq/.erlang.cookie
[root@mq1 ~]# scp /var/lib/rabbitmq/.erlang.cookie mq2:/var/lib/rabbitmq/ 100% 20 9.4KB/s 00:00
[root@mq1 ~]# scp /var/lib/rabbitmq/.erlang.cookie mq3:/var/lib/rabbitmq/
# 確保復制后的文件權限為400:
[root@mq2 ~]# chmod 400 /var/lib/rabbitmq/.erlang.cookie
在節點2和節點3上執行以下命令,將它們加入到節點1的集群中(mq2和3節點執行):
[root@mq2 ~]# systemctl restart rabbitmq-server
[root@mq2 ~]# rabbitmqctl stop_app
Stopping rabbit application on node rabbit@mq2 ...
[root@mq2 ~]# rabbitmqctl join_cluster rabbit@mq1
Clustering node rabbit@mq2 with rabbit@mq1
[root@mq2 ~]# rabbitmqctl start_app
Starting node rabbit@mq2 ...
在任何一個節點上查看集群狀態
[root@mq3 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@mq3 ...
Basics
Cluster name: rabbit@mq3
Total CPU cores available cluster-wide: 12
Disk Nodes
rabbit@mq1
rabbit@mq2
rabbit@mq3
Running Nodes
rabbit@mq1
rabbit@mq2
rabbit@mq3
Versions
rabbit@mq3: RabbitMQ 4.0.1 on Erlang 26.2.5.3
rabbit@mq1: RabbitMQ 4.0.1 on Erlang 26.2.5.3
rabbit@mq2: RabbitMQ 4.0.1 on Erlang 26.2.5.3
CPU Cores
Node: rabbit@mq3, available CPU cores: 4
Node: rabbit@mq1, available CPU cores: 4
Node: rabbit@mq2, available CPU cores: 4
Maintenance status
Node: rabbit@mq3, status: not under maintenance
Node: rabbit@mq1, status: not under maintenance
Node: rabbit@mq2, status: not under maintenance
安裝web端插件并設置賬戶密碼
# 所有mq節點執行
[root@mq1 ~]# rabbitmq-plugins enable rabbitmq_management
# 其中一個節點執行
[root@mq1 ~]# rabbitmqctl add_user admin 123.com
Adding user "admin" ...
Done. Dont forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
[root@mq1 ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator] ...
[root@mq1 ~]# rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
Setting permissions for user "admin" in vhost "/" ...
瀏覽器訪問mq1:15672,查看UI信息
圖片
此時,集群搭建完畢,但是默認采用的模式“普通模式”,只會相互同步元數據,消息數據不會被同步,如果某一個節點宕機,則會導致該節點上的消息數據不可用。
創建克隆隊列策略
在之前的mq中,我們可以將所有隊列設置為鏡像隊列,即隊列會被復制到各個節點,各個節點元數據和消息內容保持一致。從 RabbitMQ 3.8 開始,官方不推薦使用經典的鏡像隊列,而是推薦使用 隊列克?。≦uorum Queues) 來代替鏡像隊列。Quorum Queues 提供了更穩定的高可用性,尤其是在節點故障和網絡分區的情況下。
- name:策略名,可自定義
- pattern:隊列的匹配模式(正則表達式)
- "^" 可以使用正則表達式,比如"^queue_" 表示對隊列名稱以“queue_”開頭的所有 隊列進行鏡像,而"^"表示匹配所有的隊列
- definition:鏡像定義,**x-queue-type: quorum**:指定隊列類型為 Quorum Queue。
- quorum.initial-group-size:指定 Quorum Queue 初始副本數量(通常與集群節點數量相匹配)
- max-length:設置隊列的最大長度,以限制存儲的消息數量。當隊列中的消息數超過此限制時,RabbitMQ 會丟棄最早的消息。
- delivery-limit:設置消息在投遞失敗后的最大重試次數。達到這個次數后,消息會被轉移到死信隊列(DLX)。
- message-ttl:消息在隊列中的生存時間,單位為毫秒。
- priority:可選參數,policy的優先級。
圖片
HaProxy部署
以下操作在hk1和hk2機器執行
安裝haproxy
[root@hk1 ~]# dnf -y install haproxy
修改配置文件
[root@hk1 ~]# cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
[root@hk1 ~]# vim /etc/haproxy/haproxy.cfg
# 開啟管理員監控頁面
listen admin_stats
bind *:8080 #監聽的ip端口號
stats enable
stats refresh 30s #統計頁面自動刷新時間
stats uri /admin #訪問的uri ip:8080/admin
stats realm haproxy
stats auth admin:admin #認證用戶名和密碼
stats hide-version #隱藏HAProxy的版本號
stats admin if TRUE #管理界面,如果認證成功了,可通過webui管理節點
# 配置前端監聽
frontend main
bind *:5672 # 監聽地址
default_backend rabbitmq # 匹配后端服務
# 配置后端代理
backend rabbitmq # 后端服務名稱
server rabbitmq1 192.168.10.93:5672 check
server rabbitmq2 192.168.10.94:5672 check
server rabbitmq3 192.168.10.95:5672 check
啟動服務
[root@hk1 ~]# systemctl start haproxy.service
[root@hk1 ~]# systemctl enable haproxy.service
Created symlink /etc/systemd/system/multi-user.target.wants/haproxy.service → /usr/lib/systemd/system/haproxy.service.
[root@hk1 ~]# ss -tunlp | grep haproxy
udp UNCONN 0 0 0.0.0.0:59334 0.0.0.0:* users:(("haproxy",pid=2489,fd=6),("haproxy",pid=2487,fd=6))
tcp LISTEN 0 2048 0.0.0.0:5672 0.0.0.0:* users:(("haproxy",pid=2489,fd=7))
tcp LISTEN 0 2048 0.0.0.0:8080 0.0.0.0:* users:(("haproxy",pid=2489,fd=5))
訪問haproxy管理員頁面驗證配置是否生效。
圖片
確認無誤后hk2服務器同樣的步驟配置。
KeepAlived部署
以下操作在hk1和hk2機器執行,設備網卡名稱為ens160,VIP為192.168.10.90。
安裝軟件包
[root@hk1 ~]# dnf -y install keepalived
修改配置文件
[root@hk1 ~]# cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
[root@hk1 ~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL # vrrp協議路由標識
}
vrrp_instance VI_1 {
state MASTER # 定義主從類型
interface ens160 # 網卡名稱
virtual_router_id 51 # vrrp唯一id號
priority 100 # 優先級主大于備
advert_int 1 # 心跳檢測時間間隔
authentication { # 認證類型和密碼
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { # vip配置
192.168.10.90/24
}
}
啟動服務
[root@hk1 ~]# systemctl start keepalived.service
[root@hk1 ~]# systemctl enable keepalived.service
[root@hk1 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:2a:b6:b3 brd ff:ff:ff:ff:ff:ff
altname enp3s0
inet 192.168.10.91/24 brd 192.168.10.255 scope global noprefixroute ens160
valid_lft forever preferred_lft forever
inet 192.168.10.90/24 scope global secondary ens160
valid_lft forever preferred_lft forever
此時可以看到vip 192.168.10.90綁定到了hk1服務器ens160網卡上。
同樣的操作配置hk2服務器,配置文件如下
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state BACKUP # 主備類型
interface ens160
virtual_router_id 51
priority 99 # 優先級低于主
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.10.90/24
}
}
高可用測試
接下來停止hk1服務器,模擬異常故障,查看hk2服務器,vip已經成功飄移過來
[root@hk2 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:17:68:2a brd ff:ff:ff:ff:ff:ff
altname enp3s0
inet 192.168.10.92/24 brd 192.168.10.255 scope global noprefixroute ens160
valid_lft forever preferred_lft forever
inet 192.168.10.90/24 scope global secondary ens160
valid_lft forever preferred_lft forever
訪問vip的8080端口,可正常提供服務
圖片
web界面使用
進入 web 管理界面之后,可以很清晰的看到分了 6 個菜單目錄,分別是:Overview、Connections、Channels、Exchanges、Queues、Admin。
- Overview:總覽概述,主要介紹 rabbitmq 一些基礎匯總等信息
圖片
- Connections:連接池管理,主要介紹客戶端連接等信息
圖片
- Channels:信道管理,主要介紹信道連接等信息
圖片
點擊具體某個具體的信道,可以看到對應的消費隊列等信息。
圖片
- Exchanges:交換器管理,主要介紹交換器等信息
圖片
- Queues:隊列管理,主要介紹隊列等信息
圖片
- Admin:系統管理,主要介紹用戶、虛擬主機、權限等信息
圖片
下面,我們重點介紹一些如何通過 web 頁面來操作 rabbitMQ!
交換器管理
點擊進入 Exchanges 菜單,最下面有一個Add a new exchange標簽。點擊Add a new exchange,會展示如下信息!
圖片
- Name:交換器名稱
- Type:交換器類型
- Durability:是否持久化,Durable:持久化,Transient:不持久化
- Auto delete:是否自動刪除,當最后一個綁定(隊列或者exchange)被unbind之后,該exchange 自動被刪除
- Internal:是否是內部專用exchange,是的話,就意味著我們不能往該exchange里面發消息
- Arguments:參數,是AMQP協議留給AMQP實現做擴展使用的
我們先新建一個名稱為test.exchange,類型為direct的交換器,結果如下。
圖片
等會用于跟隊列關聯!
隊列管理
點擊進入 Queues 菜單,最下面也有一個Add a new queue標簽。
點擊標簽,即可進入添加隊列操作界面!
圖片
- Name:隊列名稱
- Durability:是否持久化,Durable:持久化,Transient:不持久化
- Auto delete:是否自動刪除,是的話,當隊列內容為空時,會自動刪除隊列
- Arguments:參數,是AMQP協議留給AMQP實現做擴展使用的
同樣的,新建一個名稱為test_queue的消息隊列,結果如下。
圖片
隊列新建好了之后,繼續來建立綁定關系!
綁定管理
建立綁定關系,既可以從隊列進入也可以從交換器進入。
如果是從交換器進入,那么被關聯的對象就是隊列。
圖片
如果是從隊列進入,那么被關聯的對象就是交換器。
圖片
我們選擇從隊列入手,被綁定的交換器是test.exchange。建立完成之后,在交換器那邊也可以看到對應的綁定關系。
圖片
發送消息
最后,我們從交換器入手,選擇對應的交換器,點擊Publish message標簽,填寫對應的路由鍵 key,發送一下數據,查看數據是否發送到對應的隊列中。
圖片
然后點擊進入 Queues 菜單,查詢消息隊列基本情況。其中Ready表示待消費的消息數,total表示總消息數。
圖片
接收消息
然后選擇hello-mq消息隊列,點擊Get messages標簽,獲取隊列中的消息。結果如下,可以很清晰的看到,消息寫入到隊列!
圖片
rabbitmqctl命令
服務管理
rabbitmqctl stop [{pid_file}]
# 表示stop 在RabbitMQ服務器上運行的一個Erlang 節點,可以指定某一個 *pid_file*,表示會等待這個指定的程序結束
rabbitmqctl shutdown
# 表示終止RabbitMQ 服務器上的Erlang進程,如果終止失敗,會返回非零數字
rabbitmqctl stop_app
# 表示終止RabbitMQ的應用,但是Erlang節點還在運行。該命令典型的運行在一些需要RabbitMQ應用被停止的管理行為之前,例如 reset
rabbitmqctl start_app
# 表示啟動RabbitMQ的應用。該命令典型的運行在一些需要RabbitMQ應用被停止的管理行為之后,例如 reset
rabbitmqctl wait {pid_file}
# 表示等待RabbitMQ應用啟動。該命令會等待指定的pid file被創建,也就是啟動的進程對應的pid保存在這個文件中,然后RabbitMQ應用在這個進程中啟動。如果該進程終止,沒有啟動RabbitMQ應用,就會返回錯誤。
# 合適的pid file是有rabbitmq-server 腳本創建的,默認保存在 Mnesia 目錄下,可以通過修改 RABBITMQ_PID_FILE 環境變量來修改
# 例如 rabbitmqctl wait /var/run/rabbitmq/pid
rabbitmqctl reset
# 表示設置RabbitMQ節點為原始狀態。會從該節點所屬的cluster中都刪除,從管理數據庫中刪除所有數據,例如配置的用戶和vhost,還會刪除所有的持久消息。
# 要想reset和force_reset操作執行成功,RabbitMQ應用需要處于停止狀態,即執行過 stop_app
rabbitmqctl force_reset
# 表示強制性地設置RabbitMQ節點為原始狀態。它和reset的區別在于,可以忽略目前管理數據庫的狀態和cluster的配置,無條件的reset。
# 該方法的使用,應當用在當數據庫或者cluster配置損壞的情況下作為最后的方法。
rabbitmqctl rotate_logs {suffix}
# 表示將日志文件的內容追加到新的日志文件中去,這個新的日志文件的文件名是原有的日志文件名加上命令中的 suffix,并且恢復日志到原來位置的新文件中。
# 注意:如果新文件原先不存在,那么會新建一個;如果suffix為空,那么不會發生日志轉移,只是重新打開了一次日志文件而已。
rabbitmqctl hipe_compile {directory}
# 表示在指定的目錄下執行HiPE編譯和緩存結果文件 .beam-files
# 如果需要父目錄會被創建。并且在編譯之前,該目錄下的所有 .beam-files會被自動刪除。
# 使用預編譯的文件,你應該設置 RABBITMQ_SERVER_CODE_PATH 環境變量為 hipe_compile 調用指定的目錄。
集群管理
rabbitmqctl join_cluster {clusternode} [--ram]
# 表示結合到指定的集群,如果有參數 --ram 表示作為RAM節點結合到該集群中。
# 該命令指令本節結合到指定的集群中,在結合之前,該節點需要reset,所以在使用時,需要格外注意。為了成功運行本命令,必須要停止RabbitMQ應用,例如 stop_app
# 集群節點有兩種類型: disc 和 RAM。disc類型,復制數據在RAM和disc上,在節點失效的情況下,提供了冗余保證,也能從一些全局事件中恢復,例如所有節點失效。RAM類型,只復制數據在RAM上,主要表現在伸縮性上,特別是在管理資源(例如:增加刪除隊列,交換器,或者綁定)上表現突出。
# 一個集群必須至少含有一個disc節點,當通常都多余一個。通過該命令時,默認是設置為disc節點,如果需創建RAM節點,需要指定參數 --ram
# 執行此命令之后,在該節點上啟動的RabbitMQ應用,在該節點掛掉之后,會嘗試連接節點所在集群中的其他節點。
# 為了離開集群,可以 reset 該節點,也可以使用命令 forget_cluster_node 遠程刪除節點
rabbitmqctl cluster_status
# 表示顯示通過節點類型聚合在一起的集群中的所有節點,還有目前正在運行的節點
rabbitmqctl change_cluster_node_type {disc|ram}
# 表示改變集群節點的類型。該操作的正確執行,必定會停止該節點。并且在調整一個node為ram類型時,該節點不能為該集群的唯一node
rabbitmqctl forget_cluster_node [--offline]
# 表示遠程移除一個集群節點。要刪除的節點必須脫機,如果沒有脫機,需要使用 --offline 參數。當使用 --offline 參數時,rabbitmqctl不會去連接節點,而是暫時變成節點,以便進行變更。這在節點不能正常啟動時非常有用。在這種情況下,節點會成為集群元數據的規范來源(例如哪些隊列存在)。因此如果可以的話,應該使用此命令在最新的節點上關閉。
# --offline 參數使節點從脫機節點上移除。使用場景主要是在所有節點脫機,且最后一個節點無法聯機時,從而防止整個集群啟動。在其他情況不應該使用,否則會導致不一致。
# 例如 rabbitmqctl -n hare@mcnulty forget_cluster_node rabbit@stringer
# 上述命令將從節點 hare@mcnulty 中移除節點 rabbit@stringer
rabbitmqctl rename_cluster_node {oldnode1} {newnode1} [oldnode2] [newnode2...]
# 表示在本地數據庫上修改集群節點名稱。該命令讓rabbitmqctl暫時成為一個節點來做出做變更。因此,本地的待修改的集群節點一定要完全停止,其他節點可以是online或者offline
rabbitmqctl update_cluster_nodes {clusternode}
# 表示指示已經集群的節點在喚醒時聯系 {clusternode} 進行集群。這與 join_cluster 命令不同,因為它不加入任何集群,它是檢查節點是否已經在具有 {clusternode} 的集群中。
# 該命令的需求,是在當一個節點offline時,修改了集群節點的情形下。例如:節點A和B聚群,節點A offline了,節點C和B集群,并且B節點離開了該集群,那么當節點A起來的時候,A會嘗試連接B,但是由于B節點已經不在該集群中,所以會失敗。
# 通過 update_cluster_nodes -n A C 將會解決上述問題。
rabbitmqctl force_boot
# 表示強制確保節點啟動,即使該節點并不是最后down的。
# 一般情況下,當你同時shut down了RabbitMQ集群時,第一個重啟的節點應該是最后一個down掉的,因為它可能已經看到了其他節點發生的事情。但是有時候這并不可能:例如當整個集群lose power,那么該集群的所有節點會認為他們不是最后一個關閉的。
# 如果最后down的節點永久的lost,那么應該優先使用 rabbitmqctl forget_cluster_node --offline ,因為這將確保在丟失節點上的鏡像隊列得到優先處理。
rabbitmqctl sync_queue [-p vhost] {queue}
# {queue} 表示待同步的隊列名稱
# 指引含有異步slaves的鏡像隊列去同步自身。當隊列執行同步化時,其將會被鎖定(指所有publishers發送出去的和consumers獲取到的隊列都會被鎖定)。為了成功執行此命令,隊列必須要被鏡像。
# 注意,排除消息的異步隊列將最終被同步化,此命令主要運用于未被排除完全消息的隊列。
rabbitmqctl cancel_sync_queue [-p vhost] {queue}
# 指引一個正在同步的鏡像隊列停止此操作。
rabbitmqctl purge_queue [-p vhost] {queue}
# {queue} 表示待清空消息的隊列名稱
# 該命令表示清空隊列(即刪除隊列中的所有消息)
rabbitmqctl set_cluster_name {name}
# 設置集群的名稱。在連接中,集群的名稱被聲明在客戶端上,被同盟和插件用來記錄一個消息所在的位置。集群的名稱默認來自于集群中第一個節點的主機名,但是可以被修改。
用戶管理
rabbitmq有一個默認的賬號密碼guest,但該情況僅限于本機localhost進行訪問,所以需要添加一個遠程登錄的用戶
用戶管理命令
# 添加用戶
rabbitmqctl add_user 用戶名 密碼
# 設置用戶角色,分配操作權限
rabbitmqctl set_user_tags 用戶名 角色
# 為用戶添加資源權限(授予訪問虛擬機根節點的所有權限)
rabbitmqctl set_permissions -p / 用戶名 ".*" ".*" ".*"
# 修改密碼
rabbitmqctl change_ password 用戶名 新密碼
# 刪除用戶
rabbitmqctl delete_user 用戶名
# 查看用戶清單
rabbitmqctl list_users
角色種類:
- administrator:可以登錄控制臺、查看所有信息、并對rabbitmq進行管理
- monToring:監控者;登錄控制臺,查看所有信息
- policymaker:策略制定者;登錄控制臺指定策略
- managment:普通管理員;登錄控制
這里創建用戶admin,密碼123.com,設置adminstator角色,賦予所有權限
[root@tiaoban ~]# rabbitmqctl add_user admin 123.com
Adding user "admin" ...
Done. Dont forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
[root@tiaoban ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator] ...
[root@tiaoban ~]# rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
Setting permissions for user "admin" in vhost "/" ...
訪問控制
rabbitmqctl add_vhost {vhost}
# {vhost} 表示待創建的虛擬主機項的名稱
rabbitmqctl delete_vhost {vhost}
# 表示刪除一個vhost。刪除一個vhost將會刪除該vhost的所有exchange、queue、binding、用戶權限、參數和策略。
rabbitmqctl list_vhosts {vhostinfoitem ...}
# 表示列出所有的vhost。其中 {vhostinfoitem} 表示要展示的vhost的字段信息,展示的結果將按照 {vhostinfoitem} 指定的字段順序展示。這些字段包括:name(名稱) 和 tracing (是否為此vhost啟動跟蹤)。
# 如果沒有指定具體的字段項,那么將展示vhost的名稱。
rabbitmqctl set_permissions [-p vhost] {user} {conf} {write} {read}
# 表示設置用戶權限。 {vhost} 表示待授權用戶訪問的vhost名稱,默認為 "/"; {user} 表示待授權反問特定vhost的用戶名稱; {conf}表示待授權用戶的配置權限,是一個匹配資源名稱的正則表達式; {write} 表示待授權用戶的寫權限,是一個匹配資源名稱的正則表達式; {read}表示待授權用戶的讀權限,是一個資源名稱的正則表達式。
# rabbitmqctl set_permissions -p myvhost tonyg "^tonyg-.*" ".*" ".*"
# 例如上面例子,表示授權給用戶 "tonyg" 在vhost為 `myvhost` 下有資源名稱以 "tonyg-" 開頭的 配置權限;所有資源的寫權限和讀權限。
rabbitmqctl clear_permissions [-p vhost] {username}
# 表示設置用戶拒絕訪問指定指定的vhost,vhost默認值為 "/"
rabbitmqctl list_permissions [-p vhost]
# 表示列出具有權限訪問指定vhost的所有用戶、對vhost中的資源具有的操作權限。默認vhost為 "/"。
# 注意,空字符串表示沒有任何權限。
rabbitmqctl list_user_permissions {username}
# 表示列出指定用戶的權限vhost,和在該vhost上的資源可操作權限。