Vấn đề đầu tiên phải nêu: UPDATE posts SET views = views + 1 mỗi lượt xem sẽ khoá cùng một dòng — bài viral biến thành điểm nóng và làm chậm cả bảng.
Cách làm: đếm ở Redis, ghi xuống DB theo lô.
INCR post:{id}:views:2026-08-06 -- bo dem theo ngay
ZINCRBY trending:2026-08-06 1 {postId} -- bang xep hang
EXPIRE trending:2026-08-06 172800INCRlà thao tác atomic, chi phí rất thấp.- Sorted set cho bảng xếp hạng: lấy top 20 chỉ là
ZREVRANGE trending:{day} 0 19, độ phức tạp log, không cầnORDER BY ... LIMITtrên bảng lớn. - Job mỗi phút đọc bộ đếm ghi vào Postgres để số liệu được lưu bền và phục vụ báo cáo.
Chống đếm gian: một người F5 mười lần không nên tính mười view. Khử trùng lặp theo cửa sổ thời gian bằng key seen:{postId}:{userOrIpHash} với TTL 30 phút, hoặc dùng HyperLogLog khi chỉ cần số lượt xem không trùng ở mức ước lượng (sai số ~0.8%, tốn vài KB thay vì lưu toàn bộ id).
Điểm nghẽn:
- Redis mất dữ liệu khi restart → chấp nhận sai lệch nhỏ ở bộ đếm view (không phải dữ liệu tiền), hoặc bật AOF nếu cần chắc hơn.
- Bảng xếp hạng theo ngày cần TTL, nếu không key sẽ tích tụ vô hạn.
Đánh đổi: số hiển thị trễ và gần đúng thay vì chính xác tuyệt đối. Với lượt xem thì gần đúng là đủ, và đổi lại hệ thống chịu được tải cao gấp nhiều lần. Nếu phỏng vấn hỏi "vậy số liệu quảng cáo tính tiền thì sao" — lúc đó phải dùng đường ghi bền vững (durable), có đối soát, không dùng bộ đếm trong bộ nhớ.