Files
goodgo-platform/docs/RUNBOOK.md
Ho Ngoc Hai d8b409a9ab
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 18s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m15s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 17s
E2E Tests / Playwright E2E (push) Failing after 31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m46s
Security Scanning / Trivy Scan — Web Image (push) Failing after 1m7s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 53s
Security Scanning / Trivy Filesystem Scan (push) Failing after 35s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
docs: dịch 22 file Markdown còn lại sang tiếng Việt có dấu (TEC-2881)
Hoàn tất đợt cuối của nhiệm vụ chuyển toàn bộ tài liệu sang tiếng Việt.
Đã dịch 22 file `.md` còn sót (~9.7k dòng) — gồm RUNBOOK, audits,
docs/architecture, docs/load-testing, libs READMEs và các quick references.
Giữ nguyên code blocks, đường dẫn, identifier kỹ thuật, URL và biến môi trường.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-19 03:26:14 +07:00

47 KiB

GoodGo Platform — Runbook Vận hành Production

Đối tượng: SRE on-call, kỹ sư DevOps và người vận hành nền tảng. Cập nhật lần cuối: 2026-04-11


Mục lục

  1. Danh sách dịch vụ
  2. Health Checks
  3. Các incident thường gặp
  4. Quy trình khôi phục
  5. Ma trận leo thang
  6. Dashboard giám sát
  7. Truy vấn PromQL hữu ích
  8. Tham chiếu nhanh môi trường

1. Danh sách dịch vụ

Dịch vụ Production (docker-compose.prod.yml)

Dịch vụ Image Port Giới hạn tài nguyên Health Check
api (NestJS) ghcr.io/goodgo/goodgo-api 3001 1 CPU / 1 GB GET /health (node fetch)
web (Next.js) ghcr.io/goodgo/goodgo-web 3000 0.5 CPU / 512 MB GET / (node fetch)
ai-services (FastAPI) ghcr.io/goodgo/goodgo-ai-services 8000 1 CPU / 1 GB GET /health (httpx)
postgres postgis/postgis:16-3.4 5432 (nội bộ) 2 CPU / 2 GB, shm=256m pg_isready
pgbouncer edoburu/pgbouncer:1.23.1-p2 6432 (nội bộ) 0.5 CPU / 256 MB pg_isready -p 6432
redis redis:7-alpine 6379 (nội bộ) 0.5 CPU / 768 MB redis-cli ping
typesense typesense/typesense:27.1 8108 (nội bộ) 1 CPU / 1 GB curl /health
minio minio/minio:latest 9000/9001 (nội bộ) 0.5 CPU / 1 GB mc ready local
pg-backup postgis/postgis:16-3.4 0.5 CPU / 512 MB — (cron daemon)
loki grafana/loki:3.0.0 3100 (nội bộ) 0.5 CPU / 512 MB wget /ready
promtail grafana/promtail:3.0.0 0.25 CPU / 256 MB
prometheus prom/prometheus:v2.51.0 9090 (nội bộ) 0.5 CPU / 1 GB wget /-/healthy
grafana grafana/grafana:10.4.1 3002 (bên ngoài) 0.5 CPU / 512 MB wget /api/health
alertmanager prom/alertmanager:v0.27.0 9093 (nội bộ) 0.25 CPU / 256 MB wget /-/healthy

Dịch vụ chỉ dùng cho Development (docker-compose.yml)

Môi trường development sử dụng cùng các dịch vụ dữ liệu và giám sát nhưng chạy API/Web trực tiếp trên host. Dịch vụ pg-backup cũng chạy trong dev với credential mặc định.

Chuỗi phụ thuộc giữa các dịch vụ

web --> api --> pgbouncer --> postgres
                  |-> redis
                  |-> typesense
                  |-> minio
                  |-> ai-services

grafana --> prometheus --> alertmanager
        |-> loki --> promtail (Docker socket)

pg-backup --> postgres

2. Health Checks

Các endpoint health của ứng dụng

Endpoint Loại Kiểm tra Phản hồi mong đợi
GET /health Liveness Tiến trình đang chạy 200 { status: "ok" }
GET /health/ready Readiness PostgreSQL + Redis 200 { status: "ok", info: { database: ..., redis: ... } }
GET /health/db Chỉ database Kết nối PostgreSQL 200 { status: "ok", info: { database: ... } }
GET /health/redis Chỉ Redis Kết nối Redis 200 { status: "ok", info: { redis: ... } }

Xác minh tất cả dịch vụ đang khỏe mạnh

# Kiểm tra nhanh — tất cả container
docker compose -f docker-compose.prod.yml ps --format "table {{.Name}}\t{{.Status}}\t{{.Health}}"

# API liveness
curl -sf http://localhost:3001/health && echo "API OK" || echo "API FAIL"

# API readiness (DB + Redis)
curl -sf http://localhost:3001/health/ready | jq .

# Kiểm tra từng phụ thuộc
curl -sf http://localhost:3001/health/db | jq .
curl -sf http://localhost:3001/health/redis | jq .

# Typesense
curl -sf -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" http://localhost:8108/health

# MinIO
docker exec goodgo-minio mc ready local && echo "MinIO OK"

# AI Services
curl -sf http://localhost:8000/health && echo "AI OK" || echo "AI FAIL"

# PostgreSQL (trực tiếp)
docker exec goodgo-postgres pg_isready -U ${DB_USER} -d ${DB_NAME}

# PgBouncer
docker exec goodgo-pgbouncer pg_isready -h 127.0.0.1 -p 6432 -U ${DB_USER}

# Redis
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" ping

# Prometheus
curl -sf http://localhost:9090/-/healthy && echo "Prometheus OK"

# Loki
curl -sf http://localhost:3100/ready && echo "Loki OK"

# Grafana
curl -sf http://localhost:3002/api/health | jq .

# Alertmanager
curl -sf http://localhost:9093/-/healthy && echo "Alertmanager OK"

Tiêu thụ tài nguyên của container

docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}"

3. Các incident thường gặp

3.1 Cạn kiệt connection pool của database

Triệu chứng:

  • API trả về 503 hoặc treo khi xử lý request
  • /health/ready trả về unhealthy cho database
  • Log PgBouncer: no more connections allowed hoặc query_wait_timeout
  • Prometheus: tăng đột biến số kết nối active trong pg_stat_activity

Chẩn đoán:

# Kiểm tra trạng thái pool của PgBouncer
docker exec goodgo-pgbouncer psql -h 127.0.0.1 -p 6432 -U pgbouncer_admin pgbouncer -c "SHOW POOLS;"
docker exec goodgo-pgbouncer psql -h 127.0.0.1 -p 6432 -U pgbouncer_admin pgbouncer -c "SHOW CLIENTS;"
docker exec goodgo-pgbouncer psql -h 127.0.0.1 -p 6432 -U pgbouncer_admin pgbouncer -c "SHOW STATS;"

# Kiểm tra số kết nối active của PostgreSQL
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "SELECT state, count(*) FROM pg_stat_activity WHERE datname = '${DB_NAME}' GROUP BY state;"

# Xác định các truy vấn chạy lâu
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "SELECT pid, now() - pg_stat_activity.query_start AS duration, query, state
   FROM pg_stat_activity
   WHERE datname = '${DB_NAME}' AND state != 'idle'
   ORDER BY duration DESC
   LIMIT 10;"

Cách xử lý:

# 1. Hủy các truy vấn chạy lâu (> 5 phút)
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "SELECT pg_terminate_backend(pid)
   FROM pg_stat_activity
   WHERE datname = '${DB_NAME}'
     AND state != 'idle'
     AND now() - query_start > interval '5 minutes'
     AND pid <> pg_backend_pid();"

# 2. Nếu pool đã cạn kiệt hoàn toàn, restart PgBouncer
docker compose -f docker-compose.prod.yml restart pgbouncer

# 3. Nếu vấn đề vẫn còn, tạm thời tăng pool size
#    Chỉnh sửa PGBOUNCER_POOL_SIZE trong .env, sau đó:
docker compose -f docker-compose.prod.yml up -d --no-deps pgbouncer

Tham chiếu cấu hình PgBouncer:

  • Pool mode: transaction (kết nối được trả về pool sau mỗi transaction)
  • Pool size mặc định: 20 server connection cho mỗi cặp user/db
  • Số client connection tối đa: 200
  • Reserve pool: 5 kết nối dự phòng (sau khi chờ 3s)
  • Query wait timeout: 120s (báo lỗi nếu client chờ lâu hơn)

3.2 Lỗi kết nối Redis

Triệu chứng:

  • /health/redis trả về unhealthy
  • Thời gian phản hồi API tăng (cache miss đánh vào DB)
  • Log API hiển thị lỗi kết nối Redis

Chẩn đoán:

# Kiểm tra container Redis
docker logs --tail=50 goodgo-redis

# Kiểm tra kết nối
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" ping
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" INFO server
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" INFO memory
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" INFO clients

Cách xử lý:

# 1. Restart Redis (dữ liệu được lưu qua AOF)
docker compose -f docker-compose.prod.yml restart redis

# 2. Nếu OOM — kiểm tra sử dụng bộ nhớ
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" INFO memory | grep used_memory_human
# Bộ nhớ tối đa là 512 MB (prod), eviction policy: allkeys-lru

# 3. Nếu AOF bị hỏng
docker compose -f docker-compose.prod.yml stop redis
docker exec goodgo-redis redis-check-aof --fix /data/appendonly.aof
docker compose -f docker-compose.prod.yml start redis

Graceful Degradation: API được thiết kế để tiếp tục hoạt động khi Redis không khả dụng. Các cache miss sẽ đi thẳng xuống PostgreSQL. Hiệu năng sẽ giảm nhưng chức năng vẫn được bảo đảm. Redis không quan trọng đối với các hoạt động cốt lõi.

3.3 Typesense không khả dụng

Triệu chứng:

  • Chức năng tìm kiếm trả về lỗi hoặc fallback về tìm kiếm DB cơ bản
  • curl http://localhost:8108/health thất bại
  • Log API hiển thị timeout kết nối Typesense

Chẩn đoán:

# Kiểm tra trạng thái container
docker logs --tail=50 goodgo-typesense

# Kiểm tra health
curl -sf -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" http://localhost:8108/health

# Kiểm tra collection
curl -sf -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" http://localhost:8108/collections | jq .

# Kiểm tra dung lượng đĩa cho volume dữ liệu Typesense
docker system df -v | grep typesense

Cách xử lý:

# 1. Restart Typesense
docker compose -f docker-compose.prod.yml restart typesense

# 2. Nếu dữ liệu bị hỏng — rebuild từ PostgreSQL
docker compose -f docker-compose.prod.yml stop typesense
docker volume rm goodgo-platform-ai_typesense_data
docker compose -f docker-compose.prod.yml up -d typesense
# Chờ tới khi healthy, sau đó reindex:
docker compose -f docker-compose.prod.yml exec api npx ts-node scripts/typesense-reindex.ts
# Hoặc: pnpm run typesense:reindex

# 3. Nếu có backup volume — khôi phục
docker compose -f docker-compose.prod.yml stop typesense
docker run --rm -v goodgo-platform-ai_typesense_data:/data -v $(pwd)/backups:/backup \
  alpine sh -c "rm -rf /data/* && tar xzf /backup/typesense_YYYYMMDD_HHMMSS.tar.gz -C /data"
docker compose -f docker-compose.prod.yml start typesense

Hành vi Fallback: Khi Typesense không khả dụng, tìm kiếm bất động sản sẽ fallback về PostgreSQL full-text search kết hợp với truy vấn geo PostGIS. Chất lượng tìm kiếm giảm nhưng chức năng cốt lõi vẫn hoạt động.

3.4 Latency API cao

Triệu chứng:

  • Alert Prometheus ApiLatencyP99High kích hoạt (p99 > 1s trong 5 phút)
  • Alert critical ApiLatencyP99Critical kích hoạt (p99 > 3s trong 3 phút — vi phạm SLO)
  • Người dùng báo tải trang chậm

Chẩn đoán:

# 1. Kiểm tra endpoint nào đang chậm
# Grafana: dashboard GoodGo API Latency
# Hoặc qua PromQL:
curl -s "http://localhost:9090/api/v1/query" --data-urlencode \
  'query=topk(10, histogram_quantile(0.99, sum(rate(goodgo_api_request_duration_seconds_bucket[5m])) by (le, route, method)))' \
  | jq '.data.result[] | {route: .metric.route, method: .metric.method, p99: .value[1]}'

# 2. Kiểm tra slow query của database
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "SELECT pid, now() - query_start AS duration, left(query, 100) AS query_preview
   FROM pg_stat_activity
   WHERE state = 'active' AND now() - query_start > interval '1 second'
   ORDER BY duration DESC;"

# 3. Kiểm tra thời gian chờ của PgBouncer
docker exec goodgo-pgbouncer psql -h 127.0.0.1 -p 6432 -U pgbouncer_admin pgbouncer -c "SHOW POOLS;"

# 4. Kiểm tra sử dụng tài nguyên container
docker stats --no-stream goodgo-api goodgo-postgres goodgo-redis goodgo-pgbouncer

# 5. Kiểm tra latency Redis
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" --latency-history -i 3

# 6. Kiểm tra log ứng dụng để tìm lỗi
docker logs --tail=200 --since=5m goodgo-api 2>&1 | grep -i "error\|timeout\|slow"

Cách xử lý:

# 1. Nếu có slow query DB — terminate chúng
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "SELECT pg_terminate_backend(pid)
   FROM pg_stat_activity
   WHERE state = 'active' AND now() - query_start > interval '30 seconds';"

# 2. Nếu connection pool cạn kiệt — xem Mục 3.1

# 3. Nếu Redis chậm — restart
docker compose -f docker-compose.prod.yml restart redis

# 4. Nếu container API bị OOM — restart với nhiều memory hơn
docker compose -f docker-compose.prod.yml restart api

# 5. Nếu một endpoint cụ thể là bottleneck — kiểm tra log Loki:
# Grafana > Explore > Loki > {container_name="goodgo-api"} |= "slow"

3.5 Lỗi callback thanh toán

Triệu chứng:

  • Người dùng báo thanh toán bị kẹt ở trạng thái "pending"
  • Callback IPN của VNPay/MoMo/ZaloPay trả về lỗi
  • Không khớp đối soát thanh toán

Chẩn đoán:

# 1. Kiểm tra log callback thanh toán
docker logs goodgo-api 2>&1 | grep -i "payment\|callback\|vnpay\|momo\|zalopay" | tail -50

# 2. Kiểm tra các thanh toán pending trong DB
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "SELECT id, provider, status, \"amountVND\", \"createdAt\"
   FROM \"Payment\"
   WHERE status = 'PENDING'
   AND \"createdAt\" > now() - interval '24 hours'
   ORDER BY \"createdAt\" DESC
   LIMIT 20;"

# 3. Xác minh URL callback có thể truy cập được từ bên ngoài
curl -sf https://your-domain.com/api/payments/vnpay/callback && echo "Callback URL reachable"

# 4. Kiểm tra API có đang nhận callback không (qua Loki)
# Grafana > Explore > Loki > {container_name="goodgo-api"} |= "callback" |= "payment"

Cách xử lý:

# 1. Nếu callback bị timeout — kiểm tra health API và restart nếu cần
docker compose -f docker-compose.prod.yml restart api

# 2. Nếu xác thực chữ ký VNPay thất bại — kiểm tra các env var VNPAY_*
docker compose -f docker-compose.prod.yml exec api printenv | grep VNPAY

# 3. Đối với thanh toán kẹt — đối soát thủ công
#    Kiểm tra cổng merchant VNPay/MoMo để biết trạng thái giao dịch thực tế
#    Cập nhật trạng thái thanh toán trong DB nếu xác nhận đã thanh toán:
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c \
  "UPDATE \"Payment\" SET status = 'COMPLETED', \"updatedAt\" = now()
   WHERE id = '<payment-id>' AND status = 'PENDING';"

# 4. Nếu callback không đến được server — kiểm tra:
#    - Quy tắc firewall (cổng 3001 hoặc cổng reverse proxy phải mở)
#    - Hiệu lực chứng chỉ SSL
#    - Phân giải DNS
#    - Cấu hình webhook của payment provider (URL callback đúng)

Quan trọng: Trình xử lý callback thanh toán dùng xử lý idempotent với state transition nguyên tử. Việc replay một callback là an toàn và sẽ không tạo ra thanh toán trùng.

3.6 Cảnh báo dung lượng đĩa

Triệu chứng:

  • Container thất bại khi khởi động hoặc bị crash
  • PostgreSQL từ chối ghi (PANIC: could not write to file)
  • Docker daemon hết dung lượng

Chẩn đoán:

# Dung lượng đĩa của host
df -h

# Dung lượng đĩa của Docker
docker system df
docker system df -v

# Kiểm tra kích thước từng volume
for vol in $(docker volume ls -q | grep goodgo); do
  echo -n "$vol: "
  docker run --rm -v "${vol}:/data" alpine du -sh /data 2>/dev/null
done

# Kiểm tra volume backup
docker exec goodgo-pg-backup du -sh /backups/
docker exec goodgo-pg-backup ls -lht /backups/

Cách xử lý:

# 1. Dọn dẹp các tạo phẩm Docker
docker system prune -f          # Xóa container đã dừng, network không dùng, image dangling
docker image prune -a -f        # Xóa TẤT CẢ image không dùng (cẩn thận trên prod)

# 2. Xóa backup cũ (nếu retention không hoạt động)
docker exec goodgo-pg-backup find /backups -name "goodgo_*.sql.gz" -mtime +7 -delete

# 3. Dọn dẹp dữ liệu Prometheus (nếu quá lớn)
# Retention của Prometheus là 30d (prod) / 15d (dev) — cấu hình qua --storage.tsdb.retention.time
# Để ép compaction:
curl -sf -XPOST http://localhost:9090/-/quit  # Tắt graceful sẽ kích hoạt compaction
docker compose -f docker-compose.prod.yml start prometheus

# 4. Dọn dẹp dữ liệu Loki (retention 15 ngày)
# Loki tự dọn dẹp qua compactor. Nếu khẩn cấp:
docker compose -f docker-compose.prod.yml restart loki

# 5. Truncate log container Docker
sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' goodgo-api)
# Hoặc cho tất cả container:
sudo sh -c 'truncate -s 0 /var/lib/docker/containers/*/*-json.log'

Phòng ngừa: Tất cả container production dùng logging json-file với max-size: 10mmax-file: 3-5. Retention backup là 7 ngày (cấu hình qua BACKUP_RETENTION_DAYS).

3.7 Lỗi MinIO / Object Storage

Triệu chứng:

  • Upload ảnh/file thất bại
  • Ảnh bất động sản không tải được
  • Console MinIO không truy cập được ở cổng 9001

Chẩn đoán:

docker logs --tail=50 goodgo-minio
docker exec goodgo-minio mc ready local
docker exec goodgo-minio mc admin info local

Cách xử lý:

# 1. Restart MinIO
docker compose -f docker-compose.prod.yml restart minio

# 2. Nếu volume dữ liệu bị hỏng
docker compose -f docker-compose.prod.yml stop minio
docker volume rm goodgo-platform-ai_minio_data  # CẢNH BÁO: mất dữ liệu
docker compose -f docker-compose.prod.yml up -d minio
# Tạo lại bucket qua API hoặc admin console

3.8 AI Services không khả dụng

Triệu chứng:

  • Tính năng dùng AI (AVM, mô tả bất động sản) thất bại
  • GET /health trên cổng 8000 thất bại
  • Log API hiển thị timeout kết nối AI service

Chẩn đoán:

docker logs --tail=50 goodgo-ai-services
curl -sf http://localhost:8000/health
docker stats --no-stream goodgo-ai-services

Cách xử lý:

# 1. Restart AI services
docker compose -f docker-compose.prod.yml restart ai-services

# 2. Kiểm tra rate limit (mặc định: 60/phút)
docker compose -f docker-compose.prod.yml exec ai-services printenv | grep AI_RATE_LIMIT

# 3. Nếu OOM — service có giới hạn 1 GB; có thể cần tăng cho các model lớn

Graceful Degradation: Tính năng AI là tùy chọn. API nên xử lý việc AI service không khả dụng một cách mượt mà và trả về kết quả không dùng AI.

3.9 Lỗi pipeline log (Loki/Promtail)

Triệu chứng:

  • Log explorer Grafana trả về kết quả trống
  • Container Promtail unhealthy hoặc bị crash-loop
  • Loki trả về 503

Chẩn đoán:

docker logs --tail=50 goodgo-loki
docker logs --tail=50 goodgo-promtail
curl -sf http://localhost:3100/ready && echo "Loki ready" || echo "Loki NOT ready"

Cách xử lý:

# 1. Restart pipeline
docker compose -f docker-compose.prod.yml restart loki promtail

# 2. Nếu dữ liệu Loki bị hỏng
docker compose -f docker-compose.prod.yml stop loki promtail
docker volume rm goodgo-platform-ai_loki_data
docker compose -f docker-compose.prod.yml up -d loki promtail
# Log lịch sử sẽ mất nhưng log mới sẽ chảy ngay lập tức

# 3. Nếu Promtail không truy cập được Docker socket
ls -la /var/run/docker.sock
# Đảm bảo container promtail có mount Docker socket

3.10 Tăng đột biến tỷ lệ lỗi 5xx

Triệu chứng:

  • Alert Prometheus ApiErrorRate5xxHigh kích hoạt (> 1% 5xx trong 5 phút)
  • Người dùng báo lỗi

Chẩn đoán:

# Kiểm tra endpoint nào trả về 5xx
curl -s "http://localhost:9090/api/v1/query" --data-urlencode \
  'query=topk(10, sum(rate(http_requests_total{job="goodgo-api", status_code=~"5.."}[5m])) by (route, method))' \
  | jq '.data.result'

# Kiểm tra log lỗi API
docker logs --tail=200 --since=5m goodgo-api 2>&1 | grep -i "error\|exception\|500"

# Kiểm tra health của tất cả phụ thuộc
curl -sf http://localhost:3001/health/ready | jq .

Cách xử lý:

  1. Nếu liên quan đến DB: xem Mục 3.1
  2. Nếu liên quan đến Redis: xem Mục 3.2
  3. Nếu là do deploy gần đây: xem Mục 4.4
  4. Nếu không rõ nguyên nhân: restart API và điều tra log

4. Quy trình khôi phục

4.1 Khôi phục database từ backup

Backup tự động chạy hàng ngày lúc 02:00 UTC qua container pg-backup. Retention: 7 ngày. Định dạng: pg_dump --format=custom --compress=6.

Xác minh tự động chạy hàng ngày lúc 04:00 UTC — khôi phục vào một database test cô lập, kiểm tra sự tồn tại của table, số dòng, checksum, extension PostGIS, index và enum. Báo cáo được ghi vào /backups/verify-latest.json.

Liệt kê các backup hiện có

docker exec goodgo-pg-backup ls -lht /backups/goodgo_*.sql.gz

Tạo backup theo yêu cầu

docker exec goodgo-pg-backup /scripts/pg-backup.sh

Quy trình khôi phục đầy đủ

# 1. Dừng các dịch vụ ứng dụng
docker compose -f docker-compose.prod.yml stop api web ai-services

# 2. (Production) Dừng PgBouncer để tránh kết nối cũ
docker compose -f docker-compose.prod.yml stop pgbouncer

# 3. Chạy script restore
docker exec -it goodgo-pg-backup /scripts/pg-restore.sh /backups/goodgo_YYYYMMDD_HHMMSS.sql.gz
# Script sẽ:
#   - Terminate các kết nối DB đang active
#   - DROP và tạo lại database
#   - Khôi phục từ file backup

# 4. Xác minh việc khôi phục
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c '\dt'
docker exec goodgo-postgres psql -U ${DB_USER} -d ${DB_NAME} -c 'SELECT count(*) FROM "User";'

# 5. Áp dụng các migration đang chờ (nếu có)
docker compose -f docker-compose.prod.yml exec api npx prisma migrate deploy

# 6. Khởi động lại tất cả dịch vụ
docker compose -f docker-compose.prod.yml up -d

# 7. Xác minh health của ứng dụng
curl -sf http://localhost:3001/health/ready | jq .

Xác minh backup mà không khôi phục

# Chạy verification trên backup mới nhất (tạo DB tạm, sau đó drop)
docker compose run --rm pg-verify-backup

# Hoặc xác minh một file backup cụ thể
docker exec goodgo-pg-backup /scripts/pg-verify-backup.sh /backups/goodgo_YYYYMMDD_HHMMSS.sql.gz

# Kiểm tra báo cáo verification mới nhất
docker exec goodgo-pg-backup cat /backups/verify-latest.json | jq .

RPO/RTO:

  • RPO: ≤ 24 giờ (backup hàng ngày; cân nhắc WAL archiving để giảm RPO)
  • RTO: ~15 phút (volume local), ~30 phút (off-site)

4.2 Xóa cache Redis và warm-up

# Xóa toàn bộ dữ liệu Redis
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" FLUSHALL

# Xác minh việc xóa
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" DBSIZE
# Phải trả về: (integer) 0

Warm-up: Redis dùng eviction allkeys-lru. Cache tự ấm dần khi người dùng gửi request. Không cần script warm-up thủ công — cache miss sẽ đi thẳng xuống PostgreSQL.

Khi nào cần flush:

  • Sau khi restore database (cache tham chiếu cũ)
  • Sau khi dữ liệu bị hỏng ở tầng ứng dụng
  • Sau khi thay đổi schema làm thay đổi cấu trúc dữ liệu được cache

4.3 Quy trình rolling restart

Restart từng dịch vụ (Zero Downtime)

# API — cờ --wait đảm bảo health check pass trước khi tiếp tục
docker compose -f docker-compose.prod.yml up -d --no-deps --wait api

# Web
docker compose -f docker-compose.prod.yml up -d --no-deps --wait web

# AI Services
docker compose -f docker-compose.prod.yml up -d --no-deps --wait ai-services

Rolling restart toàn bộ stack

# Các dịch vụ dữ liệu trước (thứ tự quan trọng theo chuỗi phụ thuộc)
docker compose -f docker-compose.prod.yml restart redis
docker compose -f docker-compose.prod.yml restart typesense

# Chờ các dịch vụ dữ liệu healthy
sleep 10

# Connection pooling
docker compose -f docker-compose.prod.yml restart pgbouncer
sleep 5

# Các dịch vụ ứng dụng
docker compose -f docker-compose.prod.yml up -d --no-deps --wait api
docker compose -f docker-compose.prod.yml up -d --no-deps --wait web
docker compose -f docker-compose.prod.yml up -d --no-deps --wait ai-services

# Xác minh
curl -sf http://localhost:3001/health/ready | jq .

Khẩn cấp: Restart mọi thứ

docker compose -f docker-compose.prod.yml down
docker compose -f docker-compose.prod.yml up -d --wait

4.4 Rollback deployment

Cách hoạt động của Rollback Image

Mỗi lần deploy (cả CI/CD lẫn thủ công) đều gắn tag :rollback cho image hiện đang chạy trước khi pull image mới. Điều này đảm bảo phiên bản trước được giữ lại ngay cả khi docker image prune chạy. Các tag :rollback chỉ được dọn dẹp sau khi smoke test pass.

Vòng đời image trong quá trình deploy:

  1. docker tag <current-image> goodgo-api:rollback (giữ lại phiên bản trước)
  2. docker compose pull (kéo image mới)
  3. docker compose up (khởi động phiên bản mới)
  4. Chạy smoke test
  5. Nếu smoke test pass: xóa tag :rollback, chạy docker image prune
  6. Nếu smoke test thất bại: các image :rollback được đổi tag để khớp với template của compose và các dịch vụ được khởi động lại

Rollback tự động (CI/CD)

Pipeline CI/CD (.github/workflows/deploy.yml) tự động kích hoạt rollback nếu smoke test thất bại. Job rollback sẽ:

  1. Dừng các container bị lỗi
  2. Đổi tag các image :rollback để khớp với template image của compose (${REGISTRY_URL}/goodgo-{svc}:${IMAGE_TAG})
  3. Khởi động lại compose — lúc này sẽ resolve về image trước đó (đang hoạt động)
  4. Gửi thông báo Slack tới #deployments

Không cần can thiệp thủ công cho các deploy do CI kích hoạt.

Rollback nhanh dùng tag :rollback (Thủ công)

# SSH vào host
ssh deploy@$PRODUCTION_HOST
cd ~/goodgo

# Xác minh các image rollback có tồn tại
for svc in goodgo-api goodgo-web goodgo-ai-services; do
  docker image inspect "${svc}:rollback" > /dev/null 2>&1 \
    && echo "OK: ${svc}:rollback" \
    || echo "MISSING: ${svc}:rollback"
done

# Dừng các container hiện tại
docker compose -f docker-compose.prod.yml stop api web ai-services

# Đổi tag image rollback để khớp với template compose
export REGISTRY_URL=ghcr.io/goodgo
export IMAGE_TAG=$(docker inspect --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' goodgo-api 2>/dev/null || echo "latest")

for svc in goodgo-api goodgo-web goodgo-ai-services; do
  docker tag "${svc}:rollback" "${REGISTRY_URL}/${svc}:${IMAGE_TAG}"
done

# Khởi động lại với image rollback
docker compose -f docker-compose.prod.yml up -d --no-deps --wait api web ai-services

# Xác minh
curl -sf http://localhost:3001/health && echo "Rollback successful"

Rollback dùng deploy-production.sh (Script thủ công)

Script deploy thủ công (scripts/deploy-production.sh) có tích hợp sẵn rollback. Nếu health check hoặc smoke test thất bại, script sẽ tự động khôi phục từ các image được gắn tag :rollback và khởi động lại dịch vụ.

# Chạy deploy thủ công — rollback tự động khi thất bại
cd ~/goodgo
./scripts/deploy-production.sh <image-tag>

Rollback về một Git commit / image tag cụ thể

# Đặt tag mục tiêu (git SHA)
export IMAGE_TAG=<previous-commit-sha>
export REGISTRY_URL=ghcr.io/goodgo

# Pull phiên bản cụ thể
docker compose -f docker-compose.prod.yml pull api web ai-services

# Deploy
docker compose -f docker-compose.prod.yml up -d --no-deps --wait api
docker compose -f docker-compose.prod.yml up -d --no-deps --wait web
docker compose -f docker-compose.prod.yml up -d --no-deps --wait ai-services

# Xác minh
curl -sf http://localhost:3001/health/ready | jq .

Rollback migration database

# CẢNH BÁO: Prisma không hỗ trợ down-migration tự động.
# Để rollback migration, khôi phục từ backup trước khi migration:

# 1. Dừng ứng dụng
docker compose -f docker-compose.prod.yml stop api web ai-services pgbouncer

# 2. Khôi phục từ backup đã tạo trước khi migration
docker exec -it goodgo-pg-backup /scripts/pg-restore.sh /backups/<pre-migration-backup>.sql.gz

# 3. Deploy phiên bản code trước đó (IMAGE_TAG cũ hơn)
export IMAGE_TAG=<previous-commit-sha>
docker compose -f docker-compose.prod.yml up -d --wait

4.5 Reindex Typesense từ PostgreSQL

Nếu dữ liệu Typesense bị mất hoặc hỏng, rebuild index tìm kiếm từ PostgreSQL:

# 1. Đảm bảo Typesense đang chạy và healthy
curl -sf -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" http://localhost:8108/health

# 2. Chạy reindex
docker compose -f docker-compose.prod.yml exec api npx ts-node scripts/typesense-reindex.ts
# Hoặc từ host:
pnpm run typesense:reindex

# 3. Xác minh collection
curl -sf -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" http://localhost:8108/collections | jq '.[].name'

4.6 Khôi phục toàn bộ host

Dành cho trường hợp host bị lỗi hoàn toàn hoặc di chuyển sang máy chủ mới:

# 1. Cung cấp host mới với Docker + Docker Compose
# Yêu cầu: Docker >= 24, Docker Compose v2, tối thiểu 8 GB RAM

# 2. Clone repository và cấu hình
git clone <repo-url> ~/goodgo && cd ~/goodgo
cp .env.example .env
# Chỉnh sửa .env với các secret production (từ secrets manager)

# 3. Khôi phục backup PostgreSQL từ bộ lưu trữ off-site
# Chuyển file backup sang host mới
scp backups/goodgo_latest.sql.gz deploy@newhost:~/goodgo/backups/

# 4. Khởi động các dịch vụ hạ tầng
docker compose -f docker-compose.prod.yml up -d postgres redis typesense minio

# 5. Chờ PostgreSQL sẵn sàng, sau đó restore
docker compose -f docker-compose.prod.yml exec postgres pg_isready
docker exec goodgo-pg-backup /scripts/pg-restore.sh /backups/goodgo_latest.sql.gz

# 6. Khởi động các dịch vụ ứng dụng
docker compose -f docker-compose.prod.yml up -d

# 7. Chạy migration (nếu backup cũ hơn code mới nhất)
docker compose -f docker-compose.prod.yml exec api npx prisma migrate deploy

# 8. Rebuild index Typesense
pnpm run typesense:reindex

# 9. Flush Redis (cache cũ từ host cũ)
docker exec goodgo-redis redis-cli -a "${REDIS_PASSWORD}" FLUSHALL

# 10. Xác minh mọi thứ
curl -sf http://localhost:3001/health/ready | jq .
curl -sf http://localhost:3000 > /dev/null && echo "Web OK"

# RTO dự kiến: ~60 phút (phụ thuộc tốc độ truyền backup)

5. Ma trận leo thang

Mức độ Điều kiện Người phản hồi đầu tiên Leo thang SLA
P0 — Nghiêm trọng Ngừng dịch vụ hoàn toàn, mất dữ liệu, hỏng thanh toán SRE on-call CTO + CEO trong 15 phút Acknowledge: 5 phút, Resolve: 1 giờ
P1 — Cao Ngừng một phần, vi phạm SLO (p99 > 3s), 5xx > 5% SRE on-call Engineering lead trong 30 phút Acknowledge: 15 phút, Resolve: 4 giờ
P2 — Trung bình Hiệu năng suy giảm, một dịch vụ (không trọng yếu) bị down, p99 > 1s SRE on-call Team lead vào ngày làm việc kế tiếp Acknowledge: 1 giờ, Resolve: 24 giờ
P3 — Thấp Vấn đề về thẩm mỹ, thiếu giám sát, cải tiến không cấp bách Kỹ sư được giao Sprint planning Sprint tiếp theo

Kênh liên lạc

Vai trò Kênh
SRE on-call Slack #sre-oncall + PagerDuty
Engineering Lead Slack #engineering
CTO Slack DM / Điện thoại (xem PagerDuty)
Vấn đề thanh toán Slack #payments + cổng hỗ trợ VNPay/MoMo
Hạ tầng Slack #infrastructure

Thông báo Slack

Pipeline deploy tự động thông báo tới #deployments (qua SLACK_WEBHOOK_URL) khi:

  • Deploy production thành công
  • Smoke test staging thất bại
  • Rollback production được kích hoạt

6. Dashboard giám sát

Tất cả dashboard được provision tự động qua monitoring/grafana/provisioning/ và có sẵn trong thư mục GoodGo trên Grafana.

Dashboard Đường dẫn Grafana Mục đích
API Overview api-overview Tốc độ request, status code, kết nối active
API Latency api-latency Latency p50/p95/p99 theo endpoint, heatmap latency
Database database Kết nối PostgreSQL, hiệu năng truy vấn, thống kê PgBouncer
Search search Tốc độ truy vấn Typesense, latency, kích thước index
Business Metrics business-metrics Tin đăng, inquiry, thanh toán, đăng ký người dùng
Web Vitals web-vitals Core Web Vitals (LCP, FID, CLS), thời gian load trang
Logs logs Explorer log Loki với filter theo service, level, correlation ID

Truy cập: http://localhost:3002 (credential mặc định trong .env: GRAFANA_ADMIN_USER / GRAFANA_ADMIN_PASSWORD)

Nguồn dữ liệu:

  • Prometheus (http://prometheus:9090) — Metric (mặc định)
  • Loki (http://loki:3100) — Log, có correlation ID liên kết với Prometheus
  • Alertmanager (http://alertmanager:9093) — Trạng thái alert và silence

7. Truy vấn PromQL hữu ích

Hiệu năng API

# Latency p99 tổng thể
histogram_quantile(0.99, sum(rate(goodgo_api_request_duration_seconds_bucket{job="goodgo-api"}[5m])) by (le))

# Latency p99 theo từng endpoint (top 10 chậm nhất)
topk(10, histogram_quantile(0.99, sum(rate(goodgo_api_request_duration_seconds_bucket{job="goodgo-api"}[5m])) by (le, route, method)))

# Tốc độ request theo status code
sum(rate(http_requests_total{job="goodgo-api"}[5m])) by (status_code)

# Phần trăm lỗi 5xx
(sum(rate(http_requests_total{job="goodgo-api", status_code=~"5.."}[5m])) / sum(rate(http_requests_total{job="goodgo-api"}[5m]))) * 100

Database

# Kết nối active
pg_stat_activity_count{datname="goodgo", state="active"}

# Tỷ lệ sử dụng connection pool (nếu metric PgBouncer được scrape)
# Kiểm tra thủ công qua: SHOW POOLS trong admin console PgBouncer

Hạ tầng

# Sử dụng memory của container
container_memory_usage_bytes{name=~"goodgo-.*"}

# Sử dụng CPU của container
rate(container_cpu_usage_seconds_total{name=~"goodgo-.*"}[5m])

8. Tham chiếu nhanh môi trường

Biến môi trường chính

Biến Bắt buộc Mô tả
DATABASE_URL PostgreSQL qua PgBouncer (postgresql://user:pass@pgbouncer:6432/db)
DATABASE_URL_DIRECT Có (prod) PostgreSQL trực tiếp cho migration (postgresql://user:pass@postgres:5432/db)
JWT_SECRET Secret ký JWT
JWT_REFRESH_SECRET Secret ký refresh token
REDIS_URL Kết nối Redis (redis://:password@redis:6379)
REDIS_PASSWORD Có (prod) Mật khẩu auth Redis
TYPESENSE_API_KEY API key admin của Typesense
MINIO_ACCESS_KEY Root user của MinIO
MINIO_SECRET_KEY Mật khẩu root của MinIO
VNPAY_* Cấu hình payment gateway VNPay
AI_API_KEY Xác thực AI services
GRAFANA_ADMIN_USER Có (prod) Username admin Grafana
GRAFANA_ADMIN_PASSWORD Có (prod) Mật khẩu admin Grafana
PGBOUNCER_POOL_SIZE Không Kích thước pool PgBouncer (mặc định: 20)
PGBOUNCER_MAX_CLIENT_CONN Không Số client connection tối đa của PgBouncer (mặc định: 200)
BACKUP_RETENTION_DAYS Không Thời gian lưu giữ backup (mặc định: 7)
IMAGE_TAG Không (prod) Tag image container (mặc định: latest)

Bản đồ cổng

Cổng Dịch vụ Phơi bày
3000 Web (Next.js) Bên ngoài
3001 API (NestJS) Bên ngoài
3002 Grafana Bên ngoài (chỉ admin)
5432 PostgreSQL Nội bộ
6432 PgBouncer Nội bộ
6379 Redis Nội bộ
8000 AI Services Nội bộ
8108 Typesense Nội bộ
9000 MinIO API Nội bộ
9001 MinIO Console Nội bộ
9090 Prometheus Nội bộ
3100 Loki Nội bộ

Docker Volume

Volume Dịch vụ Mục đích
pgdata PostgreSQL File database
redis_data Redis Bền vững AOF
typesense_data Typesense Dữ liệu index tìm kiếm
minio_data MinIO Object storage (ảnh, file)
pg_backups pg-backup File backup database
loki_data Loki Lưu trữ log (retention 15 ngày)
prometheus_data Prometheus Metric (retention 30 ngày prod / 15 ngày dev)
grafana_data Grafana Trạng thái dashboard, tùy chọn người dùng

9. Xác thực Disaster Recovery

Xác minh tự động

Xác minh backup chạy hàng ngày lúc 04:00 UTC bên trong container pg-backup. Nó khôi phục backup mới nhất vào một database test cô lập và kiểm tra:

  • Sự tồn tại của table (tất cả 22 Prisma model)
  • So sánh số dòng với database live
  • Checksum dữ liệu trên các bảng quan trọng (User, Property, Listing, Payment, Subscription, Transaction, Plan)
  • Khả dụng của extension PostGIS
  • Khớp số lượng index
  • Khớp số lượng enum type

Kiểm tra báo cáo xác minh mới nhất:

docker exec goodgo-pg-backup cat /backups/verify-latest.json | jq .

Kiểm tra log xác minh:

docker exec goodgo-pg-backup cat /var/log/pg-verify.log

Quy trình xác thực DR thủ công

Chạy hàng quý (hoặc sau khi thay đổi schema lớn) để xác thực toàn bộ quy trình DR end-to-end.

Bước 1: Xác minh backup tồn tại và mới

# Liệt kê backup kèm timestamp và kích thước
docker exec goodgo-pg-backup ls -lht /backups/goodgo_*.sql.gz

# Xác minh backup mới nhất dưới 25 giờ tuổi
LATEST=$(docker exec goodgo-pg-backup ls -t /backups/goodgo_*.sql.gz | head -1)
echo "Latest backup: $LATEST"

Bước 2: Chạy xác minh trên backup mới nhất

# Xác minh tự động (tạo DB tạm, validate, drop)
docker exec -e REPORT_FILE=/backups/verify-latest.json goodgo-pg-backup \
  /scripts/pg-verify-backup.sh

# Xem xét kết quả
docker exec goodgo-pg-backup cat /backups/verify-latest.json | jq .

Kết quả mong đợi: Tất cả các kiểm tra pass, việc restore hoàn thành trong < 60 giây với dataset thông thường.

Bước 3: Test restore đầy đủ (chỉ trên Staging)

⚠️ CẢNH BÁO: Chỉ thực hiện trên môi trường staging hoặc môi trường cô lập. Không bao giờ trên production.

# 1. Tạo môi trường test riêng biệt
docker compose -f docker-compose.yml -p goodgo-dr-test up -d postgres

# 2. Chờ PostgreSQL sẵn sàng
docker exec goodgo-dr-test-postgres-1 pg_isready

# 3. Chạy restore vào môi trường test
PGHOST=localhost PGPORT=<test-port> PGUSER=goodgo PGPASSWORD=<password> \
  /scripts/pg-restore.sh /backups/<latest-backup>.sql.gz

# 4. Xác minh các bảng quan trọng
docker exec goodgo-dr-test-postgres-1 psql -U goodgo -d goodgo -c \
  "SELECT count(*) FROM \"User\"; SELECT count(*) FROM \"Property\"; SELECT count(*) FROM \"Listing\";"

# 5. Dọn dẹp môi trường test
docker compose -f docker-compose.yml -p goodgo-dr-test down -v

Bước 4: Xác thực chuỗi khôi phục dịch vụ

Kiểm tra rằng tất cả dịch vụ có thể khởi động từ trạng thái sạch với dữ liệu đã khôi phục:

# 1. Ghi chú trạng thái dịch vụ hiện tại
docker compose -f docker-compose.prod.yml ps --format "table {{.Name}}\t{{.Status}}\t{{.Health}}"

# 2. Khởi động lại tất cả dịch vụ theo thứ tự phụ thuộc
docker compose -f docker-compose.prod.yml restart postgres
sleep 10  # Chờ PostgreSQL

docker compose -f docker-compose.prod.yml restart pgbouncer redis typesense
sleep 10  # Chờ các dịch vụ dữ liệu

docker compose -f docker-compose.prod.yml restart api web ai-services
sleep 15  # Chờ các dịch vụ ứng dụng

# 3. Xác minh tất cả health check
curl -sf http://localhost:3001/health/ready | jq .
curl -sf http://localhost:3000 > /dev/null && echo "Web OK"
curl -sf http://localhost:9090/-/healthy && echo "Prometheus OK"
curl -sf http://localhost:9093/-/healthy && echo "Alertmanager OK"
curl -sf http://localhost:3002/api/health | jq .

Bước 5: Xác thực pipeline cảnh báo

# 1. Kiểm tra Prometheus đang load các alert rule
curl -sf http://localhost:9090/api/v1/rules | jq '.data.groups | length'
# Mong đợi: 7 group

# 2. Kiểm tra các alert hiện tại (phải rỗng nếu khỏe mạnh)
curl -sf http://localhost:9090/api/v1/alerts | jq '.data.alerts | length'

# 3. Kiểm tra Alertmanager đang nhận từ Prometheus
curl -sf http://localhost:9093/api/v2/status | jq '.cluster'

# 4. Xác minh cấu hình Alertmanager đã được load
curl -sf http://localhost:9093/api/v2/status | jq '.config'

Danh sách kiểm tra xác thực DR

Dùng danh sách này trong các đợt review DR hàng quý:

  • Backup mới nhất dưới 25 giờ tuổi
  • Báo cáo xác minh tự động cho thấy tất cả kiểm tra pass
  • Restore thủ công vào DB test thành công với số dòng chính xác
  • Restart đầy đủ dịch vụ hoàn thành trong mục tiêu RTO (< 30 phút)
  • Tất cả các health endpoint phản hồi sau khi restart
  • Alert rule Prometheus đã được load (7 group)
  • Alertmanager có thể truy cập và đã được cấu hình
  • Kênh thông báo Slack nhận được cảnh báo test
  • Dashboard Grafana hiển thị dữ liệu sau khi restart
  • Tìm kiếm Typesense trả về kết quả sau khi restart

Tóm tắt RPO/RTO

Chỉ số Mục tiêu Thực tế (đo được) Ghi chú
RPO ≤ 24 giờ ~24h (hàng ngày lúc 02:00 UTC) Giảm bằng WAL archiving
RTO — Backup local ≤ 15 phút Đo trong DR test Restore + restart dịch vụ
RTO — Backup off-site ≤ 30 phút Đo trong DR test Cộng thêm thời gian chuyển dữ liệu
RTO — Khôi phục toàn bộ host ≤ 60 phút Đo trong DR test Host mới + restore + deploy

Phụ lục: Tham chiếu Alert Rule

Alert API & Lỗi

Alert Biểu thức Mức độ Thời lượng
ApiLatencyP99High p99 > 1s Warning 5 phút
ApiEndpointLatencyP99High p99 theo từng route > 2s Warning 5 phút
ApiLatencyP99Critical p99 > 3s (vi phạm SLO) Critical 3 phút
ApiErrorRate5xxHigh Tỷ lệ 5xx > 1% Warning 5 phút
ApiErrorRate5xxCritical Tỷ lệ 5xx > 5% Critical 3 phút
ApiNoTraffic Tốc độ request = 0 Warning 10 phút

Alert Database

Alert Biểu thức Mức độ Thời lượng
PostgresActiveConnectionsHigh Kết nối active > 15 Warning 5 phút
PostgresConnectionPoolCritical Tổng số kết nối > 180 Critical 2 phút
PostgresSlowQueries Truy vấn chờ lock > 5 Warning 5 phút
PostgresDown Scrape target của API down Critical 1 phút

Alert Redis

Alert Biểu thức Mức độ Thời lượng
RedisMemoryHigh Sử dụng memory > 80% Warning 5 phút
RedisMemoryCritical Sử dụng memory > 95% Critical 2 phút
RedisConnectedClientsHigh Số client > 150 Warning 5 phút
RedisRejectedConnections Kết nối bị từ chối > 0 Critical 1 phút

Alert Tài nguyên Container

Alert Biểu thức Mức độ Thời lượng
ContainerRestartLoop > 3 lần restart trong 15 phút Critical 5 phút
ContainerMemoryHigh Memory > 85% giới hạn Warning 5 phút
ContainerCPUThrottled Tỷ lệ CPU throttle > 0.5s/s Warning 10 phút

Alert Đĩa & Hạ tầng

Alert Biểu thức Mức độ Thời lượng
HostDiskUsageHigh Đĩa root > 80% Warning 10 phút
HostDiskUsageCritical Đĩa root > 90% Critical 5 phút
ApiHealthCheckFailing Health probe thất bại Critical 2 phút
PrometheusTargetDown Scrape target down Warning 5 phút

Alert Backup

Alert Biểu thức Mức độ Thời lượng
BackupTooOld Backup cuối > 25 giờ trước Warning 5 phút
BackupVerificationFailed Kết quả verify = fail Warning 1 phút

Routing Alert

Alert được route qua Alertmanager (monitoring/alertmanager/alertmanager.yml):

Kênh Route Khoảng lặp lại
#sre-oncall (Slack) Tất cả alert warning 4 giờ
#sre-oncall (Slack) Tất cả alert critical (ưu tiên) 1 giờ
#infrastructure (Slack) Alert liên quan backup 6 giờ

Inhibition: Các alert warning bị chặn khi đã có alert critical cho cùng một dịch vụ đang kích hoạt.

Alert rule được định nghĩa trong monitoring/prometheus/alert-rules.yml và được đánh giá mỗi 15 giây.