Backend 01/09/2026 8 phút

Đặt volatile-lru khi không khoá nào có TTL chính là tắt hẳn việc dọn dẹp — Redis từ chối ghi trong khi 166.000 khoá bỏ được vẫn nằm nguyên trong RAM

Khi Redis chạm trần bộ nhớ, chính sách maxmemory quyết định nó dọn gì. Đo tám chính sách trên cùng một phép thử: volatile-lru với dữ liệu không TTL cho kết quả y hệt noeviction (0 khoá bị đuổi, 27.610 lỗi ghi) — cái bẫy dễ vấp nhất. Và LRU của Redis là gần đúng (lấy mẫu 5 khoá) nên chỉ giữ được 545/1000 khoá nóng, trong khi LFU giữ đủ 1.000/1.000 mà không cần chỉnh gì.

Backend 01/09/2026 8 phút

Xoá 270.000 khoá khỏi Redis mà RSS không giảm một byte — bộ nhớ trả về theo cả trang, không theo từng khoá, nên xoá rải rác để lại lỗ không thu hồi được

mem_fragmentation_ratio là chỉ số hay bị hiểu sai nhất trong INFO memory. Đo ở ba trạng thái: một instance gần rỗng có tỷ lệ 16,59 mà hoàn toàn khoẻ; xoá 90% khoá thì used_memory tụt còn RSS đứng im ở 107,6 MB vì jemalloc chỉ trả một trang về khi MỌI đối tượng trong đó đã chết. Và activedefrag y, tự nó, thường là lệnh không có tác dụng vì ngưỡng mặc định 100 MB. Cảnh báo trên allocator_frag_bytes, đừng trên tỷ lệ.

Backend 01/09/2026 8 phút

Một lệnh KEYS đẩy độ trễ PING của Redis từ 1 ms vọt lên 263 ms — trong khoảnh khắc đó khoảng 13.000 yêu cầu xếp hàng chờ, và DEL còn tệ hơn KEYS

Redis xử lý lệnh bằng một luồng duy nhất, nên một lệnh chậm không chỉ chậm — nó chặn đầu hàng của mọi khách khác. Đo thật trên 2 triệu khoá: KEYS '*' đẩy PING max lên 263,8 ms, SCAN chậm hơn 58% nhưng độ trễ tệ nhất ít hơn 63 lần vì nó nhường luồng; DEL một Hash 194 MB chặn 467,7 ms còn UNLINK chỉ 3,6 ms. Và độ trễ trung bình gần như không đổi — nên nếu chỉ đo trung bình, cả vấn đề này vô hình.

Backend 01/09/2026 8 phút

Đường ống Redis 10.000 lệnh cho 47,9 lần thông lượng — nhưng đẩy lên 100.000 thì tụt còn một nửa; gộp lô có điểm ngọt, không phải càng lớn càng tốt

Phần 2 thấy đường ống cho hơn bốn mươi lần thông lượng trên một kết nối. Bài này tìm điểm dừng: đường ống 10.000 đạt 969.426 ops/s (47,9×), nhưng 100.000 chỉ còn 473.477 — một nửa, vì chi phí đệm ở hai phía vượt phần tiết kiệm round-trip. Bất ngờ hơn: MGET 100 khoá nhanh hơn đường ống 100 lệnh 45% dù cùng một lượt đi về, vì một lệnh phân tích một lần thay vì trăm lần. Và bộ đệm khách thường không có giới hạn (0 0 0).

Backend 01/09/2026 8 phút

Một Lua script chạy 3 giây trên Redis bắt mọi khách hàng khác chờ đúng 2.951,6 ms — vì tính nguyên tử bạn nhận được CHÍNH LÀ thời gian chặn mọi người phải chịu

Lua cho bạn tính nguyên tử mà MULTI không cho: đọc một giá trị rồi quyết định dựa trên nó. Đo cái giá: script chạy 3,02 giây thì PING của khách khác chạm 2.951,6 ms — độ chặn gần đúng bằng thời gian chạy, không nhường luồng. Vòng lặp vô hạn không làm máy chủ chết (BUSY sau 5 giây, cứu bằng SCRIPT KILL) nhưng script đã ghi thì không giết được. EVALSHA nhanh hơn EVAL 27%, và cache script sinh động rò 340 MB không ai dọn.

Backend 01/09/2026 8 phút

BLPOP nhận việc sau 0,3 mili giây, còn vòng lặp hỏi mỗi 100 ms mất 50,6 ms và tốn gấp 10 lần số lệnh — nhanh hơn 170 lần cho một dòng lệnh đổi tên

Dùng List làm hàng đợi là cách phổ biến nhất, và cách lấy việc ra quyết định gần như mọi thứ. Đo ba cách chờ: BLPOP nhận việc sau 0,3 ms với 0 lần thăm dò, còn vòng lặp hỏi mỗi 100 ms mất 50,6 ms (trung vị luôn xấp xỉ nửa chu kỳ) và gửi gấp 10 lần số lệnh cho không việc gì. Nhưng BLPOP vẫn mất việc khi tiến trình chết — BLMOVE sang danh sách 'đang xử lý' chỉ tốn thêm 9,5%, và đó là ranh giới nên chuyển sang Stream.