Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Redis và Key-Value: caching layer

API and Technical Fundamentals cho BA Bài 34/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là BA của một sàn thương mại điện tử Việt Nam. Mỗi ngày trang chủ có hàng triệu lượt truy cập, và mỗi lần khách mở app, hệ thống lại phải hỏi cùng một câu: "Top 10 sản phẩm bán chạy hôm nay là gì?". Nếu mỗi lần đều chạy một câu truy vấn nặng vào database chính, máy chủ sẽ sớm quá tải. Câu hỏi tự nhiên đặt ra là: tại sao phải tính lại một thứ vừa mới tính cách đây một giây? Đây chính là vấn đề mà Redis và các key-value store sinh ra để giải quyết.

Là BA kỹ thuật, bạn sẽ không trực tiếp viết code cấu hình Redis, nhưng bạn sẽ liên tục gặp nó trong các cuộc họp thiết kế. Khi đội kỹ thuật nói "cái này mình cache vào Redis", "session lưu ở Redis", hay "dùng Redis để chống spam đặt hàng" — bạn cần hiểu họ đang nói gì, đánh đổi gì, và rủi ro nghiệp vụ là gì. Hiểu Redis giúp bạn viết yêu cầu chính xác hơn, đặt câu hỏi đúng chỗ, và đánh giá được khi nào một tính năng "chậm" là do thiết kế dữ liệu chứ không phải do thiếu máy chủ.

Bài này tập trung vào Redis như một caching layer (lớp đệm bộ nhớ) và mô hình key-value — một mảnh ghép quan trọng trong bức tranh kiến trúc hệ thống mà BA cần nắm.

Khái niệm cốt lõi

Redis là gì?

Redis (Remote Dictionary Server) là một in-memory key-value store — kho lưu trữ dữ liệu theo cặp khóa–giá trị, hoạt động chủ yếu trong bộ nhớ RAM thay vì trên ổ đĩa. Đặc điểm này tạo nên sức mạnh cốt lõi của nó: tốc độ truy xuất tính bằng micro-giây (phần triệu của giây), nhanh hơn database truyền thống đọc từ ổ đĩa hàng trăm đến hàng nghìn lần.

Hãy hình dung sự khác biệt bằng một phép so sánh đời thường. Database trên ổ đĩa giống như một thư viện lớn: muốn tìm một cuốn sách, thủ thư phải đi vào kho, dò theo mã số, lấy ra rồi mang về. Redis giống như tập giấy nhớ dán ngay trên bàn làm việc: với tay là lấy được ngay. Tốc độ chênh nhau đến từ chỗ một bên đọc RAM, một bên đọc đĩa.

Mô hình key-value là gì?

Key-value là mô hình dữ liệu đơn giản nhất có thể: mỗi mẩu dữ liệu được lưu dưới dạng một khóa (key) duy nhất ánh xạ tới một giá trị (value). Giống một cuốn từ điển: tra từ "apple" ra nghĩa "quả táo". Ở Redis, key có thể là user:1024:cart, value là nội dung giỏ hàng của người dùng đó.

Khác với database quan hệ (SQL) có bảng, cột, quan hệ giữa các bảng, key-value không có cấu trúc bảng. Bạn không thể hỏi "tìm tất cả user có tuổi trên 30" một cách tự nhiên, vì Redis không hiểu bên trong value có gì — nó chỉ biết khóa nào ứng với giá trị nào. Đổi lại, vì cực kỳ đơn giản nên nó cực kỳ nhanh.

Tuy gọi là "key-value", Redis thực ra hỗ trợ nhiều kiểu dữ liệu phong phú cho phần value: chuỗi (string), danh sách (list), tập hợp (set), tập hợp có xếp hạng (sorted set), bảng băm (hash). Chính sự đa dạng này khiến Redis làm được nhiều việc hơn một cache thông thường.

Vì sao "in-memory" vừa là điểm mạnh vừa là điểm yếu?

Dữ liệu nằm trong RAM nên đọc/ghi cực nhanh, nhưng RAM là bộ nhớ bay hơi (volatile): mất điện hay restart là dữ liệu biến mất. Redis có cơ chế persistence (lưu bền) tùy chọn — RDB (chụp ảnh dữ liệu định kỳ) và AOF (ghi nhật ký từng thao tác) — để khôi phục sau khi khởi động lại. Nhưng điểm mấu chốt BA cần nhớ: persistence ở Redis là tùy chọn và không phải nguồn dữ liệu chính. Bạn không bao giờ nên coi Redis là nơi lưu trữ duy nhất cho dữ liệu quan trọng như đơn hàng hay giao dịch. Nó là lớp đệm, không phải két sắt.

TTL — vòng đời của một bản ghi cache

Một khái niệm sống còn của caching là TTL (Time To Live) — thời gian sống của một key. Bạn có thể đặt cho key "danh sách sản phẩm hot" một TTL là 60 giây; sau 60 giây Redis tự động xóa nó. Lần truy cập tiếp theo sẽ tính lại dữ liệu mới và lưu lại. TTL chính là cách bạn cân bằng giữa tốc độ (cache càng lâu càng nhanh) và độ tươi của dữ liệu (cache càng lâu càng dễ lỗi thời). Là BA, khi viết yêu cầu cho một màn hình, một trong những câu hỏi giá trị nhất bạn có thể đặt là: "Dữ liệu này được phép cũ tối đa bao lâu?". Câu trả lời sẽ định ra TTL.

Các use case phổ biến của Redis

  • Cache giảm tải database — tình huống kinh điển: lưu kết quả truy vấn nặng để lần sau lấy ngay, giảm áp lực lên DB chính.
  • Lưu session người dùng — khi bạn đăng nhập, "phiên" của bạn (đã login, giỏ hàng, ngôn ngữ) thường được lưu ở Redis để mọi máy chủ đều truy cập nhanh và đồng nhất.
  • Rate limiting / chống lạm dụng — đếm số lần một IP gọi API trong 1 phút, nhờ tốc độ ghi cực nhanh của Redis.
  • Leaderboard / bảng xếp hạng — nhờ kiểu sorted set, Redis xếp hạng top người chơi, top sản phẩm theo thời gian thực rất hiệu quả.
  • Hàng đợi tạm / khóa phân tán — điều phối tác vụ giữa nhiều máy chủ.
Trong khuôn khổ bài này, ta đào sâu nhất vào use case số 1 — Redis như một caching layer — vì đây là nơi BA gặp nhiều nhất.

Cache hit, cache miss và cache-aside

Khi ứng dụng cần một dữ liệu, nó hỏi Redis trước. Nếu Redis có (gọi là cache hit), trả về ngay — rất nhanh. Nếu Redis không có (gọi là cache miss), ứng dụng phải vào database lấy, rồi ghi kết quả vào Redis cho lần sau, rồi mới trả về. Mô hình "hỏi cache trước, miss thì vào DB rồi nạp lại cache" này gọi là cache-aside, là kiểu cache phổ biến nhất bạn sẽ gặp. Một chỉ số bạn nên biết để đánh giá hiệu quả cache là cache hit ratio — tỉ lệ phần trăm lượt truy cập trúng cache. Hit ratio 95% nghĩa là 95% yêu cầu được phục vụ từ RAM siêu nhanh, chỉ 5% phải xuống DB.

Tình huống thực tế

Ví dụ 1: Sàn TMĐT giảm tải trang chủ trong dịp sale

Một sàn thương mại điện tử giả định tên ShopViet gặp sự cố trong đợt sale 12/12. Trang chủ hiển thị khối "Top 20 sản phẩm bán chạy", được tính bằng một câu truy vấn tổng hợp doanh số khá nặng, mất khoảng 800ms mỗi lần. Vào giờ cao điểm, trang chủ có 5.000 lượt truy cập mỗi giây. Nghĩa là database phải chạy câu truy vấn nặng đó 5.000 lần/giây — nó gục ngã, trang chủ load mất 8–10 giây, khách bỏ đi.

Đội kỹ thuật đưa Redis vào theo mô hình cache-aside: kết quả "Top 20" được lưu vào key homepage:top20 với TTL 30 giây. Bây giờ trong 30 giây, dù có 150.000 lượt truy cập, database chỉ phải tính một lần duy nhất; 149.999 lượt còn lại được phục vụ từ Redis trong khoảng 1ms. Trang chủ load trở lại dưới 1 giây.

Diễn giải dưới góc BA: Khi đội kỹ thuật đề xuất TTL 30 giây, BA cần đặt câu hỏi nghiệp vụ: "Bảng xếp hạng bán chạy chậm 30 giây so với thực tế có chấp nhận được với marketing không?". Ở đây câu trả lời là có — không ai phàn nàn nếu top sản phẩm cập nhật trễ nửa phút. Nhưng nếu đây là số lượng tồn kho còn lại thì 30 giây có thể gây oversell (bán quá số hàng). Cùng một kỹ thuật, TTL phù hợp lại khác nhau tùy ngữ cảnh nghiệp vụ.

Bài học rút ra: Cache không phải quyết định kỹ thuật thuần túy. Việc dữ liệu được phép "cũ" bao lâu là một quyết định nghiệp vụ, và BA là người trả lời chính xác nhất.

Ví dụ 2: Ứng dụng gọi xe và bài toán session đăng nhập

Một ứng dụng gọi xe ở Đông Nam Á (giả định tên GoRide) chạy trên nhiều máy chủ phía sau load balancer. Khi tài xế đăng nhập, request đầu tiên rơi vào máy chủ A, request tiếp theo có thể rơi vào máy chủ B. Nếu thông tin phiên đăng nhập chỉ lưu trong bộ nhớ của máy chủ A, thì khi sang máy chủ B, tài xế bị coi như chưa đăng nhập — văng ra liên tục.

Giải pháp: lưu session ở Redis dùng chung, key dạng session:abc123 chứa thông tin tài xế, TTL 24 giờ (tự gia hạn mỗi lần hoạt động). Mọi máy chủ đều đọc cùng một nguồn session từ Redis, nên tài xế đăng nhập một lần là dùng được liền mạch trên toàn hệ thống.

Diễn giải dưới góc BA: Khi viết yêu cầu cho tính năng "tự động đăng xuất sau 24 giờ không hoạt động", BA cần hiểu cơ chế TTL đứng sau nó. Quyết định "24 giờ" là yêu cầu nghiệp vụ về bảo mật và trải nghiệm; "TTL có tự gia hạn mỗi lần hoạt động không" cũng là một quyết định nghiệp vụ (sliding expiration). Hai dòng yêu cầu này, nếu BA viết rõ, sẽ tránh được những hiểu lầm tốn kém khi triển khai.

Bài học rút ra: Trong hệ thống nhiều máy chủ, Redis thường là nơi giữ "trạng thái dùng chung". BA hiểu điều này sẽ viết được yêu cầu về phiên, đăng xuất, hết hạn một cách chính xác.

Ví dụ 3: Ngân hàng số chống spam OTP

Một ngân hàng số (giả định tên VietDigiBank) gặp tình trạng kẻ xấu gọi liên tục API gửi OTP để quấy rối khách hàng và tốn phí SMS (mỗi tin nhắn tốn khoảng 300–800 đồng). Đội kỹ thuật dùng Redis để rate limit: với mỗi số điện thoại, tạo key otp:limit:0909xxxxxx đếm số lần yêu cầu, đặt TTL 60 giây. Nếu trong 60 giây vượt quá 3 lần, hệ thống từ chối. Nhờ tốc độ của Redis, việc kiểm tra này thêm chưa tới 1ms vào mỗi request, không ảnh hưởng trải nghiệm.

Diễn giải dưới góc BA: Con số "3 lần trong 60 giây" không phải do kỹ thuật tự nghĩ ra — nó là quy tắc nghiệp vụ mà BA phải định nghĩa, cân bằng giữa chống lạm dụng và không gây phiền cho khách thật (ví dụ người dùng không nhận được OTP nên bấm gửi lại). BA cũng cần định nghĩa thông điệp lỗi hiển thị khi bị chặn: "Bạn đã yêu cầu OTP quá nhiều lần, vui lòng thử lại sau 1 phút."

Bài học rút ra: Redis làm cho rate limiting khả thi về mặt kỹ thuật, nhưng ngưỡnghành vi khi chạm ngưỡng là yêu cầu nghiệp vụ thuần túy — đúng phần việc của BA.

Hướng dẫn từng bước

Đây là quy trình tư duy giúp BA tham gia hiệu quả khi hệ thống cân nhắc đưa Redis vào.

  • Xác định "điểm nóng" hiệu năng. Lắng nghe trong các cuộc họp xem màn hình/API nào chậm và được gọi nhiều. Cache chỉ đáng dùng cho dữ liệu được đọc nhiều, tính lại tốn kém, và ít thay đổi. Một dữ liệu chỉ đọc một lần thì cache vô nghĩa.
  • Hỏi câu hỏi vàng về độ tươi. Với mỗi dữ liệu định cache, hỏi: "Dữ liệu này được phép cũ tối đa bao lâu mà không gây vấn đề nghiệp vụ?". Câu trả lời định ra TTL. Ghi nó vào tài liệu yêu cầu một cách tường minh.
  • Phân loại dữ liệu theo mức độ nhạy cảm. Dữ liệu danh mục sản phẩm cũ vài phút thì không sao; số dư tài khoản hay tồn kho thì gần như không được cache, hoặc cache rất ngắn. Lập một bảng nhỏ: tên dữ liệu — TTL đề xuất — hậu quả nếu hiển thị dữ liệu cũ.
  • Làm rõ chiến lược cập nhật cache. Khi dữ liệu gốc thay đổi (ví dụ admin sửa giá sản phẩm), cache phải được xử lý ra sao? Chờ TTL hết hạn (đơn giản nhưng có độ trễ) hay chủ động xóa cache ngay (invalidation)? Đây là quyết định ảnh hưởng trực tiếp trải nghiệm — BA cần nêu rõ kỳ vọng.
  • Định nghĩa hành vi khi cache "không có" hoặc Redis sập. Hệ thống phải vẫn chạy được (chậm hơn) khi Redis gặp sự cố, chứ không được trắng màn hình. BA nên ghi yêu cầu: "Nếu cache không khả dụng, hệ thống lấy dữ liệu trực tiếp từ nguồn chính."
  • Viết yêu cầu rate limit / session rõ ràng nếu liên quan. Nêu ngưỡng, cửa sổ thời gian, thông điệp lỗi, và hành vi hết hạn.
  • Thống nhất chỉ số đo lường. Đề nghị đội kỹ thuật theo dõi cache hit ratio và thời gian phản hồi trước/sau khi áp dụng, để chứng minh giá trị tính năng cho stakeholder.

Lỗi thường gặp & mẹo

Lỗi 1: Coi Redis là database chính. Vì Redis lưu trong RAM và có thể mất dữ liệu, đừng bao giờ để đơn hàng hay giao dịch chỉ tồn tại ở Redis. Mẹo: trong tài liệu, luôn nói rõ "nguồn sự thật" (source of truth) là database chính, Redis chỉ là bản sao tăng tốc.

Lỗi 2: Quên xử lý dữ liệu lỗi thời (stale data). BA mô tả màn hình hiển thị giá, kỹ thuật cache 1 giờ, kết quả khách thấy giá cũ sau khi admin đã đổi giá. Mẹo: với dữ liệu nhạy cảm về độ chính xác, hãy yêu cầu cơ chế xóa cache chủ động khi dữ liệu gốc đổi, đừng chỉ dựa vào TTL.

Lỗi 3: Đặt TTL theo cảm tính. TTL quá ngắn thì cache vô dụng (luôn miss), quá dài thì dữ liệu cũ. Mẹo: gắn TTL với nhịp thay đổi thực tế của dữ liệu — danh mục đổi vài lần/ngày thì TTL vài phút là hợp lý.

Lỗi 4: Bỏ qua "cache stampede". Khi một key hot hết hạn đúng lúc cao điểm, hàng nghìn request cùng miss và đồng loạt đập vào DB, gây sập. Mẹo: BA không cần giải kỹ thuật, nhưng nên nêu rủi ro này để đội kỹ thuật áp dụng giải pháp (như khóa nạp lại, hoặc TTL ngẫu nhiên hóa nhẹ).

Lỗi 5: Cache cả dữ liệu cá nhân hóa mà không phân biệt. Cache nhầm giỏ hàng người này hiển thị cho người khác là thảm họa bảo mật. Mẹo: luôn xác định key có yếu tố định danh người dùng (ví dụ cart:user:1024) khi dữ liệu mang tính cá nhân.

Mẹo chung cho BA: Khi nghe "mình cache cái này", phản xạ tốt là hỏi ba câu — Cũ bao lâu thì chấp nhận được? Khi dữ liệu gốc đổi thì xử lý sao? Nếu Redis sập thì điều gì xảy ra? Ba câu này phủ phần lớn rủi ro nghiệp vụ của caching.

Bài tập thực hành

Bài 1 — Lập bảng quyết định cache. Cho một app đặt vé xem phim, hãy liệt kê 5 loại dữ liệu (ví dụ: danh sách phim đang chiếu, sơ đồ ghế còn trống, thông tin tài khoản người dùng, giá vé, lịch sử đặt vé). Với mỗi loại, điền: có nên cache không, TTL đề xuất, và hậu quả nếu hiển thị dữ liệu cũ. Chú ý loại nào tuyệt đối không nên cache lâu (gợi ý: ghế còn trống).

Bài 2 — Viết yêu cầu rate limit. Viết một đoạn yêu cầu nghiệp vụ hoàn chỉnh cho tính năng "giới hạn số lần gửi lại email khôi phục mật khẩu", bao gồm: ngưỡng, cửa sổ thời gian, thông điệp khi bị chặn, và hành vi sau khi cửa sổ hết hạn.

Bài 3 — Phân tích sự cố. Một stakeholder báo: "Khách phản ánh sau khi mình giảm giá sản phẩm, app vẫn hiển thị giá cũ suốt cả tiếng." Hãy chẩn đoán nguyên nhân liên quan đến cache, và đề xuất hai cách khắc phục (một dựa vào TTL, một dựa vào xóa cache chủ động). Nêu ưu nhược điểm mỗi cách.

Bài 4 — Đặt câu hỏi đúng. Đội kỹ thuật nói: "Tụi mình sẽ lưu giỏ hàng vào Redis cho nhanh." Hãy viết ra 5 câu hỏi bạn — với vai trò BA — cần hỏi để đảm bảo không phát sinh rủi ro nghiệp vụ (gợi ý: điều gì xảy ra nếu Redis sập và giỏ hàng biến mất?).

Tóm tắt

Redis là một in-memory key-value store cực nhanh, mạnh nhất khi đóng vai caching layer giúp giảm tải database và tăng tốc hệ thống. Mô hình key-value đơn giản (khóa ánh xạ tới giá trị) đánh đổi khả năng truy vấn phức tạp để lấy tốc độ micro-giây. Vì dữ liệu nằm trong RAM, Redis không bao giờ nên là nguồn sự thật duy nhất cho dữ liệu quan trọng — nó là lớp đệm, không phải két sắt.

Khái niệm quan trọng nhất với BA là TTL và quyết định "dữ liệu được phép cũ bao lâu" — đây là một quyết định nghiệp vụ, không phải kỹ thuật. Qua ba tình huống (sàn TMĐT giảm tải trang chủ, app gọi xe lưu session dùng chung, ngân hàng số chống spam OTP), ta thấy cùng một công cụ Redis nhưng TTL và ngưỡng luôn phải bắt nguồn từ ngữ cảnh nghiệp vụ.

Vai trò của BA không phải cấu hình Redis, mà là đặt đúng câu hỏi: dữ liệu cũ bao lâu thì chấp nhận được, cập nhật cache thế nào khi dữ liệu gốc đổi, và hệ thống ứng xử ra sao khi cache không khả dụng. Nắm vững ba câu hỏi này, bạn sẽ viết yêu cầu chính xác hơn và trở thành cầu nối đáng tin giữa nghiệp vụ và kỹ thuật.