# 17 為什麼CPU結構也會影響Redis的性能? ## 一、Redis 和 CPU 的基本關係 - 多數人認為 Redis 性能僅與 CPU 快慢有關,其實 CPU 的「多核架構」與「多 CPU 架構」也會影響 Redis 效能。 ## 二、主流的 CPU 架構 ### 1. CPU 核心與快取層級 - 每個 CPU 處理器有多個物理核心,每個核心擁有私有的 L1 與 L2 cache。 - L3 cache 為共享緩存,各物理核心可共用,容量大但速度較慢。 - 兩個超執行緒(邏輯核心)共用一個物理核心的 L1/L2 cache。 ![CleanShot 2025-06-26 at 13.08.44@2x](https://hackmd.io/_uploads/S1nkLL94xl.jpg) ![CleanShot 2025-06-26 at 13.08.24@2x](https://hackmd.io/_uploads/B1YCBL5Elg.jpg) ![CleanShot 2025-06-26 at 13.09.16@2x](https://hackmd.io/_uploads/rkiWII9Vxg.jpg) ### 2. 多 CPU (Socket) 架構 - 每個 CPU Socket 擁有自己的核心、快取與內存。 - 不同 CPU Socket 間的資料傳遞需透過總線,訪問遠端記憶體會增加延遲。 - 此架構稱為 NUMA(Non-Uniform Memory Access)。 ## 三、CPU 多核對 Redis 的影響 ### 1. 什麼是尾延遲(Tail Latency)? 尾延遲指的是系統處理請求時,最慢那一部分請求的延遲情況,通常用百分位數表示,例如: P99 尾延遲(99% tail latency): 表示 99% 的請求在某個延遲以下完成,剩下最慢的 1% 超過這個延遲值。 假設你有 1000 筆請求延遲資料(從快到慢排序): - 第 990 筆延遲是 0.8ms - 第 991 筆延遲是 1.2ms - 992 ~ 1000 可能是 2ms, 100ms 之類的 則 P99(99% 尾延遲)= 1.2ms 為什麼尾延遲很重要? - 在高併發環境下,少數高延遲請求可能會拖垮整體使用者體驗。 - 分散式系統中,如果一個服務鏈有 10 個子服務,只要有一個尾延遲高,就會影響整體響應。 ### 1. Context Switch 導致尾延遲增加 (Reids 7 有更好的設定方式) - 應用從一個核心切換到另一核心會重新載入運行時資訊與快取,增加延遲。 - 使用 `taskset` 綁定 Redis 實例至固定核心可改善此問題。 - 範例: ```bash taskset -c 0 ./redis-server ``` ### 2. 實驗結果 - 綁核前:GET/PUT 的 99% 尾延遲分別為 504μs / 1175μs。 - 綁核後:降至 260μs / 482μs。 ## 四、NUMA 架構對 Redis 的影響 ### 1. 網路中斷程序與 Redis 的綁定需在同一 Socket - 否則 Redis 存取中斷處理所寫入的記憶體時會跨 Socket,造成延遲。 - 使用 `lscpu` 查明核心與 NUMA 編號配置。 ![CleanShot 2025-06-26 at 13.19.01@2x](https://hackmd.io/_uploads/H1I8O8cNge.jpg) ### 2. 編號說明 - 編號非連續,需確認綁定的核心屬於同一 Socket。 ## 五、綁核的風險與解法 ### 1. 風險 - Redis 子進程與後台線程也會與主線程搶佔 CPU,造成延遲。 ### 2. 解法一:綁定一個物理核的兩個邏輯核 (Reids 7 有更好的設定方式) - 如: ```bash taskset -c 0,12 ./redis-server ``` ### 3. 解法二:程式綁核 (Reids 7 有更好的設定方式) - 使用 `sched_setaffinity()` 程式化綁定子進程與後台線程到不同核心。 - Redis 相關函數位置: - 後台線程:`bio.c` → `bioProcessBackgroundJobs` - RDB 子進程:`rdb.c` → `rdbSaveBackground` - AOF 子進程:`aof.c` → `rewriteAppendOnlyFileBackground` ### 4. Redis 7 可以使用設定綁核 在 Redis 7 中,可以使用官方提供的參數,將執行緒(尤其是 **I/O 執行緒**)綁定到特定的 CPU core 或 NUMA Socket,以提升效能,避免跨 Socket 訪問記憶體帶來的延遲。 ``` # 使用 4 條 I/O 執行緒來處理讀取 io_threads 4 # 啟用多執行緒處理 read 操作 io_threads_do_reads yes # 將 I/O 執行緒綁定在 CPU 4~7(需視你的系統 lscpu 結果) io_threads_cpulist 4-7 ``` 在 Linux 系統下可以搭配 lscpu 指令來設定 ## 六、小結 - 綁定 Redis 實例可減少 context switch,提高性能。 - 綁定策略應配合 NUMA 架構配置。 - 若不修改程式碼,可綁定一個物理核;若能修改,建議將各任務分散至不同核心。