Internal Engineering Document

Hệ Thống Đích
Kiến trúc Kioskgaming sau chuyển đổi

Trạng thái hạ tầng khi hoàn tất toàn bộ kế hoạch trong So sánh & Kế hoạch chuyển đổi — dùng làm đích ngắm chung cho cả team: mỗi hạng mục bên dưới hoặc đã có sẵn, hoặc gắn với một bước cụ thể (0A→3C) trong kế hoạch.

Ngày lập: 04/07/2026 Xuất phát: hiện trạng production 5 server Nguyên tắc: bổ sung — không đập đi xây lại Trạng thái: Bản đích v1
01

Sơ đồ kiến trúc đích

Khác biệt so với hiện tại được đánh dấu MỚI. Mọi thứ không đánh dấu là giữ nguyên từ hệ thống đang chạy.

Người dùng / Client apps
6 frontend trên Cloudflare Pages (client · shop · agent · super-agent · admin · cashier) + mobile/kiosk — HTTPS :443
Cloudflare — DNS · CDN · WAF · Load Balancing MỚI · 1B
Health-check chủ động 2 origin, tự loại origin chết trong ~15–60s.
SSL Flexible giữ nguyên ở bản đích v1 — nâng Full (strict) để lại, xem mục 06.
HTTP :80 → 2 origin
Hetzner Firewall firewall-ssh — đã vá MỚI · 0A/0B
:80 whitelist đủ 15/15 dải Cloudflare (khớp set_real_ip_from) · :22 giới hạn IP admin/VPN · port data vẫn default-deny
nginx-lb #1 — V1 (10.0.0.5)
giữ nguyên · least_conn · realip Cloudflare
MỚI · 1A
nginx-lb #2 — V4 (10.0.0.3)
cùng bộ conf, sync bằng sync-nginx.sh (1C)
keepalive 32 (2C) · rate limit ≈20r/s (2C) · timeout 15s/30s (2C)
App tier — V1 + V2
10.0.0.5 · 10.0.0.4
  • 8 instance API prod (least_conn)
  • 2 instance API dev
  • Idempotency middleware MỚI · 1D
  • Số instance/core điều chỉnh theo đo đạc 2A
MỚI · 3A
Data tier — V3 (master) + V4 (replica)
10.0.0.2 · 10.0.0.3
  • PgBouncer :6432 (transaction mode)
  • Postgres 16 master :5432
  • Redis master :6379 (+ requirepass)
  • Slave PG :5433 / Redis :6379 trên V4
  • Read-only → slave (3B, theo số liệu)
  • Runbook failover (3C)
Observability — V5 + 4 Dozzle
10.0.0.6
  • Fluent Bit → OpenSearch → Dashboards
  • replicas:0 + retention ISM MỚI
  • Dozzle per-server, healthcheck đã sửa
  • RabbitMQ :5672 (V4, giữ nguyên)
Kiến trúc đích — 2 gateway, firewall khớp application layer, idempotency, PgBouncer. Nền tảng còn lại giữ nguyên.
Đọc sơ đồ này thế nào

Mỗi nhãn MỚI · x trỏ về đúng một bước trong kế hoạch chuyển đổi (0A, 0B, 1A…3C). Khi một bước hoàn thành, hạng mục tương ứng trên sơ đồ này chuyển từ "đích" thành "hiện trạng" — khi mọi nhãn đều xong, hai tài liệu hợp nhất làm một.

02

Trước / Sau — từng chỉ số

"Trước" là hiện trạng 04/07/2026. "Sau" là trạng thái khi hoàn tất kế hoạch.

Chỉ sốTrước (hiện trạng)Sau (đích)Bước
Gateway nginx1 instance — SPOF trên V12 instance V1 + V4, Cloudflare LB health-check1A–1C
Firewall :80 vs danh sách trust nginxLệch 5/15 vs 15/15 — traffic thật có thể bị DROPKhớp 15/150A
SSH :22Mở toàn InternetGiới hạn IP admin/VPN (hoặc hardening thay thế có ghi nhận)0B
Double-processing giao dịch khi retryKhông có bảo vệIdempotency-Key trên mọi endpoint tiền1D
Connection tới PostgresKhông kiểm soát — 11 client tiềm năng vs max 100PgBouncer transaction mode, multiplex về ~20 conn thật2B, 3A
Redis authKhông password — chỉ dựa firewallrequirepass/masterauth — 2 lớp độc lập3C
Failover data (V3 chết)Thủ công, chưa văn bản hóaRunbook promote slave (tự động hóa để sau)3C
Cấu hình nginx: keepalive / rate limit / timeoutTắt / không có / 60sBật 32 / ≈20r/s / 15s-30s — gộp với DDoS Edge L0–L12C
OpenSearchVĩnh viễn yellow, không retention — index từ 04/2026 còn nguyênreplicas:0, ISM xoá theo ngày — green, disk ổn địnhvệ sinh
Giám sát trạng thái containerDozzle 4/4 unhealthy giả — báo động mất giá trịHealthcheck đúng — unhealthy = sự cố thậtvệ sinh
Nhận diện server khi SSHV2/V3 trùng hostnameHostname duy nhất V1…V5vệ sinh
03

Bố trí server sau chuyển đổi

Không thuê thêm server. Thay đổi duy nhất về bố trí: V4 nhận thêm nginx-lb #2 và PgBouncer đặt cạnh Postgres master trên V3.

ServerVai trò đíchThay đổi so với hiện tại
V1 · CCX23 · 10.0.0.5Gateway #1 + AppKhông đổi thành phần; bớt "duy nhất" — được phép bảo trì/deploy lỗi mà hệ vẫn sống
V2 · CCX13 · 10.0.0.4AppSố instance có thể giảm 4→2 theo kết quả đo 2A (2 vCPU); hostname đổi thành V2-Kiosk
V3 · CCX13 · 10.0.0.2Data master+ PgBouncer :6432 cạnh master; Redis thêm requirepass; hostname V3-Kiosk
V4 · CCX13 · 10.0.0.3Gateway #2 + Replica + Tools+ nginx-lb #2 (:80 — sau khi audit RAM, bước 1A); hostname V4-Kiosk
V5 · CCX23 · 10.0.0.6Gamify + Log hubOpenSearch: replicas:0 + ISM retention; không đổi gì khác
Ràng buộc tài nguyên cần theo dõi

V3 và V4 là hai server "vừa khít" RAM 8GB: V3 = Redis 1.5GB + Postgres buffers/cache ~4GB; V4 = 7 container hiện có + nginx mới. nginx chỉ chiếm vài chục MB nên vừa, nhưng bất kỳ service nào thêm vào 2 server này sau bản đích đều phải tính lại tổng RAM trước — đó là lý do bước 1A có điều kiện tiền đề audit RAM.

04

Hành vi khi mất từng server

Bảng "chết con nào, mất cái gì" — trước và sau chuyển đổi. Đây là thước đo trực tiếp của giá trị kế hoạch.

Sự cốHệ quả TRƯỚCHệ quả SAU
V1 chết Sập toàn hệ — mất gateway duy nhất, mọi domain chết dù V2–V5 còn sống Hệ vẫn chạy — Cloudflare LB chuyển sang gateway #2 (V4) trong ~15–60s; mất tạm 4/8 instance API, còn 4 trên V2 gánh
V2 chết Giảm nửa API — least_conn dồn về V1 Như trước — không đổi (V2 chỉ chạy app)
V3 chết Mất toàn bộ write path — promote slave thủ công, chưa có quy trình viết sẵn, thời gian phục hồi không đoán được Vẫn mất write nhưng phục hồi theo runbook 3C có sẵn từng bước (promote PG slave :5433, đổi Redis replicaof, trỏ lại env backend) — thời gian phục hồi đo lường được
V4 chết Mất replica + tools — không ảnh hưởng user Mất gateway #2 + replica — Cloudflare LB dồn về gateway #1, user không ảnh hưởng; mất tạm khả năng failover data cho tới khi V4 hồi
V5 chết Mất gamify + log tập trung — như nhau ở cả 2 trạng thái; gamify là SPOF riêng của tính năng gamification (chấp nhận ở bản đích v1, xem mục 06)
Điểm mấu chốt

Chuyển đổi này xóa được kịch bản tệ nhất (V1 chết = sập toàn hệ) và biến kịch bản tệ nhì (V3 chết) từ "không đoán được" thành "có quy trình". Hai server còn lại chết chỉ gây suy giảm cục bộ — hệ vẫn phục vụ user.

05

Tiêu chí nghiệm thu

Chuyển đổi được coi là hoàn tất khi tick đủ danh sách dưới — mỗi mục có lệnh/kịch bản kiểm chứng cụ thể, không nghiệm thu bằng cảm giác.

06

Ngoài phạm vi bản đích v1

Ghi rõ để không ai tưởng nhầm là bị quên — đây là các bước nâng cấp có chủ đích để lại sau, kèm điều kiện kích hoạt.

Hạng mụcLý do để lạiKích hoạt khi
Cloudflare Full (strict) — TLS về originCần cài Origin CA cert + nginx listen 443 trên cả 2 gateway; Flexible vẫn chạy ổn và firewall đã siết nguồnSau khi 2 gateway vận hành ổn định; hoặc yêu cầu compliance
Auto-failover data (Sentinel / Patroni)Cần ≥3 node cho quorum + kỹ năng vận hành; runbook thủ công là bước đệm đúng tầmKhi diễn tập runbook cho thấy RTO thủ công không chấp nhận được
HA cho V5 (gamify + log)SPOF cục bộ của một tính năng, không phải core money-pathKhi gamification thành tính năng doanh thu chính
KubernetesCả guideline lẫn bản so sánh đều bác — chi phí vận hành không tương xứng quy môSố service/team tăng gấp nhiều lần
OpenSearch bật security pluginPort đã default-deny từ Internet; ưu tiên thấp hơn retentionKhi có yêu cầu audit nội bộ / thêm người truy cập Dashboards