這篇文章帶大家了解Redis6中的執行緒模型,介紹一下單執行緒模型和多執行緒模型,希望對大家有幫助!
#如果單純的說redis是單線程或多線程,這個回答肯定不嚴謹,不同版本使用的線程模型是不一樣的。 【相關推薦:Redis影片教學】
#版本3.x ,最早版本,也就是大家口耳相傳的redis是單線程。
版本4.x,嚴格意義來說也不是單線程,而是負責處理客戶端請求的線程是單線程,但是開始加了點多線程的東西(異步刪除)
。
最新版本的6.0.x後, 告別了大家印像中的單線程,用一種全新的多線程
來解決問題。
#2.1 單執行緒真實意義
主要是指Redis的網路IO和鍵值對讀寫是由一個執行緒來完成的,Redis在處理客戶端的請求時包括取得(socket 讀)、解析、執行、內容回傳(socket 寫) 等都由一個順序串行的主線程處理,這就是所謂的“單線程”。這也是Redis對外提供鍵值儲存服務的主要流程。
但Redis的其他功能, 例如持久化、非同步刪除、叢集資料同步等等,其實是由額外的執行緒
執行的。
可以這麼說,Redis工作執行緒是單執行緒的。但是,整個Redis來說,是多執行緒的
;
2.2 單執行緒效能快原因
##Redis 3 .x 單執行緒時代但是效能很快的主要原因:
2.3 採用單線程原因
Redis 是基於記憶體操作的, 因此他的瓶頸可能是機器的記憶體或網路頻寬而非CPU ,既然CPU 不是瓶頸,那麼自然就採用單執行緒的解決方案了,況且使用多執行緒比較麻煩。但是在 Redis 4.0 中開始支援
多執行緒了,例如後台刪除等功能。
簡單來說,Redis 4.0 之前一直採用單線程的主要原因有以下三個:
效能瓶頸是記憶體或網路頻寬而非CPU。
#3.1 引入多執行緒原因
既然單執行緒那麼好,為啥又要引入多執行緒?
單一線程也有自己的煩惱,例如大key刪除問題:
正常情況下使用del 指令可以很快的刪除數據,而當被刪除的key 是一個非常大的物件時,例如時包含了成千上萬個元素的hash 集合時,那麼del 指令就會造成Redis 主線程卡頓。
因此,在 Redis 4.0 中就新增了多執行緒的模組,當然此版本中的多執行緒主要是為了解決刪除資料效率比較低的問題。可以透過惰性刪除有效避免Redis卡頓問題(大key刪除等問題),步驟如下:
##unlink key : 與DEL一樣刪除key功能的lazy free實作,唯一不同是,UNLINK在刪除集合類型鍵時,如果集合鍵的元素個數大於64個,主執行緒中只是把待刪除鍵從資料庫字典中摘除,會把真正的記憶體釋放操作,給單獨的bio來操作。如果元素個數較少(少於64個)或是String類型,也會在主執行緒直接刪除。
flushall/flushdb async : 對於清空資料庫指令flushall/flushdb,新增了async非同步清理選項,使得redis在清空資料庫時都是非同步操作。實作邏輯是為資料庫新建一個新的空的字典,把原有舊的資料庫字典給後台執行緒來逐一刪除其中的數據,釋放記憶體。
lazy free的本質就是把
某些cost(主要時間複製度,佔用主線程cpu時間片)較高刪除操作, 從redis主線程剝離讓bio子線程來處理,大大減少主線阻塞時間。從而減少刪除導致效能和穩定性問題。
3.2 多執行緒工作原理
I/O 的讀取和寫入本身是堵塞的,例如當socket 中有資料時,Redis會透過調用先將資料從內核態空間拷貝到用戶態空間,再交給Redis 調用,而這個拷貝的過程就是阻塞的,當資料量越大時拷貝所需的時間就越多,而這些操作都是基於單線程完成的。 在Redis 6.0 中新增了多執行緒的功能來提高I/O 的讀寫效能,他的主要實作思路是將主執行緒的IO 讀寫任務拆分給一組獨立的線程去執行,這樣就可以使多個socket 的讀寫可以並行化了,採用多路I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網絡IO的時間消耗),將最耗時的Socket的讀取、請求解析、寫入單獨外包出去,剩下的命令執行仍然由主線程串行執行併和內存的數據交互。 結合上圖可知,
將網路資料讀寫、請求協定解析通過多個IO線程的來處理,對於真正的命令執行來說,仍然使用主線程操作(線程安全),是個不錯的折衷辦法。因此,對於整個Redis來說是多執行緒的,但是對於工作執行緒(指令執行)仍舊是單執行緒。
流程簡述如下:
讀取socket 完畢
(如果指令沒有接收完畢,會等IO 下次繼續)
將資料回寫socket 完畢(一次沒寫完,會等下次再寫)
特點如下:
經過有心人士的壓測,目前效能能提升1 倍以上。
疑問1:等待清單不滿 一直阻塞不處理嗎?
回覆:阻塞時偵測的是,IO 執行緒是否還有任務。等處理完了才繼續往下。這些任務是在執行時加上的,如果 任務數這塊還是有點疑問,哪位大佬可以解釋下(評論哈)?
3.4 預設開啟多執行緒嗎?
在Redis6.0中, 多執行緒機制預設是關閉的
,如果需要使用多執行緒功能,則需要在redis.conf中完成兩個設定。
如果為8 核CPU 建議線程數設置為6
,則線程數一定要小於機器核數,線程數就不是越大越好。 Redis本身出道就是優秀,基於記憶體運算、資料結構簡單、多重化與非阻塞I/O、避免了不必要的線程上下文切換等特性,在單線程的環境下仍然很快;
但對於大數據的key 刪除還是卡頓厲害,因此在Redis 4.0 引入了多線程unlink key/flushall async 等指令,主要用於Redis 資料的非同步刪除;
而在Redis 6.0 中引入了I/O 多執行緒的讀寫,這樣就可以更有效率的處理更多的任務了, Redis 只是將I/O 讀寫變成了多執行緒
,而指令的執行依舊是由主執行緒串列執行的
,因此在多執行緒下操作Redis 不會出現線程安全的問題
。
Redis 無論是當初的單線程設計,還是如今與當初設計相背的多線程,目的只有一個:讓 Redis 變得越來越快。
更多程式相關知識,請造訪:程式設計入門! !
以上是淺析Redis6中的單執行緒與多執行緒模型的詳細內容。更多資訊請關注PHP中文網其他相關文章!