Kỹ Sư Thực Chiến - Tư Duy Lường Trước Rủi Ro Hệ Thống Tập 4: "Bóng Ma Dữ Liệu" (Tư duy thiết kế Log và Audit)
Khi một server bị sập (Crash) hoặc API trả về lỗi 500 thì cả team đều thấy, monitor sẽ báo động đỏ. Lỗi đó tuy to nhưng dễ fix. Kẻ thù đáng sợ nhất là những "bóng ma dữ liệu" - lỗi chạy ngầm, API vẫn trả về 200 OK, code không quăng exception, nhưng dữ liệu đối soát cuối ngày lại bị lệch.
Trong những hệ thống phức tạp như trạm thu phí tự động (AFC) hay xử lý giao dịch tài chính, việc Station Server và Central Server lệch nhau vài đồng doanh thu sau các luồng Night Batch Processing thường kéo theo những đợt cãi vã, đổ lỗi không hồi kết với các Vendor thông qua hàng tá biên bản DNF (Defect Notification Form).
Để không rơi vào thế yếu khi cãi lý với Vendor, đây là tư duy thiết kế vết tích (Log/Audit) từ trong máu của Senior.
1. Rạch ròi giữa Application Log và Audit Trail
Nhiều người thường gom chung khái niệm "ghi Log" thành một: Lỗi gì cũng nhét vào file log của server. Đến lúc mất tiền, mở file log ra toàn là stack trace đỏ lòm vô nghĩa.
- Tư duy cốt lõi: Phải tách bạch giữa Log cho kỹ sư đọc (để debug) và Log cho nghiệp vụ đọc (để truy vết dòng tiền/dữ liệu).
- Hành động cần làm:
- Application Log: Ghi nhận "sức khỏe" của code (Ví dụ: Thời gian query DB mất 500ms, gọi API ngân hàng bị timeout, Memory đang tăng).
- Audit Trail (Lưu vết kiểm toán): Ghi nhận "vòng đời" của dữ liệu. Một bản ghi Audit chuẩn phải trả lời được 4 câu hỏi (4W): Who (Ai/Hệ thống nào gọi?), When (Thời gian chính xác tới miligiây?), What (Trạng thái Cũ - Old Value là gì, Trạng thái Mới - New Value là gì?), Where (Từ IP/Thiết bị nào?).
- Quy tắc vàng: Tuyệt đối không bao giờ cho phép thực hiện lệnh
UPDATEhayDELETEcứng trên các bảng dữ liệu cốt lõi (như giao dịch vé) mà không sinh ra một bản ghi log đi kèm ở bảngaudit_logs.
2. Sợi chỉ đỏ "Correlation ID" (Truy vết liên hệ thống)
Một giao dịch mua vé tại máy tự động (Ticket Vending Machine) sẽ đi qua luồng: Máy bán vé -> Station Server -> Central Server -> Payment Gateway. Nếu giao dịch bị xịt ở đâu đó giữa chừng, làm sao ghép nối các đoạn log nằm rải rác ở 4 hệ thống khác nhau để điều tra?
- Tư duy cốt lõi: Dữ liệu trôi đi đâu, căn cước công dân của nó phải đi theo đó.
- Chiến thuật triển khai:
- Ngay từ lúc request phát sinh tại Client/Máy bán vé, sinh ra một chuỗi UUID duy nhất, gọi là
X-Correlation-ID. - Chuỗi ID này phải được nhét vào HTTP Header của tất cả các luồng gọi API nội bộ, và chèn vào mọi dòng log được ghi xuống đĩa hoặc đẩy lên hệ thống quản lý (như Elasticsearch).
- Khi có khiếu nại (VD: vé lỗi lúc 14h30), chỉ cần lấy cái Correlation-ID đó ném vào hệ thống tìm kiếm tập trung (Kibana), bạn sẽ thấy toàn bộ hành trình của dòng dữ liệu từ lúc chạm vào máy bán vé cho đến lúc chết ở Central Server, không cãi đi đâu được.
- Ngay từ lúc request phát sinh tại Client/Máy bán vé, sinh ra một chuỗi UUID duy nhất, gọi là
3. Vũ khí tối thượng: Change Data Capture (CDC)
Ghi Audit log bằng code (Application-level) có một nhược điểm chí mạng: Rủi ro bất đồng bộ. Giả sử code gọi lệnh UPDATE database thành công, nhưng chuẩn bị gọi lệnh INSERT vào bảng audit log thì server... sập nguồn. Kết quả là dữ liệu bị thay đổi mà không hề có dấu vết. Hoặc tệ hơn, DBA vào thẳng Database gõ lệnh UPDATE thủ công, code không hề hay biết.
- Tư duy cốt lõi: Code có thể nói dối (hoặc chết nửa chừng), nhưng log của Database thì luôn nói thật.
- Chiến thuật triển khai (CDC):
- Không bắt ứng dụng (Backend app) phải chịu trách nhiệm ghi log thay đổi dữ liệu nữa.
- Triển khai các công cụ CDC (Ví dụ: Debezium) đọc trực tiếp vào các file log nguyên thủy của Database (như WAL của PostgreSQL hoặc Binlog của MySQL).
- Bất kỳ thay đổi nào ở mức độ row-level (dù là do app chạy hay do DBA sửa tay) đều sẽ được bắt lại ngay lập tức và đẩy stream vào Kafka. Từ Kafka, data được đẩy sang một Database khác (hoặc Data Warehouse) chuyên dùng để lưu lịch sử. Vừa an toàn tuyệt đối, vừa không làm chậm luồng xử lý chính của ứng dụng.
4. Thiết kế Job Đối soát (Reconciliation) chủ động
Đừng đợi có biên bản báo lỗi hay khách hàng gọi lên tổng đài phàn nàn thì mới đi tra log. Tư duy phòng thủ là hệ thống phải tự biết nó đang bị sai lệch.
- Góc nhìn của Senior: Log sinh ra không chỉ để con người đọc, mà để máy tự đọc và tự bắt lỗi nhau.
- Chiến thuật triển khai:
- Thiết kế các Night Batch Job chạy vào khung giờ thấp điểm (VD: 2h sáng).
- Nhiệm vụ của các Job này là lấy tập dữ liệu chốt ca của các Station Server, so khớp chéo (Cross-check) với dữ liệu đã lưu tại Central Server dựa trên
Transaction_ID. - Nếu phát hiện mâu thuẫn (bên A có mà bên B không, hoặc status bên A là Success nhưng bên B là Pending), lập tức sinh ra một file "Discrepancy Report" (Báo cáo chênh lệch) và tự động alert qua Email/Telegram cho team Vận hành hoặc team QA trước khi trời sáng.
All rights reserved