Lập trình 22/09/2026 8 phút

Nén response API: đo thật gzip và brotli — JSON 21 KB còn 2,2 KB trong 125 µs, brotli-11 tốn 16,85 ms cho thêm 2%, và thân 11 byte nén xong thành 35 byte

Đo nén trên JSON thật từ PostgreSQL, từ 308 byte tới 2,09 MB: gzip-6 đưa 21,2 KB xuống 2,2 KB (10,6%) với 125 µs nén và 26 µs giải. Mức nén gần như không quan trọng với JSON — gzip-1 và gzip-9 chênh 0,3 điểm phần trăm — nhưng brotli-11 tốn 16,85 ms, gấp 135 lần brotli-4, để mua thêm 1 điểm. Hai trường hợp nén làm hại: thân dưới 100 byte phình thêm 24 byte, và JSON chứa ảnh base64 chỉ còn 75% nhưng tốn CPU gấp 17 lần. Kèm thương lượng Accept-Encoding qua HTTP thật, header Vary bắt buộc, và điểm hoà vốn theo băng thông tính từ số đo.

Lập trình 22/09/2026 8 phút

Giới hạn tần suất API: đo thật trên Redis — bản đọc-rồi-ghi cho qua 50/50 khi giới hạn là 20, fixed window lọt gấp đôi ở biên cửa sổ, và client phớt lờ 429 gửi 52.853 request để lấy 100 thành công

Token bucket trên Redis 7 viết hai cách: hai lệnh rời (HMGET rồi HSET) và một script Lua nguyên tử. 50 request đến cùng lúc với giới hạn 20: bản rời cho qua 50/50 ở hai trên ba lần chạy, bản Lua đúng 20/50 mọi lần. Fixed window cho lọt 200 request trong 0,6 giây quanh biên cửa sổ khi giới hạn là 100/10 giây; sliding log đúng 100. Server trả RateLimit-Limit, RateLimit-Remaining và Retry-After: client cần 100 request thành công ở 20 request/giây — phớt lờ 429 gửi 52.853 request, retry cố định 50 ms gửi 175, tôn trọng Retry-After gửi 104, cả ba cùng mất 4 giây.

Lập trình 22/09/2026 7 phút

Thiết kế payload: đo thật N+1 qua HTTP — 51 request mất 172,7 ms so với 1 request 3,1 ms, và expand mà server tự N+1 vào database thì chỉ đổi chỗ vấn đề

Một màn hình cần 50 review kèm tên và giá sản phẩm. Client làm N+1 qua HTTP: 51 request, 51 query, 172,7 ms với RTT giả lập 2 ms; chạy song song 10 luồng còn 31,2 ms nhưng vẫn 51 request. Endpoint bulk ?ids= còn 2 request, 7,6 ms. ?expand=product còn 1 request, 3,1 ms — nhưng chỉ khi server gom id thành một query IN; bản server tự lặp từng sản phẩm vẫn tốn 51 query. Chọn trường ?fields=id,ten,gia cắt 3,0 KB xuống 0,4 KB vì mỗi sản phẩm mang theo mô tả 256 ký tự màn hình không hiện. Ở RTT 20 ms, N+1 là 1,17 giây cho 50 dòng.

Lập trình 22/09/2026 7 phút

Validation và hợp đồng đầu vào: đo thật — để lỗi lọt tới database là 1.000 rollback, kiểm-rồi-chèn tạo 48 dòng trùng cho một email, và gom lỗi giảm 6 vòng gửi còn 2

Cùng một request sai, 1.000 lần: để database bắt bằng CHECK tốn 110 µs và 1.000 rollback thật đếm từ pg_stat_database, thân lỗi mang tên constraint; kiểm ở biên tốn 41 µs, 0 rollback, thân lỗi mang tên trường. Form sai 5 trường: dừng ở lỗi đầu bắt client gửi 6 vòng, gom mọi lỗi còn 2. Nhưng kiểm ở biên không thay được ràng buộc: 50 request đăng ký cùng email đến cùng lúc, có bước băm bcrypt 60 ms giữa SELECT và INSERT, tạo 48 dòng trùng; UNIQUE trong database giữ đúng 1 và trả 409. Thân 20 MB: không giới hạn thì đọc hết rồi mới chê sau 66,6 ms, MaxBytesReader 1 MB trả 413 sau 2,1 ms.

Lập trình 22/09/2026 9 phút

Timeout, retry và deadline xuyên suốt: đo thật chuỗi gateway → A → B — retry ở mỗi tầng đẩy p99 lên 771 ms và 98 lần A làm việc vào hư không, deadline truyền xuống giữ p99 255 ms

Ba service trong một chuỗi gọi, B chậm 400 ms ở 30% request, người dùng chịu được 250 ms. Không timeout: p99 410 ms. Mỗi tầng tự đặt timeout: gateway bỏ đi lúc 250 ms nhưng A vẫn chờ B tới cùng — 61 lần làm việc vào hư không, 139/200 thành công. Mỗi tầng tự retry: 194/200 thành công nhưng p99 771 ms, B nhận gấp 2,1 lần request, 98 lần A làm việc vô ích. Deadline 250 ms truyền qua header và context: 180/200, p99 255 ms, 0 việc vô ích, và khi gateway huỷ thì cả A lẫn B dừng theo — 80 lần B dừng sớm thay vì chạy hết 400 ms.

Lập trình 22/09/2026 9 phút

Tổng kết Thiết kế API: gom 11 phép đo vào một endpoint — 2.000 request tới origin còn 6, 8,5 MB qua dây còn 28 KB, p99 từ 30 ms xuống 1,7 ms

Phần cuối sê-ri gom các bài học đã đo vào đúng một endpoint danh sách — keyset, chỉ trường cần, ETag, Cache-Control với stale-while-revalidate, gzip, Vary — rồi đặt cạnh bản viết trong năm phút dưới cùng lưu lượng: 20 client song song, 2.000 request, 70% lật trang đầu và 30% nhảy tới trang 5.000. Kết quả: request tới origin từ 2.000 xuống 93 khi cache lạnh và 6 khi ấm, byte qua dây từ 8,5 MB xuống 27,7 KB, p99 từ 30,12 ms xuống 1,68 ms. Không có thư viện mới, chỉ sáu header và một mệnh đề WHERE. Kèm khung quyết định cho từng chủ đề và checklist rà soát API trước khi lên production.