Redis 作為全球最受歡迎的記憶體資料庫,以單機超過 10 萬 QPS 的恐怖吞吐量與微秒級(μs)極致延遲著稱。
然而,在現代多核心 CPU 當道的時代,許多工程師心中都有一個巨大的疑問:「為什麼 Redis 核心執行緒只採用單執行緒(Single-threaded)架構?單執行緒為何能做到如此極速?」
到了 Redis 6.0,官方又為何引入了 多執行緒(Threaded I/O)?這是否打破了其原有的單執行緒原子性保證?
本文將從作業系統底層、事件迴圈(Event Loop)、內部資料結構到多執行緒網路 I/O,全面解密 Redis 的核心架構。
1. 為什麼 Redis 採用單執行緒卻能做到極速?
Redis 的單執行緒特指**「網路請求解析、命令執行與資料讀寫」** 由單一主執行緒完成(其背景仍有非同步執行緒負責 AOF 刷盤、UNLINK 惰性釋放記憶體等)。
1.1 三大效能核心支柱
- 純記憶體操作(Pure In-Memory):所有資料均駐留在記憶體中,資料讀寫耗時在數十至數百奈秒(ns)級別,完全沒有磁碟 I/O 尋道延遲。
- 非阻塞 I/O 多路復用(I/O Multiplexing):基於 Linux
epoll,單一執行緒可同時監聽數萬個 Socket 連線,僅在有資料可讀寫時才被喚醒。 - 完全消除了執行緒切換與鎖競爭開銷:
- 多執行緒模型在處理高併發共享資料時,必須依賴互斥鎖(Mutex)、讀寫鎖或自旋鎖來保證線程安全,這會引發嚴重的鎖競爭(Lock Contention) 與作業系統上下文切換(Context Switch)。
- Redis 主執行緒無鎖運行,每個指令天然具備絕對的原子性(Atomicity)。
2. Redis 事件驅動核心:aeEventLoop 反應器架構
Redis 自研了一套極其精簡的高效能事件驅動庫 ae(A simple event-driven library):
3. Redis 核心資料結構底層黑科技
Redis 外部封裝的 String、Hash、List、Set、ZSet,在底層由一系列極致優化空間與效能的資料結構組成:
| 外部資料型態 | 底層資料結構 (Encoding) | 核心設計亮點 |
|---|---|---|
| 1. String | SDS (Simple Dynamic String) | O(1) 長度獲取、二進位安全、空間預分配 |
| 2. Hash | ListPack (緊湊列表) / Dict (字典) | 小資料時連續記憶體,大資料轉哈希表 |
| 3. List | QuickList (雙向鏈表 + ListPack) | 兼顧鏈表插入彈性與連續記憶體快取友善 |
| 4. Set | IntSet (整數集合) / Dict (字典) | 純整數極致二進位壓縮 (節省70%空間) |
| 5. ZSet (有序集合) | ListPack / Dict + SkipList (跳躍表) | O(log N) 極速多維範圍檢索與分值排序 |
3.1 SDS(簡單動態字串)
傳統 C 語言以 \0 結尾的字串存在安全與效能問題。SDS 引入結構體:
- 內建
len(記錄長度,O(1)獲取)與alloc(分配容量)。 - 空間預分配與惰性釋放:大幅減少字串頻繁拼接修改時的
malloc記憶體重分配次數。 - 二進位安全:允許內容包含任意二進位資料(包含
\0,可直接存圖片或 Protobuf 序列化物件)。
3.2 Dict 漸進式 Rehash(Progressive Rehashing)
當 Hash 表中的元素過多或過少時,需要擴容或縮容:
- Redis 維護兩個哈希表
ht[0]與ht[1]。 - 避免單次百萬級 Rehash 卡死:Redis 不會一次性將
ht[0]搬移到ht[1],而是在每次後續的客戶端讀寫請求中,順手將ht[0]上索引為rehashidx的桶資料搬移一個槽位到ht[1]。 - 同時在定時任務
serverCron中每次花費 1ms 進行輔助搬移,將龐大的計算開銷均攤到每一次日常請求中!
3.3 SkipList(跳躍表)
ZSet 在大資料量時採用跳躍表。相較於紅黑樹或 AVL 樹,跳躍表透過多層隨機高度索引節點(Level 1~32),以更簡單的代碼邏輯實現了 O(log N) 的插入、刪除與範圍掃描(ZRANGEBYSCORE),且在範圍遍歷時效率遠超平衡樹。
4. Redis 6.0+ 多執行緒網路 I/O 演進
在萬兆網卡普及的現代環境中,單一執行緒讀寫網路 Socket 的速度已經趕不上網路傳輸速度。
4.1 多執行緒架構邊界
- 核心原則不變:所有命令的執行依然在單一主執行緒中完成,因此原有命令的原子性保證與無鎖特性 100% 得到保留!
- 突破極限:僅將最耗費 CPU 週期與系統呼叫的「網路 Socket 讀取、協議解析、網路 Socket 寫入」交由多執行緒平行處理,使 Redis 吞吐量再次獲得 2 倍以上的翻倍暴增!
