Vấn đề thực tế: Single-node RabbitMQ và điểm chịu lỗi duy nhất
Mình từng chứng kiến một hệ thống xử lý đơn hàng e-commerce bị tê liệt hoàn toàn chỉ vì server chạy RabbitMQ single-node bị OOM killer lúc 2 giờ sáng. Toàn bộ message đang pending trong queue biến mất, 200+ consumer process phải restart thủ công, và dev team mất gần 3 tiếng để khôi phục trạng thái bình thường.
Đây không phải lỗi của RabbitMQ — đây là vấn đề kiến trúc. Khi có single point of failure, câu hỏi không phải là “có bị sập không” mà là “bao giờ sập”. RabbitMQ cluster giải quyết điều này bằng cách replicate queue metadata qua nhiều node. Với Quorum Queue, ngay cả message data cũng được replicate — không mất message dù một node die giữa chừng.
Mình dùng Fedora làm máy development chính được 2 năm và khá ưng với tốc độ cập nhật package. Nhưng khi triển khai lên production Fedora Server, SELinux và firewalld hay sinh chuyện không báo trước. RabbitMQ đặc biệt “dễ vấp” vì cần mở nhiều port lạ và ghi vào nhiều path khác nhau — những thứ SELinux policy mặc định không cover hết.
Ba cách triển khai RabbitMQ cluster phổ biến
Cách 1: Bare-metal cluster (cài trực tiếp lên OS)
Cài gói rabbitmq-server trực tiếp lên từng server, đồng bộ Erlang cookie, rồi join cluster bằng rabbitmqctl join_cluster. Cách này cho phép kiểm soát từng chi tiết — từ file descriptor limits, memory watermarks đến SELinux context của từng file.
Ưu điểm: Không có container overhead, dễ monitor qua systemd/journald, tích hợp tốt với Prometheus node_exporter. Erlang 26 có sẵn trong repo Fedora 40 — không cần thêm EPEL hay repo ngoài như trên CentOS Stream.
Nhược điểm: Phải xử lý SELinux và firewalld thủ công. Rolling upgrade đòi hỏi cẩn thận hơn. Khó reproduce môi trường dev.
Cách 2: Podman cluster với persistent volume
Dùng image rabbitmq:3-management, tạo pod hoặc dùng Podman Compose. Podman là lựa chọn mặc định trên Fedora — hỗ trợ rootless container tốt hơn Docker và không cần daemon chạy nền.
Ưu điểm: Portable, dễ upgrade bằng cách pull image mới, không cần xử lý SELinux ở application-level vì container đã isolate sẵn.
Nhược điểm: Vẫn phải cấu hình firewalld cho port expose ra ngoài. Network giữa nhiều Podman host cần thêm layer — VPN hoặc overlay network. Persistent volume với SELinux label :z hay bị quên và gây lỗi permission khó debug.
Cách 3: Kubernetes với RabbitMQ Cluster Operator
Dùng RabbitMQ Cluster Operator deploy qua Helm. Operator tự quản lý việc join/leave cluster, xử lý rolling upgrade và scale in/out.
Ưu điểm: Fully automated, self-healing, tích hợp tốt với monitoring stack Kubernetes.
Nhược điểm: Overhead của Kubernetes không nhỏ — cần ít nhất 3 worker node chỉ để chạy control plane đúng cách. Với workload nhỏ-trung trên VPS bare-metal, đây là overkill rõ ràng.
Chọn cách nào cho Fedora Server?
Tùy hạ tầng hiện tại:
- VPS bare-metal 2–3 server, muốn kiểm soát tối đa, không có Kubernetes → Bare-metal cluster
- Đã có Podman infrastructure, cần portability và dễ reproduce → Podman cluster
- Đang chạy Kubernetes, muốn tích hợp cùng ecosystem → K8s Operator
Mình sẽ hướng dẫn bare-metal cluster — trường hợp phổ biến nhất với Fedora Server trên VPS, và cũng là nơi SELinux + firewalld gây friction nhiều nhất nếu không cấu hình đúng từ đầu.
Triển khai RabbitMQ cluster 3 node trên Fedora Server
Bước 0: Chuẩn bị hostname và /etc/hosts
Cần 3 server Fedora Server 40+. Mình dùng:
rmq1— 192.168.1.10rmq2— 192.168.1.11rmq3— 192.168.1.12
Thêm vào /etc/hosts trên cả 3 node. RabbitMQ cluster nhận diện node bằng hostname, không phải IP — sai chỗ này là nguồn gốc của phần lớn lỗi “node not found” khi join cluster:
sudo tee -a /etc/hosts <<EOF
192.168.1.10 rmq1
192.168.1.11 rmq2
192.168.1.12 rmq3
EOF
Đặt hostname khớp với tên đã khai báo:
# Chạy trên từng node tương ứng
sudo hostnamectl set-hostname rmq1 # hoặc rmq2, rmq3
Bước 1: Cài đặt Erlang và RabbitMQ
Fedora 40 có Erlang 26 trong repo chính thức — không cần thêm EPEL hay repo ngoài như trên CentOS Stream:
# Chạy trên cả 3 node
sudo dnf install -y erlang rabbitmq-server
# Kiểm tra phiên bản
erl -version
rabbitmqctl version
# Bật và khởi động service
sudo systemctl enable --now rabbitmq-server
Bước 2: Đồng bộ Erlang cookie — bước hay bị bỏ qua nhất
Erlang nodes chỉ giao tiếp được khi share cùng một Erlang cookie — chuỗi ký tự lưu ở /var/lib/rabbitmq/.erlang.cookie. Cookie không khớp sinh ra lỗi “authentication failed” rất khó phân biệt với lỗi network hay firewall — đây là bước bị skip phổ biến nhất khi setup cluster lần đầu.
# Trên rmq1: đọc cookie hiện tại
sudo cat /var/lib/rabbitmq/.erlang.cookie
# Output ví dụ: WKDXQABCMNOPQRSTUVWX
# Dừng service trước khi sửa
sudo systemctl stop rabbitmq-server
# Trên rmq2 và rmq3: ghi đè bằng cookie từ rmq1
echo -n "WKDXQABCMNOPQRSTUVWX" | sudo tee /var/lib/rabbitmq/.erlang.cookie
sudo chmod 400 /var/lib/rabbitmq/.erlang.cookie
sudo chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie
# Khởi động lại trên cả 3 node
sudo systemctl start rabbitmq-server
Bước 3: Cấu hình SELinux cho RabbitMQ
Fedora không có SELinux policy sẵn cho tất cả port RabbitMQ cluster dùng. Port 25672 (Erlang distribution) và 4369 (EPMD) thường bị chặn mà audit log không rõ ràng — dễ nhầm sang lỗi firewall.
Kiểm tra SELinux đang chặn gì trước:
sudo ausearch -m avc -ts recent | grep rabbitmq
# hoặc
sudo journalctl -u rabbitmq-server | grep -i denied
Thêm các port vào type amqp_port_t:
# Cài công cụ quản lý SELinux port
sudo dnf install -y policycoreutils-python-utils
# Thêm port cho AMQP, Management UI, Erlang distribution và EPMD
sudo semanage port -a -t amqp_port_t -p tcp 5672
sudo semanage port -a -t amqp_port_t -p tcp 15672
sudo semanage port -a -t amqp_port_t -p tcp 25672
sudo semanage port -a -t amqp_port_t -p tcp 4369
# Xác nhận
sudo semanage port -l | grep amqp
Vẫn gặp lỗi permission sau khi mở port? Tạo custom SELinux module từ audit log:
sudo ausearch -c 'beam.smp' --raw | audit2allow -M rabbitmq_custom
sudo semodule -i rabbitmq_custom.pp
# Kiểm tra module đã load chưa
sudo semodule -l | grep rabbitmq
Bước 4: Cấu hình firewalld
RabbitMQ cluster cần 4 port chính giữa các node:
- 4369/tcp — EPMD (Erlang Port Mapper Daemon) — node discovery
- 5672/tcp — AMQP protocol — consumer/producer kết nối
- 25672/tcp — Erlang distribution — inter-node cluster communication
- 15672/tcp — Management Web UI (nên giới hạn source IP)
# Mở port cluster communication trên cả 3 node
sudo firewall-cmd --permanent --add-port=4369/tcp
sudo firewall-cmd --permanent --add-port=5672/tcp
sudo firewall-cmd --permanent --add-port=25672/tcp
# Management UI — giới hạn chỉ mạng nội bộ
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="15672" accept'
# Reload
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports
Bước 5: Join cluster
Erlang cookie đồng bộ xong, port đã mở — giờ join node2 và node3 vào node1:
# Trên rmq2:
sudo rabbitmqctl stop_app
sudo rabbitmqctl reset
sudo rabbitmqctl join_cluster rabbit@rmq1
sudo rabbitmqctl start_app
# Trên rmq3:
sudo rabbitmqctl stop_app
sudo rabbitmqctl reset
sudo rabbitmqctl join_cluster rabbit@rmq1
sudo rabbitmqctl start_app
# Kiểm tra trạng thái cluster từ bất kỳ node nào
sudo rabbitmqctl cluster_status
Output đúng sẽ liệt kê đủ 3 node trong running_nodes: rabbit@rmq1, rabbit@rmq2, rabbit@rmq3.
Bước 6: Tạo Quorum Queue và admin user
Classic Mirrored Queue bị deprecated từ RabbitMQ 3.9. Dùng Quorum Queue thay — replication dựa trên Raft consensus, an toàn và predictable hơn hẳn. Với cluster 3 node, Raft cần đa số (2/3) để commit, nên hàng đợi vẫn hoạt động khi 1 node chết.
# Bật Management Plugin
sudo rabbitmq-plugins enable rabbitmq_management
# Tạo admin user — đừng dùng guest trên production
sudo rabbitmqctl add_user admin StrongPassword123
sudo rabbitmqctl set_user_tags admin administrator
sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
# Xóa guest user mặc định
sudo rabbitmqctl delete_user guest
# Tạo Quorum Queue qua CLI
sudo rabbitmqadmin declare queue name=order_queue durable=true \
arguments='{"x-queue-type":"quorum"}'
Test cluster: Publish từ node này, consume từ node khác
Kiểm tra nhanh bằng Python — publish vào rmq2, consume từ rmq3:
import pika
# Publish từ rmq2
conn = pika.BlockingConnection(
pika.ConnectionParameters(
host='192.168.1.11',
credentials=pika.PlainCredentials('admin', 'StrongPassword123')
)
)
channel = conn.channel()
channel.queue_declare(
queue='order_queue', durable=True,
arguments={'x-queue-type': 'quorum'}
)
channel.basic_publish(exchange='', routing_key='order_queue', body='test-message')
conn.close()
print("Published")
Sau đó consume từ 192.168.1.12 (rmq3) với code tương tự. Message vẫn đọc được vì Quorum Queue replicate data qua cả 3 node. Thử tắt rmq2 đi rồi consume lại — hàng đợi vẫn chạy bình thường. Đó là HA thực sự, không phải chỉ trên paper.
Những lỗi thường gặp và cách xử lý
“Node ‘rabbit@rmq2’ not running” khi join cluster → Kiểm tra hostname trong /etc/hosts. Sai hostname là nguyên nhân số 1. Chạy sudo rabbitmqctl status để xem node đang tự nhận diện mình là gì.
“Authentication failed” khi join → Erlang cookie không khớp. Dừng service, copy lại cookie từ rmq1, đặt permission 400, restart.
“Permission denied” dù firewalld đã mở port → SELinux block, không phải firewall. Mình từng mất cả buổi chiều debug vì tưởng là firewalld block nhưng thực ra SELinux không cho beam.smp bind port 25672. Bài học: luôn check /var/log/audit/audit.log trực tiếp thay vì chỉ dùng ausearch — khi log bị rotate, ausearch -ts recent sẽ miss mất context.
Cluster split-brain sau network partition → Quorum Queue dùng Raft: partition có đa số node (≥2/3) tiếp tục nhận write, partition còn lại tự block. Không có inconsistency data — đây là lý do chính nên migrate từ Classic Mirrored Queue sang Quorum Queue.

