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.

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

Bắt tay WebSocket đọc từng byte: 155 byte đi, 129 byte về, Sec-WebSocket-Accept tự tính bằng SHA-1 khớp đúng ví dụ của RFC, bắt tay mất 80 µs ngang một GET mở kết nối mới nhưng gấp 8 lần GET keep-alive, và bốn cách bắt tay hỏng kèm mã lỗi thật

Một client Go viết tay từng dòng header bắt tay WebSocket và in nguyên văn phản hồi: 155 byte đi, 129 byte về sau 333 µs, Accept là base64 của SHA-1 key nối GUID, khớp đúng ví dụ RFC 6455. Đo 2.000 lần: dial WebSocket mất 80 µs p50, GET mở kết nối mới 94 µs, GET keep-alive 10 µs. Sau bắt tay, một thông điệp 10 byte tốn 16 byte đi và 12 byte về so với 99 byte header tối thiểu của một GET. Bốn cách hỏng đo thật: thiếu Upgrade 400, version 12 cũng 400 thay vì 426, Origin lạ 403, proxy bỏ header Upgrade gây bad handshake trong khi ReverseProxy của Go cho 101.

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

Slowloris đo thật: 400 kết nối gửi một byte mỗi 500 ms, chỉ 6,4 Kbit mỗi giây, làm server Go không timeout trèo lên 252 goroutine và từ chối 80% client thật; ReadHeaderTimeout dọn sạch, giới hạn 50 kết nối mỗi IP thì không cả spike

Một client mở 400 kết nối tới server Go và gửi header nhỏ giọt một byte mỗi 500 ms, không bao giờ hoàn tất request. Server http.Server{} mặc định không timeout: trèo lên 252 goroutine, cạn file descriptor với 37 lần too many open files, client thật rớt từ 20/20 còn 2/10. Thêm ReadHeaderTimeout 3 giây: spike 252 goroutine trong 2 giây rồi timeout đóng hết, goroutine về 2, client thật 10/10. Thêm giới hạn 50 kết nối mỗi IP ở tầng Accept: 350 trên 400 bị đóng ngay, 0 lần cạn file descriptor. Băng thông tấn công chỉ 6,4 Kbit mỗi giây.