Mạng cho lập trình viên

Sê-ri 45 bài về mạng máy tính nhìn từ góc lập trình viên: mỗi phần dựng lại một hiện tượng mạng trong container rồi đo bằng số thật.

45/45 phần đã đăng Mạng
1 Gói tin từng tầng Mỗi gói tin gánh 66 byte header cố định. Với 1 byte dữ liệu, 98,51% những gì chạy trên dây là header — đo thật bằng tcpdump. 02/09/2026 · 7 phút đọc 2 Địa chỉ IP và subnet Subnet mask, chứ không phải địa chỉ, mới vẽ ra biên mạng con. Cùng một IP có thể trên-link hay ngoài-link tùy prefix — đo thật bằng ip route get. 02/09/2026 · 7 phút đọc 3 ARP trên mạng ảo Trước khi gửi gói đầu tiên tới một hàng xóm, máy phải hỏi MAC bằng một vòng ARP tốn ~190 micro giây — trả một lần rồi cache. Đo thật bằng tcpdump. 02/09/2026 · 7 phút đọc 4 Bắt tay TCP ba bước Mở một kết nối TCP tốn ba gói và một vòng khứ hồi trước khi gửi được byte đầu tiên. Đo thật chuỗi SYN, SYN-ACK, ACK bằng tcpdump. 02/09/2026 · 7 phút đọc 5 TCP so với UDP Dưới mất gói 10%, TCP giao đủ 100% nhưng đuôi trễ vọt lên 200-800 ms vì phát lại; UDP giữ trễ thấp đều nhưng rơi ~10%. Đo thật bằng netem. 02/09/2026 · 8 phút đọc 6 Cổng và socket Một máy khách không mở được 65535 kết nối tới một cổng — trần thật là số cổng tạm (~28232), và nó đếm theo từng bộ bốn. Đo thật bằng container. 02/09/2026 · 8 phút đọc 7 MTU và phân mảnh Vượt MTU thì gói hoặc bị cắt thành mảnh, hoặc bị chặn thẳng nếu đặt cờ DF. Và mất 10% gói có thể thành mất 37% datagram — đo thật bằng container. 02/09/2026 · 9 phút đọc 8 RTT và thông lượng Với cửa sổ cố định, thông lượng TCP tỉ lệ nghịch với RTT — RTT gấp đôi thì tốc độ còn một nửa. Đo thật bằng netem, và một cái bẫy slow-start. 02/09/2026 · 8 phút đọc 9 Cửa sổ TCP Ở RTT cố định, thông lượng tăng tỉ lệ với cửa sổ cho tới khi đụng trần băng thông rồi bằng phẳng. Điểm gãy đúng bằng tích băng thông-độ trễ — đo thật. 02/09/2026 · 8 phút đọc 10 Kiểm soát tắc nghẽn Chỉ 1% mất gói làm sập thông lượng CUBIC khoảng 30 lần, để 97% đường ống bỏ không — vì giao thức đọc mọi gói rơi thành 'tắc'. Đo thật bằng netem. 02/09/2026 · 9 phút đọc 11 Đệm gửi và nhận send() nuốt được khoảng 1,5 lần tổng hai đệm socket rồi mới chặn, dù người nhận không đọc byte nào. Đó là kiểm soát luồng của TCP — đo thật. 02/09/2026 · 8 phút đọc 12 Nagle và ACK trễ Một vòng request/response lẽ ra vài chục micro giây có thể kẹt đúng 40 ms vì Nagle và delayed ACK chờ nhau. Đo thật, và cách nó ẩn hiện. 03/09/2026 · 8 phút đọc 13 Trạng thái TIME_WAIT Bên đóng kết nối trước phải nằm TIME_WAIT đúng 60 giây trên Linux — và tcp_fin_timeout KHÔNG chỉnh được con số đó. Đo thật ai gánh, bao lâu. 03/09/2026 · 8 phút đọc 14 Keepalive TCP Một kết nối có đầu kia biến mất im lặng: mặc định TCP mất hơn 2 giờ mới phát hiện. Bật keepalive tuỳ chỉnh thì xuống vài giây — đo thật công thức IDLE + CNT×INTVL. 03/09/2026 · 8 phút đọc 15 Phân giải DNS Một getaddrinfo gửi HAI truy vấn (A và AAAA) và chờ cả hai; nếu AAAA bị bỏ rơi, lookup stall ~6 giây dù IPv4 sẵn ngay. Đo thật, kèm chuyện OS không cache DNS. 03/09/2026 · 7 phút đọc 16 TTL của DNS Một bản ghi DNS được đệm đúng bằng TTL giây rồi mới hỏi lại nguồn — và đổi bản ghi ở nguồn chỉ có hiệu lực sau khi bản sao đệm hết hạn. Đo thật từng giây. 03/09/2026 · 8 phút đọc 17 DNS đệ quy Một tra cứu nguội đi ba vòng — root, TLD, thẩm quyền — mỗi vòng một khứ hồi; đệm chuỗi ủy quyền để tên kế cùng đuôi chỉ còn 2 vòng. Đo thật bằng cây DNS tự dựng. 03/09/2026 · 7 phút đọc 18 HTTP một request Một GET trên kết nối mới tốn 2 vòng khứ hồi (bắt tay + trao đổi), tái dùng còn 1; và với thân 40 byte, header chiếm ~78% response. Đo thật bằng tcpdump. 03/09/2026 · 7 phút đọc 19 Keep-alive HTTP Tái dùng một kết nối cho 20 request nhanh gấp đôi trên đường RTT ~55 ms (2360 ms xuống 1195 ms) — nhưng trên localhost thì gần như vô hình. Đo thật. 03/09/2026 · 7 phút đọc 20 Chunked transfer Với nội dung sinh dần, Content-Length buộc buffer hết (~530 ms mới có byte đầu) còn chunked stream từng khối (~105 ms) — nhanh gấp 5 lần. Đo thật. 03/09/2026 · 8 phút đọc 21 Nén HTTP gzip giảm một JSON 20 KB còn 2,3 KB (88%); Brotli còn 1 KB (95%) — nhưng nén dữ liệu ngẫu nhiên hay tí xíu chỉ làm PHÌNH thêm. Đo thật gzip vs Brotli. 03/09/2026 · 8 phút đọc 22 Bộ nhớ đệm HTTP Một revalidate với ETag khớp trả về 304 không kèm thân — 56 KB co xuống 152 byte. Nhưng ETag tính sai (đổi mỗi lần) biến 304 thành 200. Đo thật. 03/09/2026 · 7 phút đọc 23 Range request Xin bytes=30000- để tiếp tục tải dở chỉ lấy về 70 KB còn lại thay vì cả 100 KB; xin một khúc giữa chỉ lấy 100 byte. Đo thật, kèm cái bẫy off-by-one. 03/09/2026 · 7 phút đọc 24 HTTP/2 ghép luồng 20 request qua HTTP/2 trên MỘT kết nối xong trong 249 ms; HTTP/1.1 sáu kết nối mất 823 ms, một kết nối nối đuôi mất 3396 ms. Đo thật, kèm một giả thuyết sai. 03/09/2026 · 7 phút đọc 25 HTTP/2 server push Push né được một vòng khứ hồi cho khách mới, nhưng với khách quay lại đã cache CSS, nó gửi lại nguyên 33 KB để tiết kiệm vài ms. Đo cả lợi lẫn hại. 03/09/2026 · 7 phút đọc 26 HTTP/3 QUIC Tôi định đo HTTP/3 bắt tay nhanh hơn và chịu mất gói tốt hơn HTTP/2 — nhưng phép đo cho kết quả ngược, vì QUIC thuần Python không thể đua với TCP của nhân. 03/09/2026 · 7 phút đọc 27 Cookie theo request Một kho cookie 147 byte được kèm vào MỌI request tới miền — kể cả ảnh và CSS không dùng nó. Một trang 30 request tải lên ~4,4 KB chỉ riêng cookie. Đo thật. 03/09/2026 · 7 phút đọc 28 Chuyển hướng Mỗi 301/302 thêm một vòng khứ hồi (~60 ms) khi dùng lại kết nối, nhưng ~2 vòng nếu đổi host. 301 được cache nên lần sau miễn phí; 302 thì không. Đo thật. 03/09/2026 · 7 phút đọc 29 Proxy ngược Một lớp proxy ngược thêm bao nhiêu độ trễ? Cùng máy với backend thì gần như 0; khác máy thì thêm đúng một vòng khứ hồi giữa chúng. Đo thật bằng nginx. 03/09/2026 · 7 phút đọc 30 Cân bằng tải Round-robin chia 60 request thành 20/20/20 — đều theo lượt. Nhưng least-connections chỉ đưa backend chậm 2 request, dồn phần còn lại cho hai backend rảnh. Đo thật. 03/09/2026 · 7 phút đọc 31 Kết nối gộp phía client Kích thước bể kết nối là mức song song của client: pool 1 chạy 30 request mất 2581 ms, pool 30 chỉ 146 ms. Nhưng lợi ích dừng ở đúng sức backend. Đo thật. 03/09/2026 · 8 phút đọc 32 gRPC trên HTTP/2 Cùng một bản ghi, protobuf nhỏ hơn JSON ~2 lần và mã hóa nhanh hơn 7 lần — nhưng không phải 'nhỏ hơn chục lần' như đồn, và gzip còn làm phình payload nhỏ. Đo thật. 03/09/2026 · 8 phút đọc 33 Giữ một kết nối mở Giữ 3000 WebSocket mở tốn 45,8 KB mỗi kết nối trên máy chủ Python — nhưng 3000 socket TCP trần chỉ tốn 0,1 KB. Cái đắt là runtime, không phải kết nối. Đo thật. 03/09/2026 · 10 phút đọc 34 Độ trễ hay băng thông Một trang 40 tài nguyên nhỏ: qua 10 mbit là chững ~520ms, nhưng RTT kéo thời gian tăng tuyến tính. Một file 5MB thì ngược lại. Cái nào giới hạn tùy dạng tải. Đo thật. 03/09/2026 · 9 phút đọc 35 Trễ đuôi p99 Thêm 1% mất gói: p50 vẫn 28ms y như cũ, nhưng p99 nhảy từ 32ms lên 264ms. Mất gói không kéo trung vị — nó dựng một vách đứng ở cái đuôi. Đo thật bằng netem. 03/09/2026 · 8 phút đọc 36 Bóp băng thông Bóp xuống 10 mbit thì tc làm chính xác. Nhưng màn bufferbloat kinh điển tôi định dựng lại không xảy ra: TCP tự ghìm, đệm 3MB chỉ đọng 8 gói. Chỉ flood UDP mới bơm đầy. Đo thật. 03/09/2026 · 8 phút đọc 37 Ánh xạ cổng NAT NAT Linux không ném cho bạn cổng ngẫu nhiên: nó GIỮ cổng nguồn 40000 -> 40000, dùng cùng cổng ngoài cho mọi đích, chỉ đổi khi trùng. Đo thật bằng conntrack. 03/09/2026 · 8 phút đọc 38 Cô lập mạng Hai network namespace cùng bind cổng 8080 mà không xung đột — nhưng bind lại trong cùng một vùng thì Errno 98. Danh tính socket là (vùng, địa chỉ, cổng), không phải số cổng. Đo thật. 03/09/2026 · 8 phút đọc 39 Cầu nối và veth veth là sợi cáp ảo nối đúng hai vùng; cầu nối là switch ảo cho nhiều vùng. Tôi định chứng minh chuỗi cáp không phải mạng — nhưng nó chạy, vì netns thừa kế ip_forward=1 của Docker. Đo thật. 03/09/2026 · 8 phút đọc 40 Luật lọc gói Một luật DROP làm client TREO 7 giây (mặc định ~127 giây) trong im lặng; REJECT từ chối ngay 0,1 ms. Và 10000 luật iptables làm RTT gấp 2,5 lần, còn một luật ipset thì không. Đo thật. 03/09/2026 · 8 phút đọc 41 Socket Unix và TCP Cho hai tiến trình cùng máy, Unix socket nhanh hơn TCP loopback — nhưng chỉ ~1,6 lần độ trễ (18,8 so 30,2 us), không phải chục lần. Và bẫy Nagle tôi giăng sẵn không sập. Đo thật. 03/09/2026 · 7 phút đọc 42 Một luồng TCP Bắt gói một lần GET: 10 gói, mà chỉ 2 gói chở HTTP — 8 gói còn lại là bắt tay, ACK và đóng kết nối. Và một byte ma của SYN/FIN suýt làm tôi đọc sai bản bắt. Đo thật bằng tcpdump. 03/09/2026 · 7 phút đọc 43 Vòng đời kết nối Đọc vòng đời một kết nối TCP qua ss: LISTEN, ESTABLISHED, TIME-WAIT, CLOSE-WAIT. Hạ tcp_fin_timeout không rút được TIME-WAIT — nó chỉnh một trạng thái khác. Đo thật. 03/09/2026 · 7 phút đọc 44 Thoái lui và jitter Thử lại ngay dội 2000 request vào một server chỉ lỗi 2 giây. Và exponential backoff KHÔNG jitter vẫn khiến 50 client thử lại thành từng đợt ~50 gói đồng bộ — jitter mới dập được. Đo thật. 03/09/2026 · 8 phút đọc 45 Ngân sách độ trễ Bốn chặng gọi tuần tự tốn 261ms; song song hoá còn 63ms. Một chặng chậm +100ms đẩy tổng song song lên 172ms — bằng chặng chậm nhất, không phải tổng. Bài cuối của sê-ri. Đo thật. 03/09/2026 · 7 phút đọc