Observability 8 — Vận hành production & use case ngân hàng
Từ demo tới production: bài toán đổi chất
Bảy bài trước dựng đủ bộ công cụ: Prometheus thu metric (kiến trúc), PromQL, Instrumentation, Grafana, Alerting, Logs & Traces. Tất cả chạy tốt trên một máy demo. Nhưng đưa hệ đó vào production của một ngân hàng là bài toán khác về chất, không chỉ về lượng.
Ba câu hỏi mà bản demo không trả lời được:
- Nếu Prometheus chết thì sao? Một instance đơn là single point of failure. Lúc hệ thống có sự cố cũng là lúc bạn cần metric nhất.
- Dữ liệu để được bao lâu? Prometheus lưu cục bộ mặc định chỉ ~15 ngày. Ngân hàng cần dữ liệu hàng tháng đến hàng năm để phân tích xu hướng, đối chiếu SLA và tuân thủ.
- Nhiều cụm, nhiều vùng thì nhìn ở đâu? Core-banking ở DC-A, thanh toán ở DC-B, pipeline trên Kubernetes — không thể mở 5 Grafana rời mỗi khi cần bức tranh tổng.
Bài này giải quyết cả ba, cộng bảo mật, chi phí và — quan trọng nhất — văn hoá vận hành biến công cụ thành năng lực thật.
High availability cho Prometheus
Prometheus không có chế độ clustering theo kiểu chia sẻ trạng thái như database. Triết lý của nó ngược lại: giữ mỗi instance đơn giản, độc lập, tự chứa. Vậy làm sao HA?
Cách kinh điển: chạy hai (hoặc nhiều) instance Prometheus giống hệt nhau, song song, cùng scrape cùng một tập target. Chúng độc lập hoàn toàn — không nói chuyện với nhau — nên nếu một cái chết, cái kia vẫn thu metric bình thường. Đơn giản và cực kỳ bền.
Chạy song song đẻ ra hai vấn đề trùng lặp:
- Trùng dữ liệu khi truy vấn. Grafana nhận hai chuỗi gần giống nhau từ hai Prometheus (lệch vài giây do thời điểm scrape khác). Cần lớp deduplication phía trước trả về kết quả sạch. Thường Grafana không trỏ thẳng vào Prometheus mà trỏ vào lớp query của Thanos/Mimir (mục sau) — lớp này dedup dựa trên external label phân biệt replica, ví dụ
replica="a"/replica="b". - Trùng cảnh báo. Cả hai Prometheus cùng đánh giá rule, cùng bắn alert → nguy cơ báo động kép. Lời giải: Alertmanager tự cluster (giao thức gossip) — nhiều Alertmanager thống nhất một alert đã gửi thì không gửi lại. Đây là ngoại lệ: Alertmanager có HA thực sự qua clustering, khác Prometheus.
Nguyên tắc rút ra: HA của Prometheus = nhân bản + dedup, không phải clustering. Đơn giản mà đủ tin cậy cho tầng thu thập.
Lưu trữ dài hạn & global view: Thanos, Mimir, VictoriaMetrics
Prometheus local retention ngắn (mặc định ~15 ngày; đẩy lên vài tháng thì đĩa phình, truy vấn chậm) vì được thiết kế cho dữ liệu nóng, gần đây. Ba nhu cầu production vượt khỏi một Prometheus đơn: lưu dài hạn (giữ metric hàng tháng/năm không phình đĩa cục bộ), global view (truy vấn xuyên nhiều Prometheus của nhiều cụm/vùng như một), mở rộng ngang (dữ liệu lớn hơn khả năng một máy).
Ba hệ phổ biến giải cụm nhu cầu này, đều tương thích PromQL nên Grafana và dashboard cũ dùng lại được:
| Hệ | Ý tưởng cốt lõi | Điểm mạnh |
|---|---|---|
| Thanos | Gắn "sidecar" cạnh mỗi Prometheus, đẩy block dữ liệu lên object storage (S3/GCS/MinIO); một lớp query gộp nhiều nguồn | Bám sát mô hình Prometheus, global view + long-term, dedup replica sẵn |
| Grafana Mimir | Hệ lưu metric phân tán, chịu tải rất lớn, đa tenant | Scale cực cao, multi-tenant mạnh, hợp SaaS/nền tảng dùng chung |
| VictoriaMetrics | Cơ sở dữ liệu time-series tối ưu, nén tốt, ít tài nguyên | Đơn giản vận hành, nén và hiệu năng/chi phí rất tốt |
Điểm chung của cả ba: dùng object storage rẻ (S3 và tương đương) cho lưu dài hạn — rẻ hơn nhiều lần đĩa SSD của Prometheus. Kèm downsampling (giảm mẫu): dữ liệu cũ không cần độ phân giải giây; Thanos tự tạo bản 5 phút và 1 giờ. Vẽ đồ thị một năm, truy vấn chạy trên bản 1 giờ thay vì quét hàng tỉ điểm gốc.
Mô hình Thanos điển hình, minh hoạ vì sao nó cho cả long-term lẫn global view:
Thanos Query fan-out tới cả sidecar (dữ liệu nóng, trong Prometheus) lẫn Store gateway (dữ liệu cũ trên object storage), gộp và dedup replica — nên một truy vấn Grafana có thể trải từ "5 phút trước" tới "18 tháng trước", xuyên nhiều cụm, mà người dùng không thấy ranh giới.
Federation: bản rút gọn khi chưa cần Thanos
Trước khi có các hệ trên, cách gộp cụm truyền thống là federation: một Prometheus "cha" scrape một tập metric đã tổng hợp từ nhiều Prometheus "con" qua endpoint /federate.
# prometheus.yml (cha) — federation, minh hoạ (KHÔNG phải SQL)
scrape_configs:
- job_name: 'federate'
honor_labels: true
metrics_path: '/federate'
params:
'match[]':
- '{__name__=~"job:.*"}' # chỉ kéo metric đã aggregate (recording rules)
static_configs:
- targets: ['prom-cua-hang-1:9090', 'prom-cua-hang-2:9090']
Federation phù hợp để gom số liệu cấp cao (KPI mỗi cụm) lên một view trung tâm, nhưng không dùng để sao chép toàn bộ metric chi tiết (sẽ quá tải và không giải bài long-term storage). Với ngân hàng nhiều cụm cần global view thật, Thanos/Mimir là lựa chọn đúng hơn; federation là bước quá độ hoặc dùng cho lớp tổng hợp mỏng.
Giám sát trong Kubernetes
Ngày càng nhiều tải của ngân hàng — đặc biệt pipeline dữ liệu và API — chạy trên Kubernetes (Kubernetes production). Ở đây, target không cố định: pod sinh/diệt liên tục, IP đổi. Cấu hình scrape tĩnh (danh sách IP cứng) là bất khả thi.
Lời giải là Prometheus Operator cùng gói kube-prometheus-stack (cài qua Helm) — cách chuẩn để chạy observability trên K8s. Nó đóng gói sẵn: Prometheus + Alertmanager + Grafana + node-exporter + kube-state-metrics + bộ dashboard/alert cho chính Kubernetes.
Khái niệm then chốt là service discovery tự động qua các Custom Resource:
- ServiceMonitor — object K8s khai báo "scrape các Service khớp label này, ở cổng/đường dẫn kia". Operator đọc nó và tự sinh cấu hình scrape cho Prometheus. Thêm dịch vụ mới chỉ cần tạo một ServiceMonitor — không sửa tay
prometheus.yml, không restart. - PodMonitor — tương tự nhưng nhắm thẳng pod.
- PrometheusRule — khai báo recording/alerting rule dưới dạng object K8s, quản bằng GitOps như mọi manifest.
# ServiceMonitor — minh hoạ (KHÔNG phải SQL)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: payment-api
labels:
release: kube-prometheus-stack # để Operator nhận
spec:
selector:
matchLabels:
app: payment-api # khớp Service có label này
endpoints:
- port: metrics # cổng tên "metrics" trên Service
path: /metrics
interval: 15s
Đây chính là triết lý declarative của K8s áp vào monitoring: bạn khai báo mong muốn ("dịch vụ này cần được scrape"), Operator lo phần thực thi. Với môi trường pod đổi liên tục, đây là cách duy nhất bền vững.
Bảo mật observability
Hệ observability của ngân hàng chạm vào dữ liệu vận hành nhạy cảm — bản thân nó là mục tiêu cần bảo vệ và cũng là nguồn rò rỉ tiềm tàng. Liên hệ chặt với Bảo mật & SRE.
- Phân quyền Grafana (RBAC). Không cho tất cả quyền Admin. Dùng vai trò
Viewer / Editor / Admin, chia theo Team và giới hạn dashboard/folder mỗi nhóm xem được. Tách data source theo môi trường (prod vs dev). Bật SSO/LDAP để gắn danh tính doanh nghiệp thay vì user cục bộ. - Không lộ dữ liệu nhạy cảm trên dashboard. Metric và label không được chứa PII: đừng đặt
customer_id, số tài khoản đầy đủ, số dư từng khách làm label. Dashboard công khai trong tổ chức có thể vô tình phơi hành vi khách hàng. Metric là số liệu tổng hợp về hệ thống, không phải kho dữ liệu khách. - Bảo vệ đường truyền & endpoint.
/metricsvà/federateđứng sau xác thực/mạng nội bộ, không phơi Internet. TLS giữa các thành phần; object storage Thanos mã hoá at-rest. - Giữ log/metric theo tuân thủ. Ngân hàng có yêu cầu lưu trữ tối thiểu cho audit trail; nhưng lưu càng lâu càng đắt và nhiều rủi ro — retention theo tầng (mục sau) vừa tiết kiệm vừa phục vụ tuân thủ. Dữ liệu nhạy cảm tách hẳn khỏi metric vận hành, đưa vào hệ audit riêng kiểm soát chặt (kiểm soát truy cập).
Chi phí & kiểm soát cardinality
Chi phí một hệ metric bị chi phối gần như hoàn toàn bởi cardinality — tổng số chuỗi thời gian (time series) duy nhất. Mỗi tổ hợp label tạo một series riêng phải lưu và index; đây là thủ phạm số một khiến hệ phình chi phí và chậm dần.
Công thức trực giác: số series ≈ tích số giá trị của mỗi label. http_requests_total với method(5) × status(6) × endpoint(50) là 1.500 series — chấp nhận được. Nhưng lỡ thêm user_id (hàng triệu) hay request_id (vô hạn), số series bùng nổ và giết Prometheus. Đây đúng bài học cardinality từ Instrumentation, giờ thành vấn đề chi phí ở quy mô production.
Chiến lược kiểm soát:
- Kiểm soát cardinality tại nguồn. Không đặt giá trị biến thiên cao (ID, email, UUID, đường dẫn có tham số) làm label. Kiểm tra định kỳ bằng
topk(20, count by (__name__)({__name__=~".+"}))để tìm metric nào đang phình series. - Downsampling. Dữ liệu cũ không cần độ phân giải giây — Thanos compactor tạo bản 5m/1h. Đồ thị dài hạn chạy nhanh và ít tốn hơn.
- Retention theo tầng (tiered retention). Không giữ mọi thứ cùng độ phân giải mãi mãi. Ví dụ chính sách phân tầng của một ngân hàng:
| Tầng | Độ phân giải | Thời gian giữ | Nơi lưu |
|---|---|---|---|
| Nóng | Gốc (15s) | 15 ngày | Đĩa Prometheus cục bộ |
| Ấm | 5 phút (downsampled) | 3 tháng | Object storage |
| Lạnh | 1 giờ (downsampled) | 13 tháng+ | Object storage (rẻ nhất) |
- Recording rules cho truy vấn nặng. Tính trước các aggregate hay dùng (ví dụ
job:http_error_ratio) để dashboard đọc kết quả có sẵn thay vì tính lại mỗi lần load — giảm tải query đáng kể.
Nguyên tắc chốt: mỗi label mới là một cam kết chi phí. Trước khi thêm label, hỏi "giá trị này có bao nhiêu khả năng, và ta có thật sự sẽ nhóm/lọc theo nó không?".
Văn hoá SRE: công cụ chỉ là một nửa
Có Prometheus + Grafana + Thanos hoàn hảo mà thiếu văn hoá vận hành thì vẫn thất bại. SRE (Site Reliability Engineering) biến observability thành độ tin cậy thật.
- On-call. Luân phiên trực (rotation) rõ ràng: ai nhận alert lúc nào, escalation ra sao nếu không phản hồi. On-call phải bền vững — lịch trực kiệt sức thì đội nghỉ việc. Đây là lý do chất lượng alert (Alerting) sống còn.
- Runbook. Mỗi alert quan trọng kèm một runbook ngắn: alert này nghĩa là gì, kiểm tra gì đầu tiên, khắc phục nhanh ra sao, khi nào escalate. Người trực 3 giờ sáng không nên nghĩ từ đầu; link runbook thẳng trong annotation của alert.
- Blameless postmortem. Sau sự cố lớn, viết postmortem tập trung vào hệ thống và quy trình đã cho phép lỗi xảy ra, không đổ lỗi cá nhân. Văn hoá đổ lỗi khiến người ta giấu sự cố — điều nguy hiểm nhất trong ngân hàng.
- Giảm alert fatigue. Kẻ thù lớn nhất của on-call là mệt mỏi vì cảnh báo: quá nhiều alert (nhất là loại không hành động được) khiến đội chai lì, bỏ lỡ alert thật. Mỗi alert phải actionable và urgent; không thoả cả hai thì hạ xuống dashboard/ticket, đừng gọi điện nửa đêm.
- SLO là ngôn ngữ chung. Service Level Objective ("99.9% giao dịch thành công", "p99 < 500ms") và error budget cân bằng giữa tính năng mới và độ ổn định — quyết định kỹ thuật và kinh doanh, không cảm tính.
Kiến trúc observability tham chiếu cho ngân hàng
Gộp mọi thứ lại, đây là kiến trúc tham chiếu giám sát đầu–cuối cho một ngân hàng có nhiều hệ: thanh toán, core-banking, API, pipeline dữ liệu — mỗi hệ được phủ bằng bộ bốn: golden signals + SLO + alert + trace.
Bốn golden signals (từ Alerting) áp cho từng dịch vụ trọng yếu:
| Hệ thống | Latency | Traffic | Errors | Saturation | SLO ví dụ |
|---|---|---|---|---|---|
| Cổng thanh toán | p99 xử lý giao dịch | TPS | tỷ lệ giao dịch fail | pool DB, CPU | 99.9% thành công, p99<800ms |
| Core-banking | latency truy vấn tài khoản | QPS | lỗi nghiệp vụ | connection pool | p99<300ms |
| API layer | latency HTTP | RPS | tỷ lệ 5xx | worker/thread | 99.95% uptime |
| Data pipeline | độ trễ (freshness) dữ liệu | rows/phút | job fail | lag hàng đợi/Kafka | dữ liệu tươi < 15 phút |
Điểm mấu chốt: một cửa sổ Grafana duy nhất (qua Thanos Query) cho SRE nhìn xuyên mọi cụm; Alertmanager cluster dedup cảnh báo dù nhiều Prometheus HA bắn; tracing (Tempo, qua OTel) nối cùng Grafana để nhảy từ metric bất thường sang trace request lỗi (Logs & Traces). Toàn bộ đứng sau SSO + RBAC; dữ liệu dài hạn trên object storage rẻ với retention phân tầng.
Checklist triển khai
- Prometheus chạy HA (≥2 replica song song) cho mỗi cụm; có external label
replica. - Lớp long-term/global (Thanos/Mimir/VictoriaMetrics) trên object storage; bật downsampling + retention phân tầng.
- Alertmanager cluster để dedup cảnh báo; kênh thông báo có escalation.
- Trên K8s: kube-prometheus-stack + Operator; mỗi dịch vụ có ServiceMonitor; rule quản bằng PrometheusRule/GitOps.
- Grafana: SSO + RBAC, phân folder/team; data source prod tách dev.
- Không PII trong metric/label; endpoint
/metrics,/federatekhông phơi Internet; TLS + mã hoá object storage. - Kiểm soát cardinality: rà
count by (__name__)định kỳ; recording rules cho query nặng. - Mỗi alert actionable + urgent, kèm runbook; đo và giảm alert fatigue.
- Định nghĩa SLO + error budget cho mỗi hệ trọng yếu; golden signals phủ đủ.
- Lịch on-call bền vững; blameless postmortem sau mỗi sự cố lớn.
Use case thực tế
Bối cảnh: NCB hợp nhất monitoring rời rạc của ba hệ (thanh toán ở DC-A, core-banking ở DC-B, API + pipeline dữ liệu trên K8s) thành một nền observability chung. Trước đó mỗi hệ một Prometheus + một Grafana; điều tra sự cố xuyên hệ phải mở 3 tab và ghép tay mốc thời gian.
Triển khai:
- Mỗi cụm chạy 2 Prometheus HA + Thanos sidecar đẩy block lên MinIO (object storage on-prem). Một Thanos Query trung tâm gộp cả ba cụm.
- Grafana trung tâm (SSO qua LDAP, RBAC theo phòng ban) trỏ vào Thanos Query — SRE nhìn ba hệ trong một dashboard.
- Retention phân tầng: 15 ngày nóng trên đĩa, 3 tháng bản 5m, 13 tháng bản 1h trên MinIO — đủ chuẩn tuân thủ mà chi phí đĩa SSD giảm mạnh nhờ đẩy dữ liệu cũ sang object storage.
- Alertmanager cluster (3 replica) dedup; mỗi alert gắn runbook và đẩy vào rotation on-call.
Kết quả (số liệu minh hoạ): một sự cố "tỷ lệ giao dịch thanh toán fail tăng" trước kia điều tra ~40 phút vì phải ghép log/metric ba hệ rời; nay từ dashboard chung → exemplar → trace core-banking → nguyên nhân (pool DB cạn do một job báo cáo nặng) mất dưới 6 phút. Cardinality tổng giảm ~35% sau khi rà và bỏ các label ID lỡ đưa vào, kéo chi phí lưu và độ trễ truy vấn xuống rõ.
Để định lượng phạm vi ảnh hưởng nghiệp vụ của sự cố, đội đối chiếu số giao dịch theo phút và loại trên sandbox nghiệp vụ (PostgreSQL chỉ đọc):
-- ▶ Chạy được
SELECT date_trunc('minute', created_at) AS minute,
kind,
COUNT(*) AS so_gd,
SUM(amount) AS tong_tien
FROM transactions
WHERE created_at >= NOW() - INTERVAL '1 hour'
GROUP BY 1, 2
ORDER BY 1 DESC, 2;
Con số này ghép cùng biểu đồ error ratio trên Grafana cho ban lãnh đạo bức tranh đầy đủ: sự cố kéo dài bao lâu, ảnh hưởng bao nhiêu giao dịch và giá trị tiền — thứ mà chỉ metric hạ tầng không nói hết.
Ghi nhớ
- HA Prometheus = nhân bản + dedup, không phải clustering: chạy ≥2 instance song song độc lập; dedup ở lớp query (label
replica); Alertmanager tự cluster để khỏi báo động kép. - Thanos / Mimir / VictoriaMetrics giải bài long-term storage + global view + scale, đều tương thích PromQL. Cốt lõi: đẩy dữ liệu lên object storage rẻ, kèm downsampling cho dữ liệu cũ. Cần vì Prometheus local retention chỉ ~15 ngày.
- Federation (
/federate) chỉ nên gom metric đã aggregate lên view trung tâm — không dùng để sao chép toàn bộ chi tiết hay giải long-term storage. - Trong Kubernetes: dùng kube-prometheus-stack + Prometheus Operator; khai báo scrape qua ServiceMonitor/PodMonitor, rule qua PrometheusRule — declarative, không sửa tay khi pod đổi (k8s-08).
- Bảo mật: Grafana RBAC + SSO; không PII trong metric/label; không phơi
/metrics/federatera Internet; giữ log/metric theo tuân thủ nhưng tách dữ liệu nhạy cảm (devops-08, gov-06). - Chi phí bị chi phối bởi cardinality (số series ≈ tích số giá trị label). Kiểm soát tại nguồn (không đặt ID làm label), downsample, retention phân tầng (nóng/ấm/lạnh), recording rules cho query nặng.
- Văn hoá SRE là nửa còn lại: on-call bền vững, runbook cho mỗi alert, blameless postmortem, giảm alert fatigue (alert phải actionable + urgent), SLO + error budget làm ngôn ngữ chung.
- Kiến trúc tham chiếu ngân hàng: mỗi hệ trọng yếu phủ golden signals + SLO + alert + trace; một Grafana global qua Thanos Query; Alertmanager cluster; tracing qua OTel/Tempo nối cùng cửa sổ điều tra.
Bài viết liên quan
Continuous Integration/Delivery/Deployment, cấu trúc pipeline, ví dụ GitHub Actions và chiến lược release.
Container vs máy ảo, image/layer, Dockerfile, volume, network, Docker Compose và best practices.
Vì sao cần orchestration; Pod, Deployment, Service, Ingress; scaling, self-healing và cấu hình.
Bản chất DevOps: phá bỏ rào cản Dev–Ops, vòng lặp vô tận, CALMS, và vì sao tự động hoá.