Tám phần trước dùng hit ratio làm thước đo chính: 37,6% leo lên 95% ở phần 2, 80,2% so với 100% ở phần 8. Giờ là lúc soi lại chính cái thước đó, vì nó có hai cách hiểu sai phổ biến đến mức gần như mặc định — và cả hai đều làm bạn mù đúng lúc cần nhìn nhất.

Hai cách tính, hai kết luận

Ảnh chụp đoạn mã nền tối hit ratio là con số dễ đo nhất cũng dễ hiểu sai nhất với ba chủ đề tích luỹ so với cửa sổ tỉ lệ so với tuyệt đối và giá trị biên, cùng một dữ liệu hai cách tính hai kết luận gồm bản TÍCH LUỸ cộng dồn từ lúc khởi động mà Redis INFO stats cho kiểu này với công thức hitRatio bằng keyspace_hits chia cho tổng keyspace_hits cộng keyspace_misses, và bản CỬA SỔ chỉ tính trong 1 giây vừa rồi với công thức hitRatio bằng hitTrongGiay chia cho tổng hitTrongGiay cộng missTrongGiay, mẫu số của bản tích luỹ lớn dần mãi nên một sự cố đang diễn ra chỉ làm nó nhúc nhích vài phần trăm và càng chạy lâu càng ì, ba đại lượng trả lời ba câu hỏi khác nhau gồm hit ratio cửa sổ cho biết cache có đang làm việc không dùng để cảnh báo, miss mỗi giây cho biết database đang phải gánh bao nhiêu dùng cho dung lượng, trễ hit so với miss cho biết mỗi lần hit tiết kiệm được bao lâu dùng để tính giá trị, chỉ nhìn hit ratio là mất hai câu hỏi sau vì hai dịch vụ cùng hit ratio 98 phần trăm có thể đặt lên database hai mức tải chênh nhau hàng chục lần, phép đo gồm bước 1 cache nóng sẵn 500 key rồi từ giây 6 tới 8 cho một bot quét id lạ chiếm 60 phần trăm lưu lượng để so hit ratio cửa sổ với hit ratio tích luỹ và bước 2 hai dịch vụ A hit 98 phần trăm ở lưu lượng cao và B hit 90 phần trăm ở lưu lượng thấp xem ai thực sự làm database mệt hơn

Hình 1: Hai công thức khác nhau đúng ở mẫu số. Bản tích luỹ — chính là thứ INFO stats của Redis cho bạn — có mẫu số lớn dần mãi theo thời gian chạy.

Công thức quen thuộc nhất là lấy thẳng từ INFO stats:

hitRatio = keyspace_hits / (keyspace_hits + keyspace_misses)

Hai bộ đếm này cộng dồn từ lúc Redis khởi động. Sau một tuần chạy, mẫu số có thể là hàng tỉ — và một sự cố kéo dài vài phút chỉ làm nó nhúc nhích ở chữ số thập phân thứ hai. Con số đó trả lời câu hỏi "cache đã làm việc tốt tới đâu tính từ đầu", không phải "cache có đang làm việc lúc này không". Hai câu hỏi khác nhau, và chỉ có câu thứ hai dùng để cảnh báo được.

Đo thật: cửa sổ 44,82% trong khi tích luỹ vẫn 95,78%

Mình làm nóng 500 key, rồi từ giây thứ 6 tới giây thứ 8 cho một "bot" chiếm 60% lưu lượng và quét các id lạ — tình huống rất thật: một con crawler, một client có bug, hoặc ai đó dò id tuần tự.

Ảnh chụp output thật nền tối cửa sổ 44,8 phần trăm trong khi tích luỹ vẫn 95,8 phần trăm với Go Redis 7 PostgreSQL 16 và 500 key nóng bot quét id lạ ở giây 6 đến 8, bảng sự cố đang diễn ra hai con số nói hai chuyện gồm giây 5 hit cửa sổ 100 phần trăm hit tích luỹ 100 phần trăm miss 0, giây 6 hit cửa sổ 44.82 phần trăm hit tích luỹ 95.78 phần trăm miss 6407 khi bot đang quét id lạ, giây 7 cửa sổ 54.12 phần trăm tích luỹ 92.55 phần trăm miss 5841, giây 8 cửa sổ 62.84 phần trăm tích luỹ 90.21 phần trăm miss 5211, giây 9 cửa sổ 100 phần trăm tích luỹ 91.50 phần trăm miss 0, giây 10 cửa sổ 100 phần trăm tích luỹ 92.49 phần trăm miss 0, nên cảnh báo đặt ở hit ratio dưới 90 phần trăm sẽ không kêu vì bản tích luỹ chạm đáy 90,21 phần trăm trong khi bản cửa sổ xuống 44,82 phần trăm ngay giây đầu tiên tức cùng một sự cố mà một bên thấy một bên không, bảng hit ratio cao hơn database lại mệt hơn cho thấy dịch vụ A hit 98,01 phần trăm lưu lượng cao 18844 req mỗi giây đặt 375 truy vấn DB mỗi giây còn dịch vụ B hit 90,20 phần trăm lưu lượng thấp 814 req mỗi giây chỉ đặt 80 truy vấn DB mỗi giây nên A có hit ratio đẹp hơn 8 điểm mà đặt lên database tải gấp 4,7 lần vì hit ratio là tỉ lệ còn database chịu con số tuyệt đối, bảng giá trị biên mỗi bước là một lần giảm nửa số miss với hit ratio 90 phần trăm thì miss ratio 10 phần trăm tải DB 1,00 lần, 95 phần trăm thì miss 5 phần trăm tải 0,50 lần tức thêm 5 điểm cắt một nửa tải DB, 97,5 phần trăm thì miss 2,5 phần trăm tải 0,25 lần tức thêm 2,5 điểm cắt tiếp một nửa, 98,75 phần trăm thì miss 1,25 phần trăm tải 0,12 lần, 99,375 phần trăm thì miss 0,625 phần trăm tải 0,06 lần tức thêm 0,625 điểm vẫn cắt một nửa, nên theo dõi miss ratio thay vì hit ratio vì 99,375 và 98,75 trông như nhau trên biểu đồ nhưng 0,625 và 1,25 thì chênh đúng gấp đôi và gấp đôi tải database

Hình 2: Kết quả thật. Ba bảng cho ba hiểu lầm khác nhau về hit ratio.

Hit ratio cửa sổ rơi xuống 44,82% ngay giây đầu tiên của sự cố. Hit ratio tích luỹ, cùng lúc đó, vẫn là 95,78%.

Hệ quả rất cụ thể cho việc giám sát: một cảnh báo đặt ở ngưỡng quen thuộc "hit ratio < 90% thì kêu" sẽ không kêu, vì bản tích luỹ chạm đáy ở 90,21% rồi bò lên lại. Trong khi đó database đang nhận hơn 6.000 truy vấn mỗi giây mà trước đó nhận 0. Cùng một sự cố: một thước đo thấy rõ, một thước đo gần như không thấy gì.

Và chú ý bản tích luỹ không hồi phục sau khi sự cố qua: giây 9 và 10 có hit ratio cửa sổ 100% nhưng tích luỹ chỉ bò từ 91,50% lên 92,49%. Nó mang theo quá khứ mãi mãi. Một sự cố tuần trước vẫn đang kéo con số của hôm nay xuống, và bạn không có cách nào phân biệt "đang hỏng" với "từng hỏng".

Hiểu lầm thứ hai: hit ratio cao hơn không có nghĩa database nhẹ hơn

Bảng thứ hai so hai dịch vụ:

hit ratio lưu lượng truy vấn DB mỗi giây
A 98,01% 18.844 req/s 375
B 90,20% 814 req/s 80

A có hit ratio đẹp hơn 8 điểm nhưng đặt lên database tải gấp 4,7 lần. Không có gì nghịch lý ở đây, chỉ là số học: tải database = lưu lượng × miss ratio. A có miss ratio nhỏ hơn 5 lần nhưng lưu lượng lớn hơn 23 lần.

Hệ quả thực dụng: hit ratio không phải thước đo dung lượng. Nếu bạn đang hỏi "database có gánh nổi không?", con số cần nhìn là miss trên giây — một đại lượng tuyệt đối. Hit ratio chỉ trả lời "cache có hiệu quả không", một câu hỏi về chất lượng cấu hình. Dashboard cache nên có cả hai, và cảnh báo về dung lượng phải gắn vào con số tuyệt đối.

Hiểu lầm thứ ba: mỗi điểm hit ratio không đáng giá như nhau

Bảng thứ ba là số học thuần, không phải đo đạc, nhưng nó sửa một trực giác sai rất dai dẳng:

hit ratio miss ratio tải DB so với mốc 90%
90% 10% 1,00×
95% 5% 0,50×
97,5% 2,5% 0,25×
98,75% 1,25% 0,12×
99,375% 0,625% 0,06×

Mỗi bước trong bảng cắt một nửa tải database, nhưng số điểm hit ratio tăng thêm nhỏ dần: 5 điểm, rồi 2,5, rồi 1,25, rồi 0,625. Nói cách khác: đi từ 98,75% lên 99,375% có giá trị đúng bằng đi từ 90% lên 95% — cả hai đều cắt một nửa số lần chạm database — dù trên biểu đồ, cái sau trông như một bước nhảy còn cái trước trông như đường thẳng.

Đây là lý do nên vẽ miss ratio, không vẽ hit ratio. 99,375% và 98,75% nhìn như nhau trên trục 0–100%; 0,625% và 1,25% thì rõ ràng chênh gấp đôi. Trục log cho miss ratio còn tốt hơn nữa.

Đánh đổi cần cân nhắc

Hit ratio cao không tự nó là mục tiêu. Rất dễ kéo hit ratio lên bằng cách tăng TTL — nhưng như phần 3 đã đo, cái giá là dữ liệu cũ hơn, và cái giá đó không xuất hiện trên biểu đồ hit ratio. Một hệ thống hit ratio 99,9% phục vụ dữ liệu cũ 10 phút có thể tệ hơn hẳn hệ thống 95% phục vụ dữ liệu cũ 10 giây. Luôn đọc hit ratio cạnh một thước đo về độ cũ, nếu không bạn đang tối ưu đúng một nửa bài toán.

Hit ratio của Redis khác hit ratio của ứng dụng. keyspace_hits đếm mọi lệnh đọc trúng key trên toàn instance — gồm cả key khoá của phần 6, key phiên đăng nhập, key hàng đợi, mọi thứ. Nếu ứng dụng dùng chung một Redis cho nhiều việc, con số đó trộn lẫn hết và không nói lên gì về cache của bạn. Bộ đếm trong ứng dụng, tách theo từng loại key, mới là thứ dùng được — và đó cũng là lý do mọi phép đo trong loạt bài này đều đếm ở tầng ứng dụng rồi mới đối chiếu với INFO stats.

Cửa sổ quá ngắn thì nhiễu, quá dài thì ì. Cửa sổ 1 giây ở đây hợp với một thí nghiệm 10 giây, nhưng ở production nó sẽ nhảy loạn vì lưu lượng tự nhiên không đều. Cửa sổ 1–5 phút (hoặc rate() trong Prometheus) là điểm cân bằng thường dùng: đủ nhạy để bắt sự cố trong vài phút, đủ mượt để không báo động giả. Điều quan trọng là có cửa sổ, chứ không phải chọn đúng con số.

Số đo ở đây là một tiến trình, tập key 500, trong container. Con số tuyệt đối (18.844 req/s, 6.407 miss/giây) chỉ là của môi trường này. Thứ mang đi được là ba quan hệ: mẫu số tích luỹ làm thước đo ì dần, tải database = lưu lượng × miss ratio, và mỗi lần giảm nửa miss ratio là một bước có giá trị như nhau.

Ba ý mang về

  1. Hit ratio tích luỹ không dùng để cảnh báo được: khi bot quét làm cache gãy, cửa sổ 1 giây rơi xuống 44,82% còn tích luỹ chỉ chạm đáy 90,21% — ngưỡng cảnh báo 90% không kêu. Bản tích luỹ còn mang theo mọi sự cố cũ mãi mãi, nên không phân biệt được "đang hỏng" với "từng hỏng".
  2. Hit ratio là tỉ lệ, database chịu con số tuyệt đối: A hit 98,01% đặt 375 truy vấn/giây lên database, B hit 90,20% chỉ đặt 80 — chênh 4,7 lần theo chiều ngược với hit ratio. Hỏi về dung lượng thì nhìn miss trên giây.
  3. Vẽ miss ratio thay vì hit ratio: mỗi lần giảm nửa miss ratio cắt một nửa tải database, nên 98,75% → 99,375% đáng giá đúng bằng 90% → 95%. Trên trục hit ratio, bước thứ hai trông như không có gì.

Nguồn

Phần sau ta nhìn vào chỗ hit ratio hoàn toàn không thấy: một key duy nhất hút phần lớn lưu lượng. Hit ratio vẫn 100%, mọi biểu đồ vẫn xanh, mà một shard Redis nóng rực còn các shard khác ngồi chơi — đo thật phân bố lệch và cách gỡ.