Kỹ Sư Thực Chiến - Tư Duy Lường Trước Rủi Ro Hệ Thống Tập 1: "Sự Phản Bội Của Đường Truyền" (Tư duy xử lý gián đoạn kết nối)
"Sự phản bội của đường truyền" không chỉ là dăm ba cái lỗi HTTP Timeout thông thường. Ở kịch bản khốc liệt nhất của dân làm kiến trúc — Quản lý giao dịch tại các thiết bị biên (Edge Devices) như Máy bán vé tự động (Ticket Vending Machine) hoặc Cổng soát vé tự động (AFC) khi kết nối về Central/Station Server bị đứt — thì rủi ro mất mát dữ liệu là hiện hữu .
Khi cáp mạng bị rút, user vẫn nhét tiền vào máy, thẻ vẫn quẹt qua cổng . Trách nhiệm của hệ thống là không được nuốt tiền của khách, cũng không được để mất dấu dòng tiền . Dưới đây là cách một Kỹ sư kinh nghiệm thiết kế luồng sống sót cho kịch bản này .
1. Tư duy "Offline-First" và Cơ chế Store & Forward
Sai lầm sơ đẳng nhất là thiết kế luồng API đồng bộ (Synchronous): Thiết bị quét thẻ -> Gọi API lên Server -> Server trừ tiền -> Trả kết quả -> Thiết bị mở cổng . Mạng đứt = Cổng đóng = Khách hàng chửi .
- Cách làm của Senior: Chấp nhận độ trễ dữ liệu (Eventual Consistency) và đẩy logic kiểm tra xuống thiết bị biên .
- Thiết kế Database cục bộ: Máy bán vé hoặc cổng trạm bắt buộc phải có một Local Database (thường là SQLite để siêu nhẹ và không cần cài đặt server) .
Vòng đời của một Transaction offline :
- Giao dịch phát sinh -> Ghi ngay vào SQLite với status
PENDING_SYNC. (Tuyệt đối không lưu trên RAM, lỡ mất điện đột ngột là mất sạch dữ liệu doanh thu) . - Thiết bị phản hồi thành công cho user ngay lập tức .
- Một Background Worker (Cronjob hoặc Goroutine chạy ngầm) liên tục ping về Server . Khi mạng thông, nó sẽ lấy các bản ghi
PENDING_SYNCđóng thành batch và đẩy về . - Nhận được phản hồi thành công từ Server -> Đổi status thành
SYNCED.
2. Thiết kế Lũy Đẳng (Idempotency) - Chặn đứng thảm họa Duplicate
Đây là bài toán đau đầu nhất khi phục hồi kết nối . Mạng chập chờn sinh ra kịch bản: Máy bán vé đẩy gói data lên Server . Server nhận được, đã ghi vào PostgreSQL thành công, nhưng trên đường trả HTTP 200 OK về lại máy bán vé thì... đứt mạng .
- Hệ quả: Máy bán vé tưởng Server chưa nhận được, lát sau mạng có lại, nó gửi lại gói data đó lần 2 .
- Tư duy giải quyết: Central Server không bao giờ tin tưởng hoàn toàn vào Client . Phải có khiên đỡ Lũy đẳng (Idempotency) .
Kỹ thuật triển khai :
- Mỗi giao dịch sinh ra từ thiết bị phần cứng phải đính kèm một mã
Transaction_ID(chuỗi UUID hoặc sinh theo thuật toán Snowflake) mang tính duy nhất (Unique) ngay tại thời điểm tạo . - Tầng Cache (Redis): Khi Server nhận request, dùng lệnh
SETNX(Set if Not eXists) khóa cáiTransaction_IDnày lại với một TTL (ví dụ 24h) . Nếu request thứ 2 bay vào thấy key đã tồn tại -> Trả về HTTP 200 luôn nhưng không xử lý logic cộng tiền nữa . - Tầng DB (PostgreSQL): Đánh
UNIQUE INDEXcho cộtTransaction_ID. Dù code có lọt qua được Redis thì khi đập xuống DB cũng sẽ văng lỗiduplicate key value violates unique constraint, chặn đứng việc ghi đè doanh thu .
3. Xử lý "Bóng ma đối soát" (Night Batch Processing & Data Variance)
Hậu quả dai dẳng nhất của việc rớt mạng không nằm ở lúc realtime, mà nằm ở file báo cáo cuối ngày . Nếu bạn đang làm việc với các Vendor hoặc nhà thầu thiết bị, đây là chỗ hay sinh ra những biên bản báo lỗi (Defect Notification Form - DNF) nhất .
- Kịch bản rủi ro: Giao dịch xảy ra lúc 23:30 ngày 15/04 . Mạng đứt . Đến 01:00 sáng ngày 16/04 mạng mới có lại và dữ liệu được đẩy về Server .
- Vấn đề: Batch job chốt ca ngày 15/04 chạy lúc 23:59 sẽ KHÔNG có giao dịch này . Số liệu doanh thu báo cáo cho kế toán bị hụt . Ngày hôm sau, giao dịch lại bị tính sang doanh thu của ngày 16/04 -> Data Discrepancy (Chênh lệch dữ liệu) .
Tư duy thiết kế để đối soát :
- Trong schema Database, bắt buộc phải phân tách rõ hai khái niệm thời gian :
transaction_time: Giờ thực tế user quẹt thẻ/mua vé (Do thiết bị gửi lên) .system_sync_time: Giờ Server nhận được dữ liệu .
- Khi viết logic cho Night Batch Processing, bộ lọc (filter) doanh thu phải chạy theo
transaction_time, nhưng phải có Cơ chế quét vét (Sweep Mechanism) . - Nghĩa là: Batch job của ngày 16/04 không chỉ tính các giao dịch phát sinh trong ngày 16, mà phải quét lại xem có giao dịch nào của ngày 15 (hoặc xa hơn) bị delay và mới rớt vào hệ thống ngày hôm nay không, từ đó sinh ra một file "Báo cáo điều chỉnh doanh thu" tự động thay vì để con người đi soi log thủ công .
All Rights Reserved