Cấu hình Prometheus và Grafana để giám sát Raft và TDE
Để hệ thống phân tán hoạt động ổn định, bạn cần thu thập các chỉ số (metrics) về độ trễ đồng bộ (replication lag), trạng thái bầu cử (election) của Raft và hiệu suất mã hóa của TDE.
Tại sao: PostgreSQL mặc định không xuất các metric này ra dạng Prometheus. Ta cần dùng extension pg_exporter kết hợp với custom query để trích xuất dữ liệu từ pg_wal và log hệ thống.
Kết quả mong đợi: Prometheus có thể scrape được các endpoint, Grafana hiển thị dashboard với các đường cong latency và key status.
Bước 1: Cài đặt và cấu hình Prometheus Exporter cho PostgreSQL
Tạo file cấu hình pg_exporter.yml để định nghĩa các custom query giám sát Raft và TDE.
Đường dẫn: /etc/pg_exporter/custom_queries.yml
Nội dung file:
metrics:
- query: SELECT pg_current_wal_lsn() AS current_lsn,
pg_last_xact_replay_timestamp() AS last_replay_ts,
extract(epoch from (now() - pg_last_xact_replay_timestamp())) AS lag_seconds
help: "Replication lag in seconds for Raft followers"
metrics:
- lag_seconds:
help: "Replication lag in seconds"
type: GAUGE
- query: SELECT name, setting FROM pg_settings WHERE name IN ('encryption_key', 'tde_status')
help: "TDE Status and key info"
metrics:
- tde_status:
help: "Transparent Data Encryption status"
type: GAUGE
value: setting
- query: SELECT cluster_name, role, state, is_leader FROM pg_hba_auth WHERE type = 'host' AND user = 'replicator'
help: "Raft cluster state"
metrics:
- raft_role:
help: "Current Raft role of the node"
type: GAUGE
value: case when is_leader = 'on' then 1 else 0 end
Kết quả mong đợi: File cấu hình được tạo, sẵn sàng để exporter đọc.
Bước 2: Khởi động Prometheus Exporter
Chạy container hoặc service postgres_exporter trỏ vào database của bạn.
Đường dẫn config: /etc/prometheus/prometheus.yml (phần scrape_configs)
Nội dung cấu hình Prometheus:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'postgresql-raft-tde'
static_configs:
- targets: ['10.0.0.10:9187', '10.0.0.11:9187', '10.0.0.12:9187']
metrics_path: /metrics
params:
namespace: ['db_cluster']
relabel_configs:
- source_labels: [__address__]
target_label: instance
regex: '(.+):9187'
replacement: '${1}'
Kết quả mong đợi: Prometheus có thể scrape dữ liệu từ 3 node, xuất hiện metric db_cluster_replication_lag_seconds và
db_cluster_tde_status.
Bước 3: Deploy Dashboard Grafana
Nạp JSON dashboard vào Grafana để trực quan hóa dữ liệu.
Đường dẫn: /var/lib/grafana/dashboards/raft-tde-dashboard.json
Nội dung JSON (rút gọn các panel quan trọng):
{
"dashboard": {
"id": null,
"uid": "raft-tde-monitor",
"title": "Raft & TDE Cluster Monitor",
"panels": [
{
"id": 1,
"title": "Replication Lag (Raft)",
"type": "graph",
"targets": [
{
"expr": "db_cluster_replication_lag_seconds{instance=~\"$instance\"}",
"legendFormat": "{{instance}}"
}
]
},
{
"id": 2,
"title": "TDE Encryption Status",
"type": "stat",
"targets": [
{
"expr": "db_cluster_tde_status{instance=~\"$instance\"}",
"legendFormat": "{{instance}}"
}
]
},
{
"id": 3,
"title": "Raft Leader Election Count",
"type": "singlestat",
"targets": [
{
"expr": "rate(db_cluster_raft_election_total[5m])",
"legendFormat": "Elections per 5m"
}
]
}
]
}
}
Kết quả mong đợi: Dashboard hiện lên trên giao diện Grafana, bạn thấy các chỉ số lag và trạng thái mã hóa theo thời gian thực.
Phân tích và xử lý lỗi phổ biến
Trong môi trường phân tán có mã hóa, 3 lỗi thường gặp nhất là Split-brain, Key mismatch và Replication lag quá cao.
Tại sao: Lỗi này thường xảy ra do mạng chập chờn, quản lý khóa không đồng bộ hoặc I/O không theo kịp tốc độ ghi.
Kết quả mong đợi: Hệ thống tự động hoặc thủ động khôi phục trạng thái nhất quán, dữ liệu không bị mất.
Xử lý lỗi Split-brain (Chia tách cụm)
Split-brain xảy ra khi mạng chia cắt khiến hai node đều nghĩ mình là Leader và chấp nhận ghi dữ liệu.
Cách xử lý: Sử dụng cơ chế Quorum (đa số) của Raft. Nếu không có đa số, node sẽ tự động chuyển sang trạng thái LEARNER hoặc
STOPPED.
Thao tác kiểm tra và khôi phục:
# Kiểm tra trạng thái của tất cả node trong cụm
psql -h 10.0.0.10 -U admin -d db_cluster -c "SELECT node_id, role, state FROM raft_status;"
# Nếu phát hiện 2 node đều có role = 'LEADER', hãy tắt node có lag lớn hơn hoặc node bị cô lập
# Giả sử node 10.0.0.12 bị cô lập và tự phong mình là leader
psql -h 10.0.0.12 -U admin -d db_cluster -c "SELECT raft_demote_leader();"
# Kiểm tra lại xem chỉ còn 1 leader duy nhất
psql -h 10.0.0.10 -U admin -d db_cluster -c "SELECT node_id, role FROM raft_status WHERE role = 'LEADER';"
Kết quả mong đợi: Chỉ còn 1 node duy nhất có role là LEADER, các node khác chuyển về
FOLLOWER và bắt đầu đồng bộ lại.
Xử lý lỗi Key Mismatch (Không khớp khóa mã hóa)
Lỗi này xảy ra khi Follower có key mã hóa khác với Leader (do rotation key chưa đồng bộ xong).
Cách xử lý: Kiểm tra log pg_log để tìm thông báo Encryption key mismatch và thực hiện đồng bộ key.
Thao tác:
# Tìm lỗi trong log
grep "key mismatch" /var/log/postgresql/postgresql-14-main.log
# Kiểm tra version của key hiện tại trên Leader và Follower
psql -h 10.0.0.10 -U admin -d db_cluster -c "SELECT key_id, key_version FROM tde_keys WHERE is_active = true;"
psql -h 10.0.0.11 -U admin -d db_cluster -c "SELECT key_id, key_version FROM tde_keys WHERE is_active = true;"
# Nếu khác nhau, thực hiện lệnh đồng bộ key từ Leader sang Follower (giả định có script)
ssh 10.0.0.11 "/opt/scripts/sync_tde_key.sh --from 10.0.0.10 --key-id current_key_id"
# Verify lại
psql -h 10.0.0.11 -U admin -d db_cluster -c "SELECT key_version FROM tde_keys WHERE is_active = true;"
Kết quả mong đợi: Giá trị key_version trên cả Leader và Follower giống hệt nhau, lỗi replication dừng lại.
Xử lý Replication Lag cao
Khi lag vượt quá ngưỡng (ví dụ > 5s), có thể do I/O của Follower quá chậm để giải mã và ghi WAL.
Cách xử lý: Tăng wal_sender_timeout tạm thời và kiểm tra I/O queue.
Thao tác:
# Kiểm tra lag hiện tại
psql -h 10.0.0.10 -U admin -d db_cluster -c "SELECT client_addr, sent_lsn, write_lsn, flush_lsn, replay_lsn, extract(epoch from (now() - replay_lsn)) as lag_seconds FROM pg_replication_slots;"
# Nếu lag > 30s, tăng timeout để không kill connection (tạm thời)
psql -h 10.0.0.10 -U admin -d db_cluster -c "ALTER SYSTEM SET wal_sender_timeout = '30s'; SELECT pg_reload_conf();"
# Kiểm tra I/O wait trên Follower
iostat -x 1 5
Kết quả mong đợi: Lag giảm dần, không còn connection bị kill do timeout.
Tối ưu hóa hiệu năng I/O với Mã hóa và Đồng bộ
Khi bật TDE và Raft, CPU và I/O tăng đáng kể. Cần điều chỉnh postgresql.conf để cân bằng.
Tại sao: TDE tốn CPU để mã hóa/giải mã, Raft tốn I/O để ghi WAL nhiều lần (Leader ghi, Follower ghi).
Kết quả mong đợi: Throughput tăng, Latency giảm, không bị nghẽn cổ chai (bottleneck).
Điều chỉnh bộ nhớ và WAL
Tăng shared_buffers và wal_buffers để giảm số lần I/O vật lý.
Đường dẫn: /etc/postgresql/14/main/postgresql.conf
Nội dung cần chỉnh sửa:
# Tăng bộ nhớ cache cho WAL để giảm I/O khi có nhiều transaction
wal_buffers = 256MB
# Tăng shared_buffers (thường là 25-40% RAM)
shared_buffers = 4GB
# Tối ưu hóa checkpoint để tránh I/O spike khi có TDE
checkpoint_completion_target = 0.9
max_wal_size = 4GB
min_wal_size = 1GB
# Bật parallel worker cho query để tận dụng CPU khi giải mã
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
Kết quả mong đợi: Số lần checkpoints giảm, thời gian ghi WAL mượt mà hơn.
Tối ưu hóa Disk I/O Scheduler
Sử dụng bộ lịch trình I/O phù hợp cho SSD hoặc NVMe trong môi trường ảo hóa.
Thao tác:
# Kiểm tra I/O scheduler hiện tại
cat /sys/block/sda/queue/scheduler
# Đổi sang 'none' hoặc 'mq-deadline' cho NVMe/SSD để giảm latency
echo none > /sys/block/sda/queue/scheduler
# Thiết lập I/O priority cho PostgreSQL (cho phép ưu tiên cao)
ionice -c 2 -n 0 -p $(pgrep -f postgres)
Kết quả mong đợi: Latency I/O giảm, throughput tăng lên rõ rệt.
Tối ưu hóa tham số Raft
Giảm heartbeat_interval để phát hiện lỗi nhanh hơn nhưng không nên quá nhỏ để tránh false positive.
Đường dẫn: /etc/raft/config.toml (hoặc file cấu hình Raft của bạn)
Nội dung:
[raft]
# Giảm heartbeat để phát hiện split-brain nhanh hơn
heartbeat_interval = "500ms"
# Tăng election timeout để tránh bầu cử liên tục khi mạng chập chờn
election_timeout = "1500ms"
# Tăng snapshot interval để giảm kích thước snapshot (tiết kiệm I/O)
snapshot_interval = "300000"
# Giới hạn số lượng entry trong log để tránh log quá lớn
max_log_size = 104857600
Kết quả mong đợi: Hệ thống phản ứng nhanh với sự cố nhưng ít xảy ra bầu cử leader không cần thiết.
Checklist bảo mật cuối cùng trước khi đưa vào sản xuất
Trước khi mở port public hoặc đưa vào production, bạn phải kiểm tra lại toàn bộ lớp bảo mật.
Tại sao: Đảm bảo không có lỗ hổng nào bị bỏ sót sau quá trình tối ưu hiệu năng.
Kết quả mong đợi: Hệ thống đạt chuẩn bảo mật, không có cảnh báo an toàn.
1. Kiểm tra cấu hình mạng và Firewall
Đảm bảo chỉ có các node trong cụm mới được kết nối port replication (5432) và port Raft (ví dụ 8400).
Thao tác:
# Kiểm tra firewall (UFW hoặc iptables)
sudo ufw status verbose
# Đảm bảo chỉ cho phép IP nội bộ (ví dụ 10.0.0.0/24)
sudo ufw allow from 10.0.0.0/24 to any port 5432
sudo ufw allow from 10.0.0.0/24 to any port 8400
# Chặn mọi kết nối khác từ public
sudo ufw default deny incoming
Kết quả mong đợi: Port 5432 và 8400 chỉ mở cho subnet nội bộ, public internet không thể scan được.
2. Kiểm tra quyền truy cập và Audit
Đảm bảo không có user postgres mặc định có quyền superuser không cần mật khẩu.
Thao tác:
# Kiểm tra user superuser
psql -h 10.0.0.10 -U admin -d db_cluster -c "SELECT usename, usesuper FROM pg_user WHERE usesuper = true;"
# Bật log audit cho các hành động nhạy cảm
# Thêm vào postgresql.conf
log_statement = 'ddl'
log_connections = on
log_disconnections = on
log_lock_waits = on
# Reload config
SELECT pg_reload_conf();
Kết quả mong đợi: Chỉ có user admin (hoặc user quản trị) là superuser, log audit ghi lại mọi thay đổi schema và kết nối.
3. Kiểm tra khóa mã hóa (TDE Key Management)
Đảm bảo khóa mã hóa được lưu trữ an toàn (HSM hoặc KMS) và không nằm trong file config plain text.
Thao tác:
# Kiểm tra quyền truy cập file key
ls -l /etc/postgresql/tde/keys/
# Đảm bảo quyền chỉ cho postgres (700)
chmod 700 /etc/postgresql/tde/keys/
chown postgres:postgres /etc/postgresql/tde/keys/
# Kiểm tra xem key có được load vào memory không (không hiển thị raw key)
psql -h 10.0.0.10 -U admin -d db_cluster -c "SELECT key_id, key_algorithm FROM tde_keys;"
Kết quả mong đợi: File key có quyền 700, chỉ user postgres đọc được. Database hiển thị ID và algorithm, không hiển thị nội dung key.
4. Kiểm tra Backup và Recovery
Thực hiện test khôi phục một bản backup đã mã hóa trên một server mới.
Thao tác:
# Tạo backup thử nghiệm
pg_basebackup -h 10.0.0.10 -D /tmp/backup_test -Fp -Xs -P -R
# Giả lập khôi phục (copy sang server mới, đặt key vào đúng vị trí)
# Sau đó khởi động postgres và kiểm tra
pg_ctl -D /tmp/backup_test start -l /tmp/recovery.log
# Kiểm tra xem dữ liệu có đọc được không
psql -d db_cluster -c "SELECT count(*) FROM critical_table;"
Kết quả mong đợi: Dữ liệu được đọc thành công, không báo lỗi decryption failed hoặc
key not found.
5. Kiểm tra Monitoring Alert
Đảm bảo Alert của Grafana/Prometheus đã được cấu hình để gửi cảnh báo qua Slack/Email khi có sự cố.
Thao tác:
# Kiểm tra Alert Rule trong Prometheus
curl http://localhost:9090/api/v1/rules
# Kiểm tra Alert Manager config
cat /etc/alertmanager/alertmanager.yml | grep "receivers"
Kết quả mong đợi: Alert rule HighReplicationLag và
TDEKeyMismatch hiện diện và được liên kết với channel thông báo.
Điều hướng series:
Mục lục: Series: Xây dựng Database phân tán an toàn với PostgreSQL, Raft và TDE
« Phần 7: Sao lưu, khôi phục và Disaster Recovery cho cụm phân tán mã hóa