Chuyển tới nội dung chính

Backup và restore thủ công cho RabbitMQ

Backup trên nền tảng đã bị gỡ khỏi RabbitMQ từ 15/09/2026, nên việc bảo vệ cấu hình của cụm giờ do bạn tự vận hành. Trang này export definitions của cụm qua Management HTTP API, kiểm tra file có đầy đủ không, rồi import sang một cụm mới.

cảnh báo

Cách này chỉ backup definitions — vhost, user, permission, exchange, queue, binding và policy. Message đang nằm trong queue không được gồm vào và không thể khôi phục bằng cách này.

Áp dụng cho RabbitMQ 3.13.x trên Erlang 26.x.

Definitions gồm những gì​

Thành phầnNội dung
VhostCác virtual host
User và permissionTài khoản và quyền truy cập
ExchangeDirect, topic, fanout và headers
QueueKhai báo queue cùng các argument
BindingLiên kết giữa exchange và queue
PolicyTTL, HA, max-length, dead-letter và các loại còn lại

Cơ chế hoạt động​

Chạy mọi thứ từ một backup server — một VM của bạn, thông tới cụm RabbitMQ ở port 15672. Nó gọi thẳng Management HTTP API, nên không phải cài gì lên cụm và không node nào bị dừng.

Giai đoạnDiễn ra điều gì
BackupBackup server gọi GET /api/definitions trên cụm nguồn và lưu file JSON
RestoreBackup server POST file đã lưu tới POST /api/definitions trên cụm đích

Trong lúc restore, cụm nguồn hoàn toàn không bị gọi tới.

Điều kiện tiên quyết​

Hạng mụcYêu cầu
MạngBackup server thông tới cụm ở port 15672
Tài khoảnUser có tag administrator
Phiên bản đíchKhi restore, phiên bản RabbitMQ của cụm đích phải bằng hoặc cao hơn cụm nguồn
Phiên bản ErlangNên khớp với cụm nguồn

Các lệnh bên dưới dùng những placeholder sau: <HOST> là địa chỉ cụm nguồn và <TARGET_HOST> là cụm đích, <USERNAME> và <PASSWORD> là thông tin đăng nhập administrator, <VHOST_NAME> là tên một vhost, <TIMESTAMP> là dấu thời gian trong tên file đã lưu, còn <RABBITMQ_HOST> là địa chỉ mà script chạy theo lịch đọc vào.

Backup definitions​

Export toàn bộ cụm​

curl -s \
-u '<USERNAME>:<PASSWORD>' \
http://<HOST>:15672/api/definitions \
-o /backup/rabbitmq/rabbitmq_definitions_$(date +%Y%m%d_%H%M%S).json

Ví dụ:

curl -s \
-u 'admin:your_password' \
http://10.0.1.10:15672/api/definitions \
-o /backup/rabbitmq/rabbitmq_definitions_$(date +%Y%m%d_%H%M%S).json

Export riêng một vhost​

curl -s \
-u '<USERNAME>:<PASSWORD>' \
'http://<HOST>:15672/api/definitions/<VHOST_NAME>' \
-o /backup/rabbitmq/rabbitmq_vhost_<VHOST_NAME>_$(date +%Y%m%d_%H%M%S).json

Ví dụ — backup vhost app_production:

curl -s \
-u 'admin:your_password' \
'http://10.0.1.10:15672/api/definitions/app_production' \
-o /backup/rabbitmq/rabbitmq_vhost_production_$(date +%Y%m%d_%H%M%S).json
cảnh báo

Export theo vhost bỏ sót user và global parameter. Hãy dùng bản export toàn cụm khi file này để phục vụ migrate đầy đủ.

Kiểm tra file trước khi tin nó​

Một bản export trả về trang lỗi thì vẫn là một file nằm trên đĩa, nên hãy đếm xem nó chứa gì:

python3 << 'EOF'
import json

with open("/backup/rabbitmq/rabbitmq_definitions_<TIMESTAMP>.json") as f:
d = json.load(f)

print(f"Vhosts: {len(d.get('vhosts', []))}")
print(f"Users: {len(d.get('users', []))}")
print(f"Exchanges: {len(d.get('exchanges', []))}")
print(f"Queues: {len(d.get('queues', []))}")
print(f"Bindings: {len(d.get('bindings', []))}")
print(f"Policies: {len(d.get('policies', []))}")
EOF

Các con số phải khớp với cụm nguồn:

Vhosts:      4
Users: 5
Exchanges: 5
Queues: 8
Bindings: 8
Policies: 3

Restore sang cụm mới​

Import file​

curl -s -X POST \
-u '<USERNAME>:<PASSWORD>' \
-H "Content-Type: application/json" \
-d @/backup/rabbitmq/rabbitmq_definitions_<TIMESTAMP>.json \
http://<TARGET_HOST>:15672/api/definitions

Ví dụ:

curl -s -X POST \
-u 'admin:your_password' \
-H "Content-Type: application/json" \
-d @/backup/rabbitmq/rabbitmq_definitions_20260519_020001.json \
http://10.0.2.10:15672/api/definitions

Đọc mã phản hồi​

Import thành công thì không in ra gì, nên hãy hỏi thẳng mã trạng thái:

curl -s -o /dev/null -w "%{http_code}\n" -X POST \
-u 'admin:your_password' \
-H "Content-Type: application/json" \
-d @/backup/rabbitmq/rabbitmq_definitions_20260519_020001.json \
http://10.0.2.10:15672/api/definitions
MãÝ nghĩa
200Import thành công
400File JSON không hợp lệ
401Sai username hoặc password
403User không có tag administrator

Đối chiếu hai cụm​

So số lượng ở cả hai bên thay vì mặc định rằng import đã đầy đủ:

python3 << 'EOF'
import json, urllib.request, base64

def get_definitions(host, user, password):
url = f"http://{host}:15672/api/definitions"
req = urllib.request.Request(url)
token = base64.b64encode(f"{user}:{password}".encode()).decode()
req.add_header("Authorization", f"Basic {token}")
with urllib.request.urlopen(req) as r:
return json.load(r)

SOURCE = get_definitions("10.0.1.10", "admin", "your_password")
DEST = get_definitions("10.0.2.10", "admin", "your_password")

keys = ["vhosts", "users", "exchanges", "queues", "bindings", "policies"]

print(f"{'Thành phần':<15} {'Nguồn':>8} {'Đích':>8} {'Khớp':>8}")
print("-" * 45)
for k in keys:
src = len(SOURCE.get(k, []))
dst = len(DEST.get(k, []))
match = "OK" if src == dst else "LỆCH"
print(f"{k:<15} {src:>8} {dst:>8} {match:>8}")
EOF

Kết quả mong đợi:

Thành phần      Nguồn     Đích     Khớp
---------------------------------------------
vhosts 4 4 OK
users 5 5 OK
exchanges 5 5 OK
queues 8 8 OK
bindings 8 8 OK
policies 3 3 OK

Những điều cần lường trước khi import​

Password được giữ nguyên. File definitions lưu hash của password chứ không phải plaintext, và các hash đó import y nguyên. User giữ đúng mật khẩu cũ trên cụm đích.

HA policy cần đủ node mới có tác dụng. Policy ha-mode: all import được vào mọi cụm, nhưng chỉ có hiệu lực khi cụm có tối thiểu ba node. Hãy cho cụm đích topology tương đương cụm nguồn.

Import nhiều lần vẫn an toàn. Thao tác này idempotent: resource đã tồn tại sẽ được cập nhật hoặc giữ nguyên, không bao giờ bị xoá. Chạy lại một lần import thất bại không gây hại gì.

Tên cluster không bị ghi đè. cluster_name trong file chỉ mang tính tham khảo. Cụm đích giữ nguyên tên của chính nó.

Tự động hoá​

Script backup​

Tạo file /opt/backup/rabbitmq_backup.sh:

#!/bin/bash

# ---- Configuration ----
HOST="<RABBITMQ_HOST>"
USER="admin"
PASS='your_password'
BACKUP_DIR="/backup/rabbitmq"
RETENTION_DAYS=30
# ------------------

mkdir -p "$BACKUP_DIR"

FILENAME="rabbitmq_definitions_$(date +%Y%m%d_%H%M%S).json"
FILEPATH="${BACKUP_DIR}/${FILENAME}"

curl -s \
-u "${USER}:${PASS}" \
"http://${HOST}:15672/api/definitions" \
-o "$FILEPATH"

if [ $? -eq 0 ] && [ -s "$FILEPATH" ]; then
echo "[OK] Backup thành công: ${FILENAME}"
find "$BACKUP_DIR" -name "rabbitmq_definitions_*.json" \
-mtime +${RETENTION_DAYS} -delete
else
echo "[FAIL] Backup thất bại!"
rm -f "$FILEPATH"
exit 1
fi

Cấp quyền thực thi:

chmod +x /opt/backup/rabbitmq_backup.sh
mẹo

Đặt PASS trong dấu nháy đơn. Password chứa ký tự ! sẽ kích hoạt history expansion của bash nếu để trong nháy kép, và script gửi đi sai thông tin đăng nhập.

Đặt lịch và theo dõi​

crontab -e

Thêm dòng chạy hằng ngày lúc 02:00:

0 2 * * * /opt/backup/rabbitmq_backup.sh >> /var/log/rabbitmq_backup.log 2>&1

Rồi xem log sau lần chạy theo lịch đầu tiên:

tail -f /var/log/rabbitmq_backup.log

Kết quả mỗi lần chạy thành công:

[OK] Backup thành công: rabbitmq_definitions_20260519_020001.json

Bước tiếp theo​