Single Thread No Problem

Thực tế, Redis nhanh nhờ vào kiến trúc Single-thread chứ không phải là nhược điểm. Để hiểu sâu vấn đề này, chúng ta cần nhìn vào bản chất của phần cứng và hệ điều hành.

Dưới đây là 4 lý do kỹ thuật chính khiến Redis đạt hiệu năng khủng khiếp (100k+ ops/sec) dù chỉ chạy đơn luồng:


1. Nó chạy hoàn toàn trên RAM (Memory-bound)

Đây là yếu tố tiên quyết.

  • Database truyền thống (MySQL/PostgreSQL) bị chậm do Disk I/O (đọc ghi ổ cứng).

  • Redis lưu mọi thứ trên RAM. Tốc độ truy xuất RAM tính bằng nanoseconds, trong khi ổ cứng là milliseconds.

  • Vì RAM quá nhanh, CPU hiếm khi phải chờ dữ liệu. Do đó, việc chia nhiều luồng để "tận dụng thời gian chờ I/O" (như cách các web server thường làm) trở nên thừa thãi.

2. I/O Multiplexing (Vũ khí bí mật)

Đây là lý do quan trọng nhất về mặt kiến trúc. Redis sử dụng cơ chế Non-blocking I/O kết hợp với I/O Multiplexing (thường là epoll trên Linux hoặc kqueue trên BSD).

  • Mô hình truyền thống (Blocking I/O): Mỗi khi có 1 client kết nối, server tạo 1 Thread để phục vụ. Khi client chưa gửi data, Thread đó ngồi chờ (Block) -> Tốn tài nguyên RAM và CPU để quản lý thread.

  • Mô hình Redis (Event Loop):

    • Redis chỉ dùng 1 luồng duy nhất để lắng nghe (monitor) hàng nghìn socket kết nối cùng lúc.

    • Chỉ khi nào socket có dữ liệu thực sự (Readable/Writable), epoll mới báo cho Redis biết.

    • Redis xử lý ngay lập tức request đó và quay lại lắng nghe tiếp.

    • Ví dụ: Giống như một ông lễ tân khách sạn siêu đẳng. Thay vì thuê 100 nhân viên đứng canh 100 cửa phòng (Multi-thread), chỉ cần 1 ông lễ tân ngồi ở sảnh, ai bấm chuông thì ông ấy xử lý ngay lập tức.

3. Loại bỏ chi phí Context Switching (Chuyển ngữ cảnh)

Trong hệ thống Multi-thread, CPU phải liên tục chuyển đổi giữa các thread để ai cũng được chạy. Quá trình này gọi là Context Switching.

  • Để chuyển từ Thread A sang Thread B, CPU phải lưu lại trạng thái của A, nạp trạng thái của B. Việc này tốn CPU.

  • Redis Single-thread chạy một mạch từ đầu đến cuối. CPU không phải mất thời gian "nhảy qua nhảy lại". Toàn bộ sức mạnh CPU tập trung vào việc xử lý dữ liệu.

4. Không cần Locks (Race Conditions Free)

Bạn là Developer chắc chắn hiểu nỗi đau của Locking (Mutex, Semaphore) trong lập trình đa luồng để tránh Race Condition.

  • Việc chờ Lock (Lock contention) làm giảm hiệu năng cực lớn.

  • Vì Redis xử lý tuần tự từng lệnh một (Sequential consistency), nó không cần Lock cho các cấu trúc dữ liệu của nó.

  • Điều này giúp code Redis cực kỳ tối ưu, đơn giản và chạy nhanh hơn.


Một sự thật thú vị: Redis không còn "hoàn toàn" Single-thread nữa!

Từ phiên bản Redis 6.0 (2020), kiến trúc đã thay đổi nhẹ để giải quyết nút thắt cổ chai mới: Network I/O.

  • Mặc dù lệnh GET/SET xử lý rất nhanh, nhưng việc đọc gói tin từ network và ghi gói tin phản hồi ra network tốn kha khá thời gian CPU.

  • Redis 6.0 giới thiệu I/O Threads:

    • Vẫn dùng 1 Main Thread để thực thi lệnh (đảm bảo tính Atomic, không cần Lock).

    • Dùng nhiều I/O Threads phụ chỉ để đọc/ghi socket mạng.

Tóm lại: Redis nhanh vì nó chuyển bài toán từ CPU-bound sang Memory-bound và Network-bound, sau đó tối ưu hóa cực tốt việc xử lý sự kiện I/O mà không gánh chi phí quản lý đa luồng cồng kềnh.

Last updated