Q

Quản trị viên

Là một lập trình viên yêu công nghệ, thích viết blog để chia sẻ kiến thức, kinh nghiệm lập trình và những điều thú vị trong thế giới tech.

2312 bài viết · Website
Lập trình Go 22/09/2026 10 phút

sqlc trong Go: viết SQL, sinh code Go an toàn kiểu — bắt lỗi lúc biên dịch

ORM giấu SQL và dùng reflection; database/sql viết tay linh hoạt nhưng Scan thủ công dễ sai và lỗi tên cột chỉ lộ lúc chạy. sqlc lật ngược: bạn viết SQL thật, nó sinh code Go an toàn kiểu và kiểm SQL so với schema ngay lúc sinh. Đo thật: sqlc bắt cột không tồn tại trước cả khi biên dịch Go.

Bảo mật 22/09/2026 6 phút

Xoay khoá mà không mã hoá lại cả kho: bao khoá (envelope encryption) và key-id

Đổi khoá mã hoá thì phải giải mã rồi mã hoá lại hàng triệu bản ghi? Không. Bài này dựng demo thật bằng python: mô hình bao khoá KEK bọc DEK, mỗi bản ghi lưu kèm kek_id. Xoay khoá chỉ cần re-wrap DEK vài chục byte, dữ liệu giữ nguyên; dữ liệu cũ vẫn giải được; và chỉ thu hồi khoá cũ sau khi mọi bản ghi đã chuyển.

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

Distributed tracing: khi metric chỉ nói 'chậm', trace chỉ đúng span nào ngốn thời gian

Metric báo checkout p99 = 127ms. Nhưng 127ms đó tiêu ở đâu — validate, query DB, hay gọi payment? Metric không biết. Bài này dựng thật tracing với OpenTelemetry và Jaeger: tạo span lồng nhau, export, rồi query Jaeger API lấy trace thật — và thấy ngay queryDB ngốn 91ms (72% tổng) trong khi validate chỉ 3.85ms. Đây là thứ metric tổng hợp không bao giờ chỉ ra được.

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.

Web 22/09/2026 6 phút

Mã trạng thái và redirect HTTP: 301 vs 302 vs 307/308, và bẫy đổi POST thành GET

Ai cũng biết 404 và 500, nhưng khác biệt thật giữa 301 và 302, giữa 307 và 308 thì nhiều người mơ hồ. Điểm mấu chốt không chỉ là vĩnh viễn hay tạm thời — mà là có giữ nguyên phương thức POST hay không. Bài này đo thật: 301/302 âm thầm đổi POST thành GET, 307/308 giữ nguyên, và một vòng lặp redirect dừng ở đâu.