Contents

Khi nào nên dùng cache (và khi nào không)

Mở đầu

Cache giống như bình giữ nhiệt trong quán cà phê: barista pha sẵn một mẻ Americano vì biết món này bán chạy nhất. Khi khách gọi, chỉ cần rót từ bình ra — nhanh, không chờ pha. Nhưng nếu chọn sai món để pha sẽ — giữ nóng một ly matcha latte mà chỉ có 1 khách gọi trong ngày — bạn tốn gas, tốn chỗ, và nước để nguội rồi bỏ đi.

Cache trong hệ thống backend cũng y hệt: dùng đúng thì performance bay lên, dùng sai thì bug nhân lên và data cũ ngày càng nhiều.

Bài này không nói về LRU, LFU hay cache eviction policy — mình sẽ nói về khi nào nên cache và khi nào không, vì đây là quyết định kiến trúc quan trọng nhất và ít người nghĩ kỹ.

https://blog-bucket.luandnh.com/images/covers/cache.jpg

Khi nào nên dùng cache

1. Đọc nhiều, ghi ít — dữ liệu “nấu chậm”

Profile user, danh mục sản phẩm, cấu hình hệ thống — những thứ ít thay đổi nhưng truy xuất liên tục. Đây là “món ăn chín” — 1 lần nấu, phục vụ nhiều lần.

GET /api/users/123 → cache hit → không cần query DB
                 → cache miss → query DB, set cache, trả về
// Pattern: cache-aside
func (s *Service) GetUser(ctx context.Context, id string) (*User, error) {
    // Check cache trước
    if data, err := s.cache.Get(ctx, "user:"+id); err == nil {
        return decodeUser(data), nil
    }

    // Cache miss → query DB
    user, err := s.db.GetUser(ctx, id)
    if err != nil {
        return nil, err
    }

    // Set cache cho lần sau
    s.cache.Set(ctx, "user:"+id, encodeUser(user), 10*time.Minute)
    return user, nil
}

2. Có điểm nóng — một bài viral, một sản phẩm best-seller

Khi 80% request chỉ hit 20% dữ liệu, cache lập tức giảm tải DB đáng kể. Đặc biệt quan trọng với những bài viết viral hoặc flash sale — nếu không cache, DB sẽ là nút thắt sớm nhất.

3. Dung sai cho dữ liệu cũ trong vài giây

Số lượng like, view count, ranking — nếu số liệu lệch 2-3 giây, user không nhận ra và không quan trọng. Nhưng nếu phải COUNT(*) mỗi lần user refresh, DB sẽ khóc.

4. Tính phức tạp để tính toán

Aggregation query, report, dashboard — những câu query mất 5-10 giây để chạy. Cache kết quả và refresh định kỳ thay vì chạy real-time mỗi request.

Khi nào KHÔNG nên cache

1. Dữ liệu biến động liên tục

Số dư tài khoản, trạng thái đơn hàng real-time, inventory — cache ở đây là thảm họa. User thấy số dư sai, mua hàng bị hết stock. Lúc này, đọc trực tiếp từ DB (hoặc event-driven update) an toàn hơn.

2. Cardinality quá cao — số key khổng lồ

Nếu bạn cache theo kết hợp nhiều filter:

❌ cache_key = "products:c=tea&p_min=20&p_max=50&sort=price&page=3&limit=20"

Số key có thể lên đến hàng triệu, cache miss liên tục, và chi phí duy trì cache cao hơn chi phí query DB.

✅ Cache ở mức cao hơn: "products:popular" → filter/sort/page ở app layer

3. Upstream đã đủ nhanh

Nếu query DB trả về trong 2ms với index đúng, thêm cache chỉ tạo thêm complexity và potential bug. Đừng optimize cái không cần optimize.

4. Không có chiến lược invalidation

Nếu bạn không biết khi nàocách nào để xóa cache khi data thay đổi, cache sẽ giữ dữ liệu cũ mãi mãi. User thấy thông tin sai → tệ hơn là không cache.

Chiến lược invalidation

Strategy Ưu điểm Nhược điểm
TTL (Time-To-Live) Đơn giản Dữ liệu cũ trong khi TTL chưa hết
Write-through Cache và DB luôn sync Write chậm hơn
Write-behind Write nhanh Rủi ro mất dữ liệu nếu cache fail
Event-driven Chính xác nhất Phức tạp nhất
// Write-through pattern
func (s *Service) UpdateProduct(ctx context.Context, p *Product) error {
    if err := s.db.Update(ctx, p); err != nil {
        return err
    }
    // Invalidate cache
    s.cache.Delete(ctx, "product:"+p.ID)
    s.cache.Delete(ctx, "products:popular") // invalidate list cache
    return nil
}

Tóm tắt

✅ Nên cache ❌ Không nên cache
Read/Write ratio Đọc nhiều, ghi ít Ghi nhiều, đọc ít
Consistency Chấp nhận dữ liệu cũ OK Cần realtime, không chấp nhận sai lệch
Complexity Lợi ích > chi phí maintain Quá phức tạp, DB đủ nhanh
Invalidation Chiến lược rõ ràng Không biết khi nào xóa

“Cache giống như bình giữ nhiệt — hữu ích khi biết thứ bên trong, lâu dài sẽ ửng hết hạn.”


Bạn đã từng gặp bug do cache chưa? Chia sẻ bên dưới để mình cùng học nhé! 🍵