Lists trong Redis: Queue, Stack và nhiều hơn nữa

Photo of author

Văn Ngọc Tân

Lists trong Redis là một tập hợp các giá trị có thứ tự, được sắp xếp theo thứ tự thêm vào. Đây là cấu trúc dữ liệu lý tưởng cho queue, stack, và activity feeds.

Lists là gì?

Redis List giống như một LinkedList — mỗi phần tử có link đến phần tử trước và sau. Điều này giúp:

  • ✅ Thêm/xóa ở đầu hoặc cuối: O(1) — siêu nhanh
  • ✅ Lấy phạm vi phần tử: O(S+N)
  • ❌ Tìm kiếm phần tử: O(N) — chậm

Các lệnh cơ bản

Lệnh Độ phức tạp Ghi chú
LPUSH / RPUSH / LPOP / RPOP O(1) Thao tác ở đầu/cuối list
LLEN O(1) Đếm số phần tử
LINDEX O(N) Truy cập theo index — tránh dùng trên list dài
LINSERT O(N) Chèn phần tử — phải duyệt list
LRANGE O(S+N) S=start, N=count phần tử
LREM O(N+M) N=list length, M=removed elements
BRPOP / BLPOP O(N) Blocking pop — N = số list theo dõi

Thêm phần tử

# Thêm vào CUỐI list (Right)
RPUSH fruits "apple" "banana" "cherry"
# (integer) 3

# Thêm vào ĐẦU list (Left)
LPUSH fruits "mango"
# (integer) 4

# Thêm nhiều phần tử cùng lúc
RPUSH fruits "orange" "grape" "watermelon"

Lấy phần tử

# Lấy theo index (0-based)
LRANGE fruits 0 -1    # Tất cả phần tử
LRANGE fruits 0 2     # 3 phần tử đầu
LRANGE fruits -3 -1   # 3 phần tử cuối

# Lấy phần tử đầu/cuối
LINDEX fruits 0       # Phần tử đầu
LINDEX fruits -1      # Phần tử cuối

# Độ dài list
LLEN fruits

Xóa phần tử

# Lấy và XÓA phần tử đầu (Left Pop)
LPOP fruits
# "mango"

# Lấy và XÓA phần tử cuối (Right Pop)
RPOP fruits
# "watermelon"

# Xóa N phần tử có giá trị cụ thể
RPUSH nums 1 2 3 2 4 2 5
LREM nums 2 2    # Xóa 2 phần tử có giá trị "2" từ đầu
LREM nums -1 2   # Xóa 1 phần tử từ cuối
LREM nums 0 2    # Xóa tất cả phần tử có giá trị "2"

Queue với Lists (FIFO)

Sử dụng List như một message queue đơn giản:

# Producer: Thêm job vào queue
RPUSH queue:email "send_welcome_email:user123"
RPUSH queue:email "send_invoice:user456"
RPUSH queue:email "send_reminder:user789"

# Consumer: Lấy job từ queue
LPOP queue:email
# "send_welcome_email:user123"

LPOP queue:email
# "send_invoice:user456"

Blocking Pop (Chờ có job)

# BLPOP: Chờ tối đa 5 giây để lấy job
BLPOP queue:email 5
# Nếu có job: ["queue:email", "send_welcome:user123"]
# Nếu hết timeout: (nil)

# BLPOP trên nhiều queue
BLPOP queue:email queue:sms 0
# 0 = chờ vô hạn

Stack với Lists (LIFO)

# Push vào stack
RPUSH stack:undo "action1"
RPUSH stack:undo "action2"
RPUSH stack:undo "action3"

# Pop từ stack (LIFO)
RPOP stack:undo
# "action3"

RPOP stack:undo
# "action2"

Activity Feed

# Thêm hoạt động mới
LPUSH feed:user:1001 "{\"action\": \"like\", \"post\": 42}"
LPUSH feed:user:1001 "{\"action\": \"comment\", \"post\": 38}"
LPUSH feed:user:1001 "{\"action\": \"share\", \"post\": 55}"

# Lấy 10 hoạt động gần nhất
LRANGE feed:user:1001 0 9

# Giới hạn feed chỉ giữ 1000 mục
LTRIM feed:user:1001 0 999

LTRIM: Giới hạn kích thước

LTRIM giữ list không phình to vô hạn:

# Chỉ giữ 100 phần tử gần nhất
RPUSH logs "log1" "log2" ... "log200"
LTRIM logs 0 99
# Chỉ còn 100 phần tử đầu

# Pattern hay dùng: LPUSH + LTRIM
LPUSH recent:searches "redis tutorial"
LTRIM recent:searches 0 9  # Giữ 10 tìm kiếm gần nhất

Use Cases thực tế

1. Background Job Queue

# Web server: Thêm job xử lý ảnh
RPUSH jobs:image:resize "{\"image_id\": 123, \"size\": \"thumbnail\"}"

# Worker: Lấy và xử lý job
while True:
    job = BLPOP jobs:image:resize, 0  # Chờ vô hạn
    process_image(job)

2. Chat Messages

# Gửi tin nhắn
LPUSH chat:room:42 "{\"user\": \"Tan\", \"msg\": \"Hello!\"}"

# Lấy 50 tin nhắn gần nhất
LRANGE chat:room:42 0 49

# Giới hạn lịch sử chat
LTRIM chat:room:42 0 999

3. Recent Items

# Sản phẩm đã xem gần đây
LPUSH recent:views:user:1001 "product:555"
LTRIM recent:views:user:1001 0 19  # Giữ 20 sản phẩm

# Lấy danh sách
LRANGE recent:views:user:1001 0 -1

So sánh: Lists vs Streams

Tiêu chí Lists Streams
Đơn giản ✅ Rất đơn giản ❌ Phức tạp hơn
Consumer Groups ❌ Không hỗ trợ ✅ Có
Message ID ❌ Không có ✅ Tự động tạo
Persistence ⚠️ Phụ thuộc config ✅ Tốt hơn
Use case Queue đơn giản Event streaming
Redis Lists queue and stack operations
Lists biến Redis thành queue hoặc stack cực kỳ hiệu quả

Best Practices

  • Dùng LTRIM — Giới hạn list size, tránh memory leak
  • Tránh LINDEX trên list dài — O(N) operation
  • Dùng BRPOP cho queue — Blocking pop tiết kiệm CPU
  • Pipeline khi batch — Gộp nhiều lệnh LPUSH thành batch
  • Monitor list length — Dùng LLEN để theo dõi

Bước tiếp theo

Bạn đã nắm vững Lists trong Redis! Tiếp theo, chúng ta sẽ tìm hiểu về Hashes — cấu trúc dữ liệu lý tưởng để lưu trữ objects.

👉 Bài tiếp theo: Hashes trong Redis

0 0 đánh giá
Đánh giá bài viết
Theo dõi
Thông báo của
guest
0 Góp ý
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất
Phản hồi nội tuyến
Xem tất cả bình luận