1. 程式人生 > 其它 >Redis6.0多執行緒模型

Redis6.0多執行緒模型

1. Redis6.0之前的版本真的是單執行緒嗎?
Redis在處理客戶端的請求時,包括獲取 (socket 讀)、解析、執行、內容返回 (socket 寫) 等都由一個順序序列的主執行緒處理,這就是所謂的“單執行緒”。但如果嚴格來講從Redis4.0之後並不是單執行緒,除了主執行緒外,它也有後臺執行緒在處理一些較為緩慢的操作,例如清理髒資料、無用連線的釋放、大 key 的刪除等等。
2. Redis6.0之前為什麼一直不使用多執行緒?
官方曾做過類似問題的回覆:使用Redis時,幾乎不存在CPU成為瓶頸的情況, Redis主要受限於記憶體和網路。例如在一個普通的Linux系統上,Redis通過使用pipelining每秒可以處理100萬個請求,所以如果應用程式主要使用O(N)或O(log(N))的命令,它幾乎不會佔用太多CPU。


使用了單執行緒後,可維護性高。多執行緒模型雖然在某些方面表現優異,但是它卻引入了程式執行順序的不確定性,帶來了併發讀寫的一系列問題,增加了系統複雜度、同時可能存線上程切換、甚至加鎖解鎖、死鎖造成的效能損耗。Redis通過AE事件模型以及IO多路複用等技術,處理效能非常高,因此沒有必要使用多執行緒。單執行緒機制使得 Redis 內部實現的複雜度大大降低,Hash 的惰性 Rehash、Lpush 等等 “執行緒不安全” 的命令都可以無鎖進行。
3.Redis6.0為什麼要引入多執行緒呢?
Redis將所有資料放在記憶體中,記憶體的響應時長大約為100納秒,對於小資料包,Redis伺服器可以處理80,000到100,000 QPS,這也是Redis處理的極限了,對於80%的公司來說,單執行緒的Redis已經足夠使用了。

但隨著越來越複雜的業務場景,有些公司動不動就上億的交易量,因此需要更大的QPS。常見的解決方案是在分散式架構中對資料進行分割槽並採用多個伺服器,但該方案有非常大的缺點,例如要管理的Redis伺服器太多,維護代價大;某些適用於單個Redis伺服器的命令不適用於資料分割槽;資料分割槽無法解決熱點讀/寫問題;資料偏斜,重新分配和放大/縮小變得更加複雜等等。
從Redis自身角度來說,因為讀寫網路的read/write系統呼叫佔用了Redis執行期間大部分CPU時間,瓶頸主要在於網路的 IO 消耗, 優化主要有兩個方向:

  • 提高網路 IO 效能,典型的實現比如使用 DPDK 來替代核心網路棧的方式
  • 使用多執行緒充分利用多核,典型的實現比如 Memcached。

協議棧優化的這種方式跟 Redis 關係不大,支援多執行緒是一種最有效最便捷的操作方式。所以總結起來,redis支援多執行緒主要就是兩個原因:

  • 可以充分利用伺服器 CPU 資源,目前主執行緒只能利用一個核
  • 多執行緒任務可以分攤 Redis 同步 IO 讀寫負荷

4.Redis6.0預設是否開啟了多執行緒?
Redis6.0的多執行緒預設是禁用的,只使用主執行緒。如需開啟需要修改redis.conf配置檔案:io-threads-do-reads yes

5.Redis6.0多執行緒開啟時,執行緒數如何設定?
開啟多執行緒後,還需要設定執行緒數,否則是不生效的。同樣修改redis.conf配置檔案

6.Redis6.0多執行緒的實現機制?

流程簡述如下:

  • 1、主執行緒負責接收建立連線請求,獲取 socket 放入全域性等待讀處理佇列
  • 2、主執行緒處理完讀事件之後,通過 RR(Round Robin) 將這些連線分配給這些 IO 執行緒
  • 3、主執行緒阻塞等待 IO 執行緒讀取 socket 完畢
  • 4、主執行緒通過單執行緒的方式執行請求命令,請求資料讀取並解析完成,但並不執行
  • 5、主執行緒阻塞等待 IO 執行緒將資料回寫 socket 完畢
  • 6、解除繫結,清空等待佇列

該設計有如下特點:

  • IO 執行緒要麼同時在讀 socket,要麼同時在寫,不會同時讀或寫
  • IO 執行緒只負責讀寫 socket 解析命令,不負責命令處理

7.開啟多執行緒後,是否會存線上程併發安全問題?
從上面的實現機制可以看出,Redis的多執行緒部分只是用來處理網路資料的讀寫和協議解析,執行命令仍然是單執行緒順序執行。所以我們不需要去考慮控制 key、lua、事務,LPUSH/LPOP 等等的併發及執行緒安全問題。

郭慕榮部落格園