執行人: Andrewtangtang
Redis 是款高效能的 key-value 資料結構儲存系統,可作為資料庫、快取及資料處理佇列使用。它將所有資料集都儲存在記憶體中,一次送出多筆請求以提升吞吐量並降低通訊延遲。與其他 key-value 快取產品相比,Redis 還具備以下特色:
在 Redis 6.0 之前,採用單執行緒模型,由主執行緒負責所有客戶端請求的處理,包含 socket 讀取、封包解析、命令執行及 socket 寫出。它透過 ae 事件模型搭配 I/O 多工處理,以便高速回應請求。需要注意的是,自 Redis 4.0 起,背景會額外啟用一些執行緒來處理較慢的操作,但在 Redis 6.0 之前,真正的「單執行緒」指的仍是那個負責 socket 讀寫與命令處理的主執行緒。
Redis 6.0 之後,可選用一組獨立的 I/O 執行緒來處理 socket 的讀寫呼叫(預設未啟用)。主執行緒仍然負責 ae 事件通知,當有讀寫需求時,會將任務平均分派給 I/O 執行緒(主執行緒也會處理部分任務),並等待所有執行緒完成後再繼續後續流程。
阿里巴巴技術團隊引入 io_uring 的非同步處理與 FAST_POLL 機制後,Redis 在 event-poll 與 io_uring 下的 QPS 表現對比如下:
參照:
2024 年 3 月 20 日,Redis, Inc. 正式將核心程式碼的授權方式從 BSD 三條款轉換為 Redis Source Available License v2(RSALv2)和 Server Side Public License v1(SSPLv1),這二種授權都非 OSI 認可的開放原始程式碼授權,旨在防止某些雲端服務商「搭便車」地使用 Redis 而不回饋程式碼或營收。
早在 2018 年,Redis 就已針對模組授權作出調整:那時將原本採用 AGPLv3 的模組,改為 Apache 2.0 加入 Commons Clause;到了 2019 年,又統一改採 RSAL,並明確禁止將模組用於資料庫、快取、串流處理、搜尋或 AI/ML 服務等商業模式的捆綁銷售。
為了延續 BSD 三條款的開放精神,Linux Foundation 於 2024 年 3 月 28 日推出 Valkey 專案,基於尚未改動授權的 Redis 7.2.4 分支,並持續以 BSD 三條款發布,迅速獲得 AWS、Google Cloud, Oracle, Ericsson 和 Snap Inc. 等多家廠商的支持。
隨後在 2025 年 5 月 1 日,Redis 宣布自 8.0 版本起回歸 GNU AGPLv3 授權,並與 SSPLv1、RSALv2 共存,使 Redis 重新成為 OSI 認可的開放原始程式碼軟體。由於 Valkey 已建立起穩固的社群與生態,短期內這兩個專案將各自獨立發展。
本任務評估以下現有 Redis/Valkey 的 io_uring 修改,重新評估和分析其效能表現,協助 code review,並嘗試在近期的 Redis 或 Valkey 予以驗證:
參照: Dragonfly vs. Valkey Benchmark: 4.5x Higher Throughput on Google Cloud
研讀 針對事件驅動的 I/O 模型演化: io_uring,指出何以 io_uring 能夠加速網路伺服器的運作,又如何細緻地調整 I/O。搭配以下影片:
現今網路伺服器的 I/O 的模式大多使用 synchronous I/O 並搭配 I/O 多工(例如 epoll
)機制來監聽網路 socket 事件來確認是否有新事件後再以系統呼叫進行 non-blocking I/O 操作,然而這也意味著對於每一次的 I/O 事件至少需要兩次的系統呼叫,一次為 I/O 事件的收割 (reap) 如 epoll_wait()
,接下來的系統呼叫才是真正的 I/O 操作如 read()
、write()
,然而隨著近年來的處理器的安全 Spectre 與 Meltdown 處理器的安全漏洞被揭露,linux 核心引入了 KPTI 完全分離使用者空間與核心空間頁表來解決洩漏的問題,這項機制讓每次的系統呼叫都會重新 flush TLB 造成極大的效能瓶頸,僅管新的處理器支援 PCID 在一定程度上緩解了 TLB flush 的問題,模式切換所帶來的延遲仍舊明顯,尤其在高頻 I/O 場景下更顯得成本高昂。
為了在 I/O 週期內盡量減少系統呼叫次數,asynchronous I/O(非同步 I/O) 機制成為解決此問題的最佳途徑。它僅需一次系統呼叫,即可讓 I/O 操作在核心空間背景中非同步執行,主應用程式則可繼續處理其他邏輯。當核心完成 I/O 操作後,透過 signal 或其他通知機制,提醒主程式該操作已完成。這樣的設計可將 I/O 延遲隱藏於核心內部,避免傳統 read()、write() 等阻塞操作造成的應用程式停滯,有效提升整體效能。
過去 Linux 曾實作過兩種非同步 I/O 機制,分別為 glibc 的 POSIX AIO 與 Linux native AIO。儘管這兩者在理論上對於高效能網路伺服器具有潛力,實務上卻因部署與維護困難、API 設計不夠直觀,導致實際被廣泛採用的案例並不多,限制了其在高速網路伺服器中的應用發展。隨著 io_uring 在 Linux v5.1 中問世,Linux 核心終於導入了一套設計現代化、效能優化的非同步 I/O 機制,能有效降低系統呼叫成本、減少 context switch,並支援批次提交與完成通知,為高效能伺服器場景提供了新的解決方案。
io_uring 會在使用者空間與核心空間之間建立一塊共享記憶體區域,並在其中配置兩個 lock-free 的環形緩衝區:
這塊共享記憶體可以讓應用程式與核心之間,高效的交換 I/O 請求與結果資訊,除此之外,為了可以符合多核環境中達成高效同步,該環形緩衝區採以 lock free 且單一消費者、單一生產者的形式。對於 SQ 只有應用程式可以寫入更新 tail,也只有核心的有可讀取更新 head ; 對於 CQ 則相反,只有應用程式可以讀取更新 head 而也只有核心可以寫入更新 tail,並藉由 atomic 操作和 memory barrier 管理頭尾指標可以有效的避免傳統 lock 帶來的開銷。
io_uring 的環形提交佇列允許應用程式先行批次填入多筆 SQE 請求,再透過一次 io_uring_enter()
系統呼叫,一次性將所有請求提交給核心執行對應的 I/O 操作。此外,在某些極致效能要求的場景中,可以啟用 SQPOLL
(提交佇列輪詢) 模式,由核心背景執行緒主動監控 SQ 的變化,從而達成幾乎零系統呼叫的 I/O 請求。綜合以上優勢,與傳統 epoll 搭配 non-blocking I/O 的模型相比(每次 I/O 至少需兩次系統呼叫),io_uring 大幅減少了高頻 I/O 場景下的模式切換開銷,可以顯著提升 throughput 與延遲表現。
針對 Add io_uring support to redis,重新實驗並比對其效能評比和 Anolis: Redis,探討效能表現,注意 Processor affinity 的設定。
針對 Redis 和 Valkey 現有 io_uring 相關 pull request 的成果,解釋其所要克服的技術議題,並說明何以 io_uring 有效益。
整合 (或重作部分) 上述成果,應用於近期的 Valkey