← Vibe coding với Next.js

Bài 8 · Vận dụng · 22 phút

Tăng tốc & chịu tải với Redis

Biên soạn bởi Nguyễn Anh Tuấn

Tối ưu hạ tầng để sản phẩm nhanh và chịu được đông người: caching với Redis. Vì sao đọc từ cache (trong bộ nhớ) nhanh hơn nhiều việc hỏi PostgreSQL mỗi lần; cache cái gì cho đáng, vòng đời cache (TTL) và làm mới khi dữ liệu đổi (invalidation); nhờ Claude Code thêm Redis vào app Next.js. Redis sẽ được script cài sẵn khi dựng VPS ở bài sau.

Sản phẩm đã biết nhớ nhờ PostgreSQL. Nhưng mỗi lần một khách mở trang sản phẩm, app lại hỏi database câu y hệt: "cho tôi danh sách hàng". Một người thì nhẹ. Một nghìn người cùng lúc hỏi đúng câu đó thì database è cổ, và trang bắt đầu chậm.

Hỏi đi hỏi lại cho cùng một câu trả lời là phí. Cách chữa: nhớ tạm câu trả lời ở một chỗ siêu nhanh, lần sau lấy luôn. Đó là caching.

Thay vì hỏi database mỗi lần, app hỏi cache trước. Khoá dùng Redis - một kho dữ liệu nằm trong bộ nhớ (RAM), nên đọc nhanh hơn hẳn việc lục ổ đĩa của database. Có sẵn thì trả ngay; chưa có thì hỏi database rồi nhớ lại cho lần sau:

RequestRedis (cache)trong bộ nhớ - rất nhanhcó sẵn (hit)⚡ Trả ngay(không đụng database)chưa có (miss)PostgreSQLổ đĩa - chậm hơnTrả & lưu cache(lần sau sẽ hit)
App hỏi Redis trước. Có sẵn (hit) thì trả ngay; chưa có (miss) thì hỏi PostgreSQL rồi lưu vào cache.

Hai từ để nhớ: hit (cache có sẵn, trả ngay) và miss (cache chưa có, phải hỏi database). Càng nhiều hit thì database càng nhàn và trang càng nhanh.

Không phải thứ gì cũng nên cache. Ứng viên tốt là dữ liệu đọc nhiều, đổi ít: danh sách sản phẩm, trang giới thiệu, giá hàng. Ngược lại, thứ nhạy cảm hoặc đổi liên tục thì đừng cache.

  • Nên cache: đọc nhiều + đổi ít (danh sách hàng, trang giới thiệu).
  • KHÔNG cache: số dư ví (đổi mỗi giao dịch, sai một nhịp là hiện sai tiền).
  • KHÔNG cache: dữ liệu riêng tư mà mỗi người một khác và hay đổi.

Trung thực

Với web bán hàng có ví, số dư là thứ tuyệt đối không cache. Khách nạp 50.000đ mà trang còn hiện số cũ vì cache trễ là mất niềm tin ngay. Số dư phải đọc thẳng từ database mỗi lần.

Cache nhanh, nhưng có một rủi ro: dữ liệu gốc đổi mà cache vẫn giữ bản cũ thì trang hiện sai. Có hai cách giữ cache tươi.

  • TTL (time to live): đặt hạn cho cache, vd 60 giây rồi tự hết - chấp nhận sai tối đa 60 giây.
  • Invalidation: chủ động xoá cache ngay khi dữ liệu gốc đổi (admin sửa giá → xoá cache sản phẩm).
  • Thường dùng cả hai: TTL làm lưới đỡ, invalidation cho cập nhật tức thì.

Trung thực

Cache sai là loại lỗi khó chịu: code không "hỏng", chỉ là hiện dữ liệu cũ, nên khó nhận ra. Khi thấy "tôi đổi rồi mà trang chưa cập nhật", nghĩ ngay tới cache. Đây là một trong vài chỗ dễ vấp nhất khi tăng tốc.

Mèo con không tự viết phần cache. Mô tả rõ là đủ, ví dụ: "cache danh sách sản phẩm bằng Redis, TTL 60 giây, và xoá cache khi admin sửa giá". Claude thêm phần đọc/ghi cache theo đúng luồng hit/miss ở trên. Đại ý cái nó dựng:

luồng cache-aside - mã giả minh hoạ (Claude viết hộ bằng code Next.js)

ds = redis.get("san_pham")          # hỏi cache trước
if ds is None:                       # miss
    ds = postgres.query("san_pham")  # hỏi database
    redis.set("san_pham", ds, ttl=60)  # nhớ lại 60 giây
return ds

Trung thực

Ở máy mình, mèo con cần một Redis đang chạy (cài trực tiếp hoặc qua Docker - cứ nhờ Claude hướng dẫn). Trên VPS thì khỏi lo: script cài đặt ở bài deploy đã dựng sẵn Redis. Redis này cũng là nền cho hàng đợi BullMQ ở bài sau.

Có cache, database bớt è cổ, trang nhanh hơn và chịu được đông khách hơn - đúng tinh thần tự chủ hạ tầng của khoá. Chỉ cần nhớ kỷ luật: cache đúng thứ, đặt TTL, và làm mới khi dữ liệu đổi.

Bước tiếp theo

Những quy ước kiểu "cache cái gì, TTL bao lâu, số dư không cache" mà phải nhắc Claude mỗi phiên thì mệt. Bài kế ta ghi chúng vào bộ nhớ dự án để AI tự bám: Dạy AI luật riêng: CLAUDE.md.

Câu hỏi thường gặp

Redis là một kho dữ liệu nằm trong bộ nhớ (RAM), nên đọc/ghi rất nhanh. Nó hay được dùng làm cache, và cũng làm hàng đợi (queue) - phần hàng đợi để bài BullMQ sau lo. Ở bài này, mèo con dùng nó như một chỗ nhớ tạm siêu nhanh.

Không. Cache chỉ giữ một bản sao tạm để trả nhanh; nguồn dữ liệu chính vẫn là database. Cache mất hay hết hạn thì app hỏi lại database rồi nhớ tạm lần nữa. Đừng bao giờ coi cache là nơi lưu trữ lâu dài.

Cache cũ làm hiện dữ liệu sai: giá đã đổi mà vẫn hiện giá cũ, hàng hết mà vẫn báo còn. Để tránh, dùng TTL (đặt hạn cho cache tự hết) và invalidation (xoá cache khi dữ liệu gốc đổi). Cache sai khá khó phát hiện, nên đây là chỗ cần cẩn thận.

Khi mèo con đo thấy trang chậm hoặc lượng khách tăng cao, không phải ngay từ ngày đầu. Thêm cache khi chưa cần là tối ưu sớm - tốn công mà chưa giải quyết vấn đề nào. Cứ ship trước, thấy nghẽn ở đâu thì cache đúng chỗ đó.

Không nên. Số dư đổi mỗi lần khách nạp hay mua; cache trễ một nhịp là hiện sai số tiền - chuyện tối kỵ. Quy tắc: thứ nhạy cảm hoặc đổi liên tục thì đọc thẳng từ database, đừng cache.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Vì sao thêm cache (Redis) giúp trang chịu tải tốt hơn?

Bài tập về nhà

  1. 1

    Phân loại nên cache hay không

    Với 6 dữ liệu (danh sách sản phẩm, số dư ví, trang giới thiệu, giá sản phẩm, đơn hàng của một khách, lượt xem trang), đánh dấu nên cache hay không và một lý do.

    ✅ Hoàn thành khi: Mỗi mục có nhãn cache/không + lý do; vd danh sách sản phẩm & trang giới thiệu = nên (đọc nhiều, đổi ít); số dư ví = không (nhạy cảm, đổi liên tục).

  2. 2

    Nhờ Claude thêm cache

    Bật plan mode, nhờ Claude cache danh sách sản phẩm bằng Redis trong 60 giây; duyệt kế hoạch rồi cho dựng.

    ✅ Hoàn thành khi: Trang /san-pham vẫn hiển thị bình thường, và Claude xác nhận danh sách được lấy từ cache khi có sẵn.

  3. 3

    Quan sát hit và miss

    Tải trang sản phẩm lần đầu (miss, lấy từ database) rồi tải lại ngay (hit, lấy từ cache); nhờ Claude in ra log "cache hit/miss" nếu cần.

    ✅ Hoàn thành khi: Bạn nhận ra lần đầu đi tới database, lần sau lấy từ Redis - đúng như sơ đồ trong bài.

  4. 4

    Đặt TTL

    Nhờ Claude đặt thời hạn (TTL) 60 giây cho cache danh sách sản phẩm.

    ✅ Hoàn thành khi: Sau 60 giây, cache tự hết và lần tải kế lấy lại từ database (Claude giải thích hoặc bạn quan sát được).

  5. 5

    Làm mới khi đổi giá

    Nhờ Claude xoá (làm mới) cache sản phẩm ngay khi admin sửa giá, thay vì chờ hết TTL.

    ✅ Hoàn thành khi: Đổi giá ở trang admin thì trang sản phẩm cập nhật giá mới gần như ngay lập tức.

  6. 6

    Vì sao không cache số dư

    Viết một câu giải thích vì sao số dư ví không nên cache.

    ✅ Hoàn thành khi: Câu nêu được: số dư đổi liên tục và nhạy cảm, cache trễ sẽ hiện sai số tiền cho khách.