+3

Sliding Expiration: Nghệ Thuật "Gia Hạn Trượt" & Lệnh GETEX Thần Thánh Của Redis

Ý tưởng "cứ User còn gọi thì Key còn sống" là một kỹ thuật cực kỳ nổi tiếng trong giới System Design. Nếu ở bài trước, chúng ta học các "ép Key phải chết" để bảo vệ Database, thì hôm nay chúng ta sẽ học nghệ thuật "giữ Key sống dai dẳng" một cách có chủ đích.

Chào mừng bạn đến với kỹ thuật Sliding Expiration (Gia hạn trượt)!

PHẦN 1: BẢN CHẤT CỦA GIA HẠN TRƯỢT LÀ GÌ?

Hãy tưởng tượng bạn bước vào cái toilet công cộng xịn sò có đèn cảm ứng chuyển động.

Cái đèn được cài đặt: Sáng trong vòng 3 phút.

  • Nếu bạn đứng im như tượng trong 3 phút -> Đèn tắt cái rụp! Tối thui. (Đây gọi là Absolute Expiration - Hết hạn tuyệt đối)
  • Nhưng thực tế, bạn đang cựa quậy, rửa tay. Cứ mỗi lần bạn cử động, bộ cảm biến lại reset cái đồng hồ về lại mốc 3 phút ban đầu . Chỉ khi nào bạn rời đi, phòng không có ai trong đúng 3 phút liên tục, đèn mới tắt. (Đây chính là Sliding Expiration - Gia hạn trượt)

Trong Redis, Sliding Expiration có nghĩa là: Mỗi khi một Key được truy cập (đọc/ghi), thời gian sống (TTL) của nó sẽ tự động được cộng đầy lại.

Từ Cực Hình Đến Lệnh GETEX Thần Thánh (Redis 6.2+)

Ngày xưa (trước bản 6.2), để làm được trò này, anh em dev phải gõ 2 lệnh rời rạc:

const data = await redis.get('session:123'); // Lấy data
if (data) {
    await redis.expire('session:123', 1800); // Set lại 30 phút
}

Nhược điểm: Tốn 2 lần kết nối mạng (Network roundtrip), vừa chậm vừa dễ lỗi.

Từ bản Redis 6.2, các pháp sư đã ban tặng lệnh GETEX (Get and Expire). Lấy data và gia hạn trong ĐÚNG 1 NHỊP (Atomic):

// Lấy data và tự động reset TTL về 1800 giây
const data = await redis.getex('session:123', 'EX', 1800);

Ngắn gọn, thanh lịch, chuẩn Vibe Coder!

PHẦN 2: TRẢI NGHIỆM TRỰC QUAN - ABSOLUTE VS SLIDING

Để não bộ "ngấm" sâu sự khác biệt giữa hai cơ chế đếm ngược này, mời bạn xem demo bên dưới nhé

image.png

image.png

Truy cập (GET) Absolute Cache thì Absolute Expiration (gia hạn tuyệt đối vẫn hết hạn)

image.png

Truy cập (GET) Sliding Cache thì thì nó gia hạn lại Sliding Expiration

image.png

PHẦN 3: "VÙNG ĐẤT THÁNH" CỦA SLIDING EXPIRATION

Kỹ thuật này sinh ra không phải để dùng bừa bãi. Nó là "Tiêu chuẩn vàng" cho 2 kịch bản sau:

1. Quản lý Session (Phiên đăng nhập)

Bạn đăng nhập vào trang web ngân hàng. App cấp cho bạn cái Session sống 15 phút.

Nếu dùng Absolute (Tuyệt đối): Đang cặm cụi chuyển tiền, đúng phút 15, nó văng ra bắt đăng nhập lại. Cực kỳ ức chế!

Dùng Sliding: Cứ mỗi lần bạn click xem số dư, click chuyển tiền, thời gian lại được reset thành 15 phút. Bạn chỉ bị văng nếu treo máy đi pha cà phê quá 15 phút. Hoàn hảo cho User Experience (Trải nghiệm người dùng)!

2. Shopping Cart (Giỏ hàng tạm thời của khách vãng lai)

Khách chưa đăng nhập nhưng cứ chọn đồ bỏ vào giỏ. Bạn lưu giỏ hàng vào Redis với TTL 7 ngày. Nếu ngày thứ 6 khách quay lại thêm 1 cái áo vào giỏ, bạn GETEX để cộng thêm 7 ngày nữa. Giỏ hàng sẽ không bao giờ bị mất miễn là khách còn quan tâm đến shop của bạn.

PHẦN 4: TỬ HUYỆT "DỮ LIỆU ÔI THIU" (STALE DATA)

Quay lại với bài toán "Bài báo Hot Key" ở bài viết trước. Tại sao không được xài Sliding cho bài báo hay thông tin sản phẩm?

Hãy tưởng tượng:

  1. Giá gốc của iPhone là 30 triệu. Bạn Cache vào Redis (TTL 1 giờ).
  2. Lên TV, sếp tuyến bố Flash Sale giảm còn 25 triệu. Admin lao vào MySQL sửa giá thành 25 triệu.
  3. Nhưng vì đang có 10.000 người dùng liên tục F5 trang web, kỹ thuật Sliding liên tục cộng thêm 1 giờ cho cái Cache cũ trên Redis.
  4. Kết quả: Cái Cache chứa giá 30 triệu trở nên BẤT TỬ. Nó mắc kẹt trên RAM và không bao giờ chết để nhường chỗ cho dữ liệu mới.

Đó gọi là thảm họa Stale Data (Dữ liệu ôi thiu). Database một đằng, Cache hiển thị một nẻo. Khách hàng chửi rủa vì không mua được giá 25 triệu.

Nguyên tắc của Vibe Coder: * Dữ liệu tĩnh (Tên, Giá, Nội dung bài viết) -> Tuyệt đối dùng Absolute Expiration + Mutex Lock.

Lời kết Viết code lưu Cache thì dễ, nhưng quyết định xem cái Cache đó sống theo kiểu "Đèn đường" (đến giờ là tắt) hay "Đèn cảm ứng" (còn người là còn sáng) lại là thứ phân định đẳng cấp kiến trúc sư. Hãy dùng đúng vũ khí cho đúng chiến trường!

Chủ đề tiếp theo: Token vs Session - Cuộc Chiến Xác Thực Đẫm Máu

Chúng ta đã nói rất nhiều về Session và Sliding Expiration. Nhưng trong thế giới API hiện đại (Node.js/React/Mobile), người ta lại tung hô JWT (JSON Web Token) và bài xích Session.

Người ta bảo JWT "Stateless", không cần lưu ở Database, không tốn RAM. Nghe như ma thuật vậy! Nhưng sự thật thì sao? Lỡ bị lộ JWT thì làm sao để "Đá" thằng Hacker văng ra khỏi hệ thống khi mà JWT không nằm trên Database?

Ở bài viết tới, chúng ta sẽ bóc trần sự thật về JWT, Refresh Token và tại sao đôi khi Session kiểu cũ kết hợp Redis lại bảo mật hơn vạn lần! Anh em chuẩn bị tinh thần nhé!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.