0

Vứt Bỏ JSON.stringify: Khai Mở Sức Mạnh 5 Cấu Trúc Dữ Liệu Của Redis

Ở bài trước về Redis, chúng ta đã đàm đạo về khái niệm In-Memory và thảm họa Cache Stampede. Nhưng có một sự thật phũ phàng: 90% anh em dev khi mới xài Redis chỉ biết dùng đúng 2 lệnh SETGET.

Bất cứ dữ liệu gì (từ một con số, một chuỗi, cho đến một Object to đùng hay một mảng danh sách), các bạn đều dùng lệnh JSON.stringify() ở Node.js để biến nó thành chuỗi, rồi nhét hết vào lệnh SET của Redis. Đó là một sự lãng phí tài nguyên khủng khiếp! Redis không chỉ là một cái kho gửi đồ (Key-Value thuần túy). Tên gọi đầy đủ của nó là REmote DIctionary Server, một máy chủ chứa các Cấu trúc dữ liệu (Data Structures). Dưới đây là bài viết khai mở sức mạnh thực sự của Redis!

Hãy tưởng tượng bạn đang làm hệ thống Giỏ hàng (Cart) cho Shopee. Mỗi user có một giỏ hàng chứa nhiều sản phẩm.

Với tư duy "Thợ gõ", bạn sẽ lấy toàn bộ giỏ hàng từ Database, convert thành chuỗi JSON, rồi lưu vào Redis bằng lệnh: SET cart:user_123 '{"item1": 2, "item2": 5}' Một lúc sau, user bấm nút "+" để tăng số lượng item1 lên 3. App của bạn phải:

  1. GET cart:user_123 (Kéo toàn bộ chuỗi JSON về Node.js).
  2. JSON.parse() (Giải mã ra Object).
  3. Update số lượng item1 = 3.
  4. JSON.stringify() (Gói lại thành chuỗi).
  5. SET cart:user_123 (Đẩy ngược lên Redis).

Vòng lặp này tốn CPU, tốn băng thông mạng và cực kỳ dễ sinh ra lỗi Race Condition (2 người cùng thao tác lúc). Một Vibe Coder không làm thế, vì họ biết Redis có Cấu trúc dữ liệu. Hãy cùng lướt qua 5 vũ khí tối thượng của Redis.

1. Strings (Chuỗi) - Kẻ Đếm Số Nguyên Tử

Dù tên là String, nhưng nếu bạn nhét vào một con số, Redis sẽ hiểu và cho phép bạn làm toán trực tiếp trên RAM.

Tuyệt kỹ lớn nhất của String không phải là lưu JSON, mà là lệnh INCR (Increment - Tăng lên 1).

Bạn muốn đếm số lượt xem bài viết? Không cần lôi số cũ về cộng, chỉ cần gọi: INCR views:post_100 Redis sẽ tự động tăng số đó lên 1 một cách Atomic (Nguyên tử) - tức là dù có 10.000 người click cùng một mili-giây, con số vẫn đúng tuyệt đối, không bao giờ bị dẫm đạp!

2. Hashes (Bảng Băm) - Cứu Tinh Của Object

Quay lại bài toán Giỏ hàng ở đầu bài. Thay vì lưu cả cục JSON, ta lưu bằng cấu trúc Hash (Giống y hệt Object trong JS).

Lệnh lưu: HSET cart:user_123 item1 2 item2 5

Khi user tăng item1 thêm 1 cái? Bạn không cần kéo nguyên cái giỏ hàng về nữa, chỉ cần ra lệnh cho Redis tự cộng vào đúng cái field đó:

HINCRBY cart:user_123 item1 1

Xong! Tốc độ ánh sáng, an toàn tuyệt đối, tiết kiệm RAM.

3. Lists (Danh sách liên kết) - Trùm Làm Hàng Đợi

List trong Redis bản chất là Danh sách liên kết kép (Doubly Linked List). Nghĩa là việc chèn vào đầu hoặc cuối list là cực kỳ nhanh O(1), dù list có 10 triệu phần tử.

Ứng dụng thực tế: Làm hệ thống Hàng đợi (Message Queue) đơn giản hoặc Lịch sử hoạt động (Activity Stream).

  • Thêm log mới vào đầu danh sách: LPUSH user:123:logs "Đăng nhập lúc 9h"
  • Giới hạn danh sách chỉ giữ lại 50 log mới nhất (Cắt bỏ phần đuôi):

Không cần Database, bạn có một hệ thống lịch sử realtime chạy siêu mượt.

4. Sets (Tập hợp vô hướng) - Vua Lọc Trùng Lặp

Set là một cái rổ chứa các phần tử không có thứ tự và KHÔNG BAO GIỜ TRÙNG NHAU.

Ứng dụng thực tế: Tính năng "Like" bài viết. Mỗi khi user 99 bấm like post 1, ta nhét ID của user vào Set: SADD post:1:likes 99 Nếu user 99 rảnh rỗi bấm like 1000 lần, Set vẫn chỉ có một số 99. Muốn biết post này có bao nhiêu like? Gọi SCARD post:1:likes. Vừa nhanh vừa chống spam triệt để.

5. Sorted Sets (ZSET) - Trùm Cuối Bảng Xếp Hạng

Đây là cấu trúc "đắt giá" nhất của Redis. Nó giống như Set (không trùng lặp), nhưng mỗi phần tử được gắn thêm một con số gọi là Score (Điểm số). Redis sẽ tự động sắp xếp các phần tử theo Điểm số này.

Ứng dụng thực tế: Leaderboard (Bảng xếp hạng Game) hoặc Top Trending.

  • User HOàng được 500 điểm: ZADD game:leaderboard 500 "HOàng"
  • User Hoàng1 được 800 điểm: ZADD game:leaderboard 800 "Hoàng1"
  • Lấy Top 10 người điểm cao nhất: ZREVRANGE game:leaderboard 0 9 WITHSCORES

Database truyền thống phải chạy lệnh ORDER BY score DESC cực kỳ nặng nề. ZSET của Redis thì khác, nó đã duy trì sẵn thứ tự đó trên RAM rồi. Gọi là có ngay!

Lời kết

Việc cứ "nhắm mắt" JSON.stringify để lưu mọi thứ vào Redis cũng giống như việc bạn mua một chiếc siêu xe Ferrari chỉ để đi siêu thị mua rau vậy. Hiểu và sử dụng đúng cấu trúc dữ liệu của Redis (đặc biệt là Hashes và ZSET) sẽ giúp hệ thống của bạn không những nhanh, mà còn giải quyết được những bài toán phức tạp (như đếm số lượng, xếp hạng, chống spam) một cách thanh lịch và ít code nhất.

Chủ đề tiếp theo: Vũ Khí Chống Spam - Rate Limiting Bằng Redis (Sliding Window)

Chúng ta đã bàn về ZSET và sự đa năng của Redis. Nhưng có một kịch bản mà mọi Public API đều phải đối mặt: Bị Bot spam.

Nếu một user gọi API Đăng nhập 1000 lần/giây để Brute-force dò mật khẩu, hệ thống của bạn sẽ sập. Làm sao để xây dựng một bộ đếm (Rate Limiter) báo lỗi 429 Too Many Requests nếu một IP gọi quá 10 lần trong vòng 1 phút?

Có nhiều thuật toán, nhưng Sliding Window Log (Cửa sổ trượt) sử dụng chính sức mạnh của Redis ZSET là một trong những giải pháp tối ưu và chính xác nhất. Ở bài viết tới, chúng ta sẽ bắt tay vào viết một Middleware Rate Limiting thực chiến chuẩn Enterprise nhé! Đón đọc!


All Rights Reserved

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