C9-OpenStack 基礎服務與高可用配置 (上)
0. 環境與連線
0.1 本課環境
- 控制節點:
ctl001(10.127.0.4) /ctl002(10.127.0.14) /ctl003(10.127.0.15) - VIP:
10.127.0.250 - 部署節點:
jmp001(10.127.0.3) - Python venv:
source ~/venv/bin/activate - 認證檔:jmp001 的
/home/ubuntu/creds/stuNN-openrc.sh(即~/creds/;NN 為學員編號 01–20) - Compute Node:
scp001、scp002 - 部署工具:Kolla-Ansible 2025.1,所有服務都跑在 Docker container 裡
- 節點的實際 hostname 是長名稱,例如
ctl001-6161060-iaas - 各台 ens3 的 MAC:ctl001
fa:16:3e:95:ff:be、ctl002fa:16:3e:96:93:5a、ctl003fa:16:3e:6d:51:ba
0.2 連線與準備
全班與講師共用 jmp001 與控制節點上的 ubuntu 帳號(具 sudo 權限)。登入 jmp001 後,先準備 OpenStack CLI:
# [jmp001]
export NN=01 # ← 換成你的學員編號(01–20)
source ~/venv/bin/activate
source ~/creds/stu${NN}-openrc.sh要到控制節點時,從 jmp001 SSH 過去(以 ctl001 為例):
ssh ubuntu@10.127.0.4本學習單的指令會標示在哪裡執行:[jmp001] 在 jmp001;[ctl] 在任一台控制節點;[ctl003] 在指定的控制節點。
⚠️ 規則
- 你使用的是和講師相同的管理員權限,任何指令都會直接影響全班共用的環境
- 除了標示「⚠️ 講師示範」的步驟外,全部都是唯讀指令
- 不要修改
/etc/kolla/底下的任何檔案,也不要docker restart任何 container- 預期輸出是示意,數字、時間、順序可能與你看到的不同
Part A:HAProxy + Keepalived
A0. 一個 API 請求的真實路徑
加上 --debug,看 CLI 在背後送出了哪些請求:
# [jmp001]
openstack server list --debug 2>&1 | grep -E 'POST /v3/auth/tokens|REQ: curl -g -i -X GET http://10.127.0.250:8774/v2.1 |8774 "GET /v2.1 '預期輸出:
http://10.127.0.250:5000 "POST /v3/auth/tokens HTTP/1.1" 201 4924
REQ: curl -g -i -X GET http://10.127.0.250:8774/v2.1 -H "Accept: application/json" -H "User-Agent: openstacksdk/4.4.1 keystoneauth1/5.10.0 python-requests/2.32.3 CPython/3.12.3"
http://10.127.0.250:8774 "GET /v2.1 HTTP/1.1" 200 387對照投影片 p.04 的五個階段:
| 階段 | 在輸出裡看到的 |
|---|---|
| ① 入口:REST 請求打向 VIP | 兩個請求的目的地都是 10.127.0.250(Keystone 5000、Nova 8774) |
| 先取得身分 | POST /v3/auth/tokens 回 201:向 Keystone 換到 token 與 service catalog |
| 再呼叫目標服務 | 從 catalog 找到 Nova 的 endpoint,對 :8774 送出請求 |
| ②–⑤ 轉發、狀態、訊息、執行 | 發生在 VIP 之後的控制平面內部,client 看不到;本學習單接下來逐一觀察 |
A1. VIP 現在在哪一台?
用投影片的寫法,從 jmp001 一次檢查三台:
# [jmp001]
for i in 4 14 15; do ssh 10.127.0.$i \
"hostname && sudo ip a | grep 10.127.0.250"; done預期輸出(只有一台會多印出 VIP 那一行):
ctl001-6161060-iaas
ctl002-6161063-iaas
ctl003-6161069-iaas
inet 10.127.0.250/32 scope global ens3※ 正常狀態下只有一台會輸出 VIP;同時出現在兩台代表 VRRP 通訊異常(split-brain)。
再確認 API Endpoint 都指向 VIP,以及 jmp001 看到的 VIP MAC 屬於哪一台:
# [jmp001]
openstack endpoint list --service identity
ip neigh show 10.127.0.250預期輸出:
+----------------------------------+-----------+--------------+--------------+---------+-----------+--------------------------+
| ID | Region | Service Name | Service Type | Enabled | Interface | URL |
+----------------------------------+-----------+--------------+--------------+---------+-----------+--------------------------+
| 11783862106c4a408b8db6f955f7f784 | RegionOne | keystone | identity | True | internal | http://10.127.0.250:5000 |
| 23f875bd0bb245e09bf70de192d669d7 | RegionOne | keystone | identity | True | public | http://10.127.0.250:5000 |
+----------------------------------+-----------+--------------+--------------+---------+-----------+--------------------------+
10.127.0.250 dev ens3 lladdr fa:16:3e:6d:51:ba REACHABLEfa:16:3e:6d:51:ba 是 ctl003 的 MAC,和迴圈的結果一致。
A2. keepalived.conf 的關鍵欄位
# [ctl](三台都看,比較差異)
sudo sed -E 's/(auth_pass).*/\1 ********/' /etc/kolla/keepalived/keepalived.conf預期輸出(以 ctl003 為例):
vrrp_script check_alive {
script "/check_alive.sh"
interval 2
fall 2
rise 10
}
vrrp_instance kolla_internal_vip_51 {
state BACKUP
nopreempt
interface ens3
virtual_router_id 51
priority 3
advert_int 1
virtual_ipaddress {
10.127.0.250 dev ens3
}
authentication {
auth_type PASS
auth_pass ********
}
track_script {
check_alive
}
}| 欄位 | 本環境的值 | 意義 |
|---|---|---|
virtual_ipaddress | 10.127.0.250 | VIP 位址 |
virtual_router_id | 51 | VRRP 群組識別碼;三節點須一致,且不可與同網段其他群組重複 |
priority | ctl001=1、ctl002=2、ctl003=3 | 選舉優先順序,數值高者成為 MASTER(三台唯一不同的欄位) |
advert_int | 1 | VRRP 通告間隔(秒) |
track_script | check_alive | 存活檢查;連續失敗 2 次(fall 2)就讓出 VIP |
authentication | auth_pass(已遮蔽) | VRRP 群組驗證,對應 passwords.yml 的 keepalived_password |
state BACKUP + nopreempt | 三台都是 | 啟動時都先當 BACKUP;原節點恢復後不會把 VIP 搶回來 |
check_alive 檢查的是什麼?
# [ctl]
sudo ls /etc/kolla/keepalived/checks/預期輸出:
check_alive_haproxy.sh check_alive_proxysql.sh兩個檢查都要通過:本機的 HAProxy(API 入口)與 ProxySQL(資料庫入口)任一個掛掉,這台就會讓出 VIP。
最後看 keepalived 的日誌:
# [ctl]
sudo docker logs --tail 50 keepalived 2>&1 | grep -E 'STATE|Stopping|Starting Keepalived'預期輸出(以 ctl003 為例;內容取決於這台最近的經歷):
Tue Oct 27 11:05:27 2026: Starting Keepalived v2.2.8 (04/04,2023), git commit v2.2.7-154-g292b299e+
Tue Oct 27 11:05:27 2026: (kolla_internal_vip_51) Entering BACKUP STATE
Tue Oct 27 11:07:17 2026: (kolla_internal_vip_51) Entering MASTER STATEA3. HAProxy:設定、Health Check 與排查
A3-a:有哪些服務經過 HAProxy?
# [ctl]
sudo ls /etc/kolla/haproxy/services.d/預期輸出:
cinder-api.cfg heat-api-cfn.cfg keystone.cfg neutron-server.cfg nova-novncproxy.cfg placement-api.cfg
glance-api.cfg heat-api.cfg memcached.cfg nova-api.cfg octavia-api.cfg rabbitmq.cfg
horizon.cfg nova-metadata.cfgA3-b:看 Keystone 與 Nova API 的前端 / 後端
# [ctl]
sudo cat /etc/kolla/haproxy/services.d/keystone.cfg
sudo cat /etc/kolla/haproxy/services.d/nova-api.cfg預期輸出(節錄 nova-api.cfg):
frontend nova_api_front
mode http
...
bind 10.127.0.250:8774
default_backend nova_api_back
backend nova_api_back
mode http
option httpchk
server ctl001-6161060-iaas 10.127.0.4:8774 check inter 2000 rise 2 fall 5
server ctl002-6161063-iaas 10.127.0.14:8774 check inter 2000 rise 2 fall 5
server ctl003-6161069-iaas 10.127.0.15:8774 check inter 2000 rise 2 fall 5| 機制 | 設定 | 意義 |
|---|---|---|
| 前端 | bind 10.127.0.250:8774 | 綁定 VIP 與服務的 API port;同一個 VIP,打 5000 進 Keystone、打 8774 進 Nova |
| 後端 | 三行 server | 三台 Controller 上的服務容器 |
| 分派 | 預設 round-robin | 輪流分派請求 |
檢查 inter 2000 | 2 秒 | 每 2 秒對每個後端檢查一次 |
檢查 fall 5 | ≈ 10 秒 | 連續失敗 5 次標記為 DOWN,停止分派新請求 |
檢查 rise 2 | ≈ 4 秒 | 恢復後連續成功 2 次標記為 UP,重新加入輪詢 |
※ 同一服務的三個後端都 DOWN 時,HAProxy 對該服務回應 503。
A3-c:容器狀態與日誌
# [ctl]
sudo docker ps --filter name=haproxy
sudo docker logs --tail 3 haproxy預期輸出:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
577ef466ec9c quay.io/openstack.kolla/haproxy:2025.1-ubuntu-noble "dumb-init --single-…" 10 days ago Up 10 days (healthy) haproxy
[WARNING] (18) : Server horizon_back/ctl002-6161063-iaas is UP, reason: Layer7 check passed, code: 302, check duration: 1913ms. 1 active and 0 backup servers online.
[WARNING] (18) : Server horizon_back/ctl003-6161069-iaas is UP, reason: Layer7 check passed, code: 302, check duration: 3ms. 2 active and 0 backup servers online.
[WARNING] (18) : Server horizon_back/ctl001-6161060-iaas is UP, reason: Layer7 check passed, code: 302, check duration: 2098ms. 3 active and 0 backup servers online.HAProxy 會把後端 DOWN / UP 的變化寫進日誌,排查間歇性錯誤時很有用。
A3-d:經由 VIP 確認 API 可回應
# [jmp001]
curl -s http://10.127.0.250:5000/v3 | head -c 100; echo預期輸出:
{"version": {"id": "v3.14", "status": "stable", "updated": "2020-04-07T00:00:00Z", "links": [{"rel":依症狀判斷排查方向(p.12)
| 症狀 | 優先檢查 |
|---|---|
| 所有 API 無回應 | VIP 是否存在(A1);持有 VIP 節點的 HAProxy 容器(A3-c) |
| 單一服務回應 503 | 該服務的三個後端是否皆為 DOWN(A3-c 日誌) |
| 間歇性錯誤 | 某一後端反覆 DOWN / UP,檢查該節點容器與資源(A3-c 日誌) |
| 回應緩慢 | 後端負載,以及資料庫與 RabbitMQ 狀態(Part B、C10) |
A4. ⚠️ 講師示範:VIP 切換演練
⚠️ 本節會短暫中斷全班的 API 存取,由講師執行;學員在自己的終端機觀察。 執行前提:僅於測試環境或已核准的維護窗口執行,並事先準備回復步驟。
學員準備(選用):持續打 Keystone,觀察切換瞬間
# [jmp001](學員各自開一個視窗;按 Ctrl+C 結束)
while true; do
printf '%s %s\n' "$(date +%T.%N | cut -c1-12)" \
"$(curl -s -o /dev/null -m 1 -w '%{http_code}' http://10.127.0.250:5000/v3)"
sleep 0.2
done講師演練步驟
# [jmp001] ⚠️ 講師執行
# 1. 找出目前持有 VIP 的節點(例:ctl003)
ssh 10.127.0.15 "sudo ip a | grep 10.127.0.250"
# 2. 停止該節點的 Keepalived 容器
ssh 10.127.0.15 "sudo docker stop keepalived"
# 3. 確認 VIP 已轉移至其他節點
for i in 4 14 15; do ssh 10.127.0.$i \
"hostname && sudo ip a | grep 10.127.0.250"; done
# 4. 確認 API 仍可正常回應
openstack endpoint list --service identity
openstack server list
# 5. 恢復服務
ssh 10.127.0.15 "sudo docker start keepalived"| 步驟 | 預期結果 |
|---|---|
| 1 確認現況 | VIP 位於 ctl003 |
| 2 停止 Keepalived | ctl003 移除 VIP,BACKUP 節點於數秒內接手 |
| 3 確認轉移 | VIP 出現在 ctl002(剩下兩台中 priority 最高),且只有一台 |
| 4 確認 API | 指令正常回應;切換瞬間學員的 curl 迴圈可能出現一次 000 |
| 5 恢復服務 | ctl003 重新加入 VRRP 群組,但因為 nopreempt,VIP 留在 ctl002 |
步驟 3 的預期輸出:
ctl001-6161060-iaas
ctl002-6161063-iaas
inet 10.127.0.250/32 scope global ens3
ctl003-6161069-iaas學員觀察切換的痕跡:
# [ctl002]
sudo docker logs --tail 5 keepalived 2>&1 | grep STATE
# [jmp001]
ip neigh show 10.127.0.250預期輸出:
Tue Oct 27 11:05:13 2026: (kolla_internal_vip_51) Entering MASTER STATE
10.127.0.250 dev ens3 lladdr fa:16:3e:96:93:5a REACHABLEjmp001 的 ARP 表自動換成 ctl002 的 MAC:新 MASTER 接手時會送出 gratuitous ARP,通知網路上的設備 VIP 換了位置。
| 切換期間的影響 | 不受影響的部分 |
|---|---|
| 進行中的 API 連線中斷,client 重試後即可恢復 | 已運行的 VM 與租戶資料平面流量(不經過 VIP) |
| VIP 位址不變,Endpoint 無須修改 | RabbitMQ 連線(不經過 VIP,Part B 會看到) |
停止 Keepalived 時,它會先送出 priority 0 的通告並移除 VIP,所以 BACKUP 幾乎立即接手;如果是整台主機斷電,BACKUP 要等通告逾時(約 3 × advert_int)才會接手。
Part B:RabbitMQ
OpenStack 各服務之間以 RabbitMQ 傳遞 RPC 訊息。本環境的 RabbitMQ 是三節點叢集,每台 Controller 各一個。
B1. 叢集成員與服務的連線方式
B1-a:叢集狀態
# [ctl]
sudo docker exec rabbitmq rabbitmqctl cluster_status預期輸出(節錄):
Cluster status of node rabbit@ctl001-6161060-iaas ...
Disk Nodes
rabbit@ctl001-6161060-iaas
rabbit@ctl002-6161063-iaas
rabbit@ctl003-6161069-iaas
Running Nodes
rabbit@ctl001-6161060-iaas
rabbit@ctl002-6161063-iaas
rabbit@ctl003-6161069-iaas
Versions
rabbit@ctl001-6161060-iaas: RabbitMQ 4.0.9 on Erlang 26.2.5.15
...
Alarms
(none)
Network Partitions
(none)
Listeners
Node: rabbit@ctl001-6161060-iaas, interface: 10.127.0.4, port: 15672, protocol: http, purpose: HTTP API
Node: rabbit@ctl001-6161060-iaas, interface: 10.127.0.4, port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Node: rabbit@ctl001-6161060-iaas, interface: 10.127.0.4, port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
...# [ctl]
sudo grep -E 'partition|classic_config' /etc/kolla/rabbitmq/rabbitmq.conf預期輸出:
cluster_partition_handling = pause_minority
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.0 = rabbit@ctl001-6161060-iaas
cluster_formation.classic_config.nodes.1 = rabbit@ctl002-6161063-iaas
cluster_formation.classic_config.nodes.2 = rabbit@ctl003-6161069-iaas| 項目 | 說明 |
|---|---|
| Running Nodes 含三節點 | 叢集成員健康 |
節點名稱 rabbit@<hostname> | 以主機 hostname 組成,這是部署後不能改 hostname 的原因之一 |
| port 5672 / 25672 / 15672 | AMQP / 叢集與 CLI 溝通 / 管理介面 |
pause_minority | 網路分割時,少數方自動暫停,避免兩邊各自運作 |
B1-b:服務怎麼連到 RabbitMQ?
# [ctl]
sudo grep '^transport_url' /etc/kolla/nova-api/nova.conf \
| sed -E 's#//[^:]+:[^@]+@#//openstack:****@#; s#,[^:]+:[^@]+@#,openstack:****@#g'預期輸出:
transport_url = rabbit://openstack:****@10.127.0.4:5672,openstack:****@10.127.0.14:5672,openstack:****@10.127.0.15:5672//transport_url 列出三個節點的位址,不是 VIP:oslo.messaging 直接連線,節點失效時自行切換到其他節點。所以 A4 的 VIP 切換不會影響既有的 RabbitMQ 連線。
B1-c:在管理介面觀察(選用,見 B5 的登入方式)
Overview 頁
| 區塊 | 會看到什麼 | 對照 |
|---|---|---|
| Totals | Connections 282、Channels 282、Exchanges 37、Queues 124、Consumers 403 | 整個叢集目前的物件數量 |
| Nodes | 三列:rabbit@ctl001/002/003-...,每列有 Memory(約 540–640 MiB / 上限約 9.4 GiB)、Disk space(約 164 GiB 可用)、File descriptors、Erlang processes、Uptime(約 10 天),全部是綠色 | B1-a 的 Running Nodes;B4 的記憶體與磁碟 |
| Ports and contexts | amqp 5672、clustering 25672、http 15672 | B1-a 的 Listeners |
任何一個節點的 Memory 或 Disk space 變成紅色,就代表觸發了 alarm(B4)。
Connections 頁
- 共約 282 條連線,每一列是一個 OpenStack 服務 process 對 RabbitMQ 的 AMQP 長連線
- Name 欄是「來源 → 目的」,例如
10.127.0.18:34118 -> 10.127.0.4:5672:來源是服務所在的主機,目的是 RabbitMQ 節點,不是 VIP - Client-provided name 欄寫著是哪個服務,例如
nova-compute:7:de1cdba3-... - Node 欄顯示連到哪一台 RabbitMQ:同一台主機的連線平均分散到三台節點。這就是
transport_url列出三個位址的效果(B1-b)
B2. Queue 深度與健康指標
B2-a:Queue 的類型
# [ctl]
sudo docker exec rabbitmq rabbitmqctl list_queues --quiet name type \
| awk 'NR>1 {print $2}' | sort | uniq -c預期輸出:
110 quorum
13 stream| 類型 | 在 OpenStack 的角色 |
|---|---|
| quorum | 一般 RPC:訊息以 Raft 複製到三節點,需多數節點存活(3 節點容許 1 台故障) |
| stream | fanout 廣播(名稱結尾為 _fanout):訊息保留一段時間,consumer 依 offset 讀取 |
B2-b:深度、未確認數與 consumer 數
# [ctl]
sudo docker exec rabbitmq rabbitmqctl list_queues \
name type messages_ready messages_unacknowledged consumers \
| grep -E '^(conductor|scheduler|compute|cinder-scheduler)' | sort | column -t預期輸出:
cinder-scheduler.ctl001-6161060-iaas quorum 0 0 1
cinder-scheduler_fanout stream 10710 0 3
cinder-scheduler quorum 0 0 3
compute_fanout stream 0 0 2
compute quorum 0 0 2
compute.scp001-6161072-iaas quorum 0 0 1
compute.scp002-6164930-iaas quorum 0 0 1
conductor.ctl001-6161060-iaas quorum 0 0 5
conductor_fanout stream 0 0 15
conductor quorum 0 0 14
scheduler.ctl001-6161060-iaas quorum 0 0 5
scheduler_fanout stream 10688 0 15
scheduler quorum 0 0 15
...| 指標 | 欄位 | 健康狀態 | 異常代表 |
|---|---|---|---|
| Queue 深度 | messages_ready | 不持續增加(RPC queue 幾乎都是 0) | Consumer 異常或處理速度不足 |
| 未確認訊息 | messages_unacknowledged | 低且會下降 | Worker 卡在外部操作或下游依賴 |
| Consumer | consumers | 大於 0 | 對應的服務沒有在聽這個 queue |
*_fanout 的 messages_ready 有上萬則:它們是 stream,訊息本來就會保留一段時間,不是堆積。
B2-c:在管理介面觀察(選用)
Queues and Streams 頁
- 共 124 個 queue;Type 欄分成
quorum與stream(B2-a) - Messages 區塊的 Ready、Unacked、Total 對應 B2-b 的 messages_ready、messages_unacknowledged;RPC queue 幾乎都是 0
- 用頁面上方的 Filter 輸入
compute,只留下與 nova-compute 相關的 queue - 點進
compute.scp001-6161072-iaas:區塊 會看到什麼 意義 Details → Type / Leader / Members / Online quorum;Leader rabbit@ctl002-6161063-iaas;Members 與 Online 都是三台quorum queue 以 Raft 複製到三台,其中一台是 leader;Online 少於 3 代表有節點離線 Consumers 1 個,來自 10.127.0.7(scp001),Prefetch count 1、Ack required ● 只有 scp001 的 nova-compute 在聽這個 queue(B3-b) Bindings (Default exchange binding)與nova→ routing keycompute.scp001-6161072-iaasB3-b 的 binding - 再點進
scheduler_fanout:Type 是 stream、Arguments 有x-max-age: 1800s,Messages 上萬則:stream 會保留 30 分鐘內的訊息,不是堆積
B3. AMQP 路由模型:在真實 RabbitMQ 中找到它們
B3-a:Exchange 與類型(p.17、p.19)
# [ctl]
sudo docker exec rabbitmq rabbitmqctl list_exchanges --quiet name type \
| grep -E '^(nova|neutron|compute_fanout|scheduler_fanout|amq\.direct)\s'預期輸出:
neutron topic
compute_fanout fanout
amq.direct direct
nova topic
scheduler_fanout fanout| Exchange | 類型 | 用途 |
|---|---|---|
nova、neutron | topic | 各服務的 RPC,依 routing key 送往對應的 queue |
compute_fanout、scheduler_fanout | fanout | 廣播給該服務的所有 worker |
amq.direct | direct | RabbitMQ 內建,routing key 精確比對 |
B3-b:Binding:routing key 怎麼對到 queue(p.18、p.20)
# [ctl]
sudo docker exec rabbitmq rabbitmqctl list_bindings --quiet source_name destination_name routing_key \
| grep -E '^(nova\s+compute|compute_fanout\s)'預期輸出:
nova compute compute
nova compute.scp001-6161072-iaas compute.scp001-6161072-iaas
nova compute.scp002-6164930-iaas compute.scp002-6164930-iaas
compute_fanout compute_fanout compute(欄位:Exchange、Queue、routing key)
這就是投影片 p.18 的實際樣子:nova-conductor 要在 scp001 建立 VM 時,以 routing key compute.scp001-6161072-iaas 發布到 nova exchange;只有 binding 相符的 queue compute.scp001-6161072-iaas 會收到,而這個 queue 只有 scp001 上的 nova-compute 在訂閱。
| 命名 | 例子 | 用途 |
|---|---|---|
<topic> | compute、conductor | 任一台的 worker 都可以處理(負載分散) |
<topic>.<host> | compute.scp001-6161072-iaas | 指定送給某一台主機 |
<topic>_fanout | compute_fanout | 廣播給所有 worker |
B3-c:reply queue:rpc.call 收回覆的地方(p.22、p.23)
# [ctl]
sudo docker exec rabbitmq rabbitmqctl list_queues --quiet name type consumers | grep -c '^reply_'
sudo docker exec rabbitmq rabbitmqctl list_queues --quiet name type consumers | grep '^reply_' | sort | head -5預期輸出:
41
reply_ctl001-6161060-iaas:cinder-api:1 quorum 1
reply_ctl001-6161060-iaas:cinder-api:2 quorum 1
reply_ctl001-6161060-iaas:cinder-api:3 quorum 1
reply_ctl001-6161060-iaas:cinder-api:4 quorum 1
reply_ctl001-6161060-iaas:nova-api:1 quorum 1| RPC 方式 | 是否需要 reply queue | 例子 |
|---|---|---|
rpc.cast | 不需要:丟出去就不等結果 | nova-conductor 對 nova-compute 發 build_and_run_instance |
rpc.call | 需要:呼叫方在自己的 reply_* queue 上等回覆 | nova-conductor 請 nova-scheduler 選出目的主機 |
每個會發出 rpc.call 的服務 process(例如 ctl001 上 cinder-api 的每個 worker)都有自己的 reply queue。
B3-d:⚠️ 講師示範:建立 VM 時的訊息流動(p.18、p.24)
學員先在控制節點開一個視窗,每秒列出「有待處理或未確認訊息」的 queue:
# [ctl](學員執行;按 Ctrl+C 結束)
watch -n 1 "sudo docker exec rabbitmq rabbitmqctl list_queues --quiet name type messages_ready messages_unacknowledged \
| awk '\$2 != \"stream\" && (\$3 > 0 || \$4 > 0)'"講師建立並刪除一台 VM:
# [jmp001] ⚠️ 講師執行
openstack server create --image cirros --flavor m1.tiny --network demo-net c9-mq-demo --wait
openstack server delete --wait c9-mq-demo預期現象:學員的視窗大多數時間是空的,建立 VM 的過程中會一閃而過出現 scheduler、conductor 或 compute.scp00X-...,深度為 1–2,例如:
compute.scp002-6164930-iaas quorum 0 1訊息一進入 queue 就被 consumer 取走,所以只看得到一瞬間。對照投影片 p.24:API → Conductor → Scheduler(rpc.call)→ Conductor → 目標 Compute Node(rpc.cast)。
B3-e:在管理介面觀察(選用)
Exchanges 頁
- 共 37 個 exchange:fanout 26、topic 7、direct 2、headers 2;預設的
(AMQP default)和amq.*是 RabbitMQ 內建的 - 點進
nova(Type: topic),往下看 Bindings:To Routing key computecomputecompute.scp001-6161072-iaascompute.scp001-6161072-iaascompute.scp002-6164930-iaascompute.scp002-6164930-iaasconductorconductorconductor.ctl001-6161060-iaasconductor.ctl001-6161060-iaas… … 這就是投影片 p.18 的 binding 表:
novaexchange 依 routing key 把訊息送到對應的 queue - 點進
compute_fanout(Type: fanout):只有一個 binding,訊息會複製給所有綁定的 queue
Overview 頁的 Message rates(搭配 B3-d)
講師建立 VM 時,看 Overview 上方的 Message rates 圖:平時 Publish 約每秒 1 則以下,建立 VM 的那幾秒會出現 publish / deliver 的尖峰。訊息進來就被取走,所以 Queued messages 圖幾乎不會變化。
B4. Broker 狀態與快速健康檢查
# [ctl]
sudo docker exec rabbitmq rabbitmqctl status | grep -E 'Total memory used|Memory high watermark|Free disk space|Low free disk'
sudo docker exec rabbitmq rabbitmqctl status | sed -n '/^Alarms/,+2p'
sudo docker exec rabbitmq rabbitmq-diagnostics check_running
sudo docker exec rabbitmq rabbitmq-diagnostics check_local_alarms預期輸出:
Total memory used: 0.5537 gb
Memory high watermark setting: 0.6 of available memory, computed to: 10.0612 gb
Low free disk space watermark: 0.05 gb
Free disk space: 176.6141 gb
Alarms
(none)
Checking if RabbitMQ is running on node rabbit@ctl001-6161060-iaas ...
RabbitMQ on node rabbit@ctl001-6161060-iaas is fully booted and running
Asking node rabbit@ctl001-6161060-iaas to report any local resource alarms ...
Node rabbit@ctl001-6161060-iaas reported no local alarms| 資源 | 門檻 | 超過時 |
|---|---|---|
| 記憶體 | high watermark(可用記憶體的 60%) | 觸發 memory alarm,阻擋發布端連線,OpenStack 的 RPC 會卡住 |
| 磁碟 | low free disk watermark | 觸發 disk alarm,同樣阻擋發布端 |
在管理介面中,同樣的資訊在 Overview → Nodes:Memory、Disk space 欄位正常時是綠色、觸發 alarm 時變紅色,並顯示門檻(memory high watermark、disk free limit)。
B5. RabbitMQ 管理介面(選用)
登入:用瀏覽器登入 https://teleport.sretest.app,在資源清單選擇 rabbitmq 應用程式(或直接開啟 https://rabbitmq.teleport.sretest.app),再以唯讀帳號 monitoring 與講師提供的密碼登入。右上角會顯示 User monitoring 與 Cluster rabbit@ctl00X-...。
各頁面可以看到什麼
| 頁面 | 可以看到什麼 | 對應的實驗 |
|---|---|---|
| Overview | • 物件總數(connections、channels、exchanges、queues、consumers) • 三台節點的記憶體、磁碟、檔案描述子、uptime • 訊息速率(publish / deliver)與佇列中的訊息數 • 監聽的 port(5672 / 25672 / 15672) | B1-c、B3-e、B4 |
| Connections | • 每個服務 process 的 AMQP 連線 • 來源主機(Client-provided name 看得出是哪個服務) • 連到哪一台 RabbitMQ 節點 | B1-c |
| Channels | • 每條連線上的 channel • prefetch • 未確認(Unacked)訊息數 | — |
| Exchanges | • exchange 名稱與類型(fanout / topic / direct / headers) • 點進 nova 可看到它的 binding• 各 exchange 的訊息速率 | B3-e |
| Queues and Streams | • queue 的類型(quorum / stream / classic)與深度(Ready / Unacked) • quorum queue 的 leader 與成員 • consumer 與 binding • stream 的 x-max-age | B2-c |
| Admin | • Virtual Hosts(只有 /)• Feature Flags、Deprecated Features • Policies(目前沒有設定) | B5 |