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

Streaming JSON lớn trong Go: json.Decoder thay vì Unmarshal cả tệp

json.Unmarshal cần toàn bộ dữ liệu trong RAM rồi dựng mọi struct cùng lúc — bộ nhớ tỉ lệ với kích thước tệp, tệp GB làm sập app. json.Decoder đọc lười từng phần tử, giữ bộ nhớ hằng số. Đo thật trong Go: xử lý tệp JSON 41.6 MB, Unmarshal tốn +142.5 MB heap, streaming chỉ +2.3 MB — cùng kết quả.

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

JSON trong Go: tiện đến mức ta quên nó tốn gì — đo thật chi phí reflection

encoding/json của Go tiện kinh khủng: một cặp Marshal/Unmarshal cho mọi struct. Nhưng nó dùng reflection lúc chạy nên có chi phí ẩn. Bài này chạy thật một đơn hàng 5 mặt hàng: đo kích thước JSON (643 byte gọn, 928 byte thụt lề), và benchmark cho thấy Unmarshal chậm ~4 lần Marshal với 27 lần cấp phát bộ nhớ so với 3 — vì giải mã phải dựng lại slice, string, struct con.

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

Tối ưu JSON trong Go: cắt một nửa số lần cấp phát mà không đổi định dạng

Phần 1 đo được encoding/json tốn nhiều cấp phát, nhất là khi giải mã. Bài này giữ nguyên JSON nhưng tối ưu cách dùng: json.Encoder/Decoder ghi đọc thẳng io tránh []byte trung gian, và json.RawMessage hoãn giải mã phần chưa cần. Đo thật: Encoder cắt 50% số lần cấp phát khi ghi 1000 object, RawMessage giảm 61% cấp phát khi chỉ cần field ngoài, Decoder streaming giảm 32% bộ nhớ đổi lấy ~10% thời gian.

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

Protobuf vs JSON: cùng dữ liệu lên bàn cân — nhỏ hơn 2 lần, giải mã nhanh gần 10 lần

Phần 3 đã thấy Protobuf gọn hơn qua từng byte. Bài này cân đầy đủ trên cùng một đơn hàng thật (nested + slice): đo kích thước lẫn tốc độ marshal/unmarshal. Kết quả đo được: Protobuf nhỏ hơn ~2 lần, và giải mã nhanh gấp ~9,7 lần JSON (283 vs 2743 ns) — lợi thế lớn nhất nằm ở giải mã, nơi JSON phải parse text và dùng reflection.

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

MessagePack: JSON nhị phân — nhưng đo thật cho thấy nó không nhỏ như bạn tưởng

MessagePack được quảng cáo là JSON nhị phân gọn hơn. Đúng, nhưng đo thật cho con số khiêm tốn hơn kỳ vọng: cùng một đơn hàng, MessagePack mặc định chỉ nhỏ hơn JSON 1,08 lần, bật compact ints được 1,25 lần — còn xa Protobuf (~2 lần). Lý do lộ ra khi nhìn byte: MessagePack vẫn lưu tên field trong map. Điểm mạnh thật của nó là giải mã nhanh ~2,4 lần JSON và đổi đúng một dòng code.

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

Structured logging: vì sao log JSON đánh bại log văn bản, và trace_id nối log với trace

Log văn bản thuần đọc bằng mắt thì được, nhưng máy khó truy vấn — grep với regex mong manh. Bài này chạy thật slog của Go in log JSON có cấu trúc, rồi dùng jq lọc theo level, theo độ trễ, tổng hợp doanh thu ngay trên log. Và cú chốt: gắn trace_id thật từ OpenTelemetry vào mỗi dòng log — thấy lỗi trong log là nhảy thẳng tới đúng trace trong Jaeger, khớp đã kiểm chứng.