《redis》4-redis是單執行緒?

David_lou發表於2020-10-10

江湖傳言,redis是單執行緒的,習慣了多執行緒高併發的高大上基數架構之後,猛然回頭,發現支援三高的redis是單執行緒的,這個你能信?

“單執行緒”描述redis固然不準確,我們只能說,redis在訪問儲存部分的時候是單執行緒的。

學習過tomcat的應該清楚,tomcat跟redis的架構有些類似。

tomcat有個專門處理connector的聯結器,可以同時處理N個請求,但是connector在提交請求到容器部分的時候,提交的其實是runner,tomcat的自己的執行緒池會持續處理提交的runner,執行結果返回給response。這也是為什麼tomcat能夠併發處理多請求的基礎。

redis的基礎模組中,

我們也總結道redis存在一個訪問模組,在我們的實際環境中,

  1. redis服務處理socket請求,多臺伺服器同時請求redis服務,也是跟tomcat一樣,使用多路複用IO模型
  2. 請求被提交到操作模組的時候,會把請求抽象成task,放入請求佇列,但是隻有一個執行緒處理task。也就是說,生產者消費者模式中,只有一個消費者。跟tomcat的執行緒池的多執行緒的區別就在這裡
  3. 把請求的結果返回給response

這個時候我們其實可以關注三個點

  1. 處理訪問請求的I/O模型-多路複用
  2. 生產者消費者模式
  3. 單執行緒和執行緒池的優缺點

I/O模型,就是作業系統處理I/O硬體的模型,主要有5中

  1. 同步阻塞操作模型
  2. 同步非阻塞操作模型
  3. 多路複用模型
  4. 非同步模型
  5. 訊號驅動模型

現在java中多使用多路複用模型,即Redis中使用的模型。他們的主要區別就是,在使用者執行緒(redis的訪問模組中的請求處理執行緒或者tomcat中connector中的請求處理執行緒),在處理socket的內容時的是否同步和是否阻塞。

簡單的同步阻塞模型,比如我們需要讀取socket的請求內容,這麼一個簡單的操作,使用者執行緒需要等待核心執行緒把資料從io外部裝置copy到核心,然後再從核心copy到使用者執行緒空間,這樣的速度是緩慢的,使用者執行緒需要同步等待並阻塞,直到這一整個過程結束。

在學習tomcat的時候,李號雙老師總結了一下上面的4中IO模型。我們比較關注多路複用模型。

上面是簡單的多路複用模型,在使用者執行緒中,

  1. 有一個單獨的執行緒在迴圈中呼叫select方法,查詢socket中已經做了資料準備的連結
  2. select方法查到準備好的socket,然後經過一些列操作,把socket的操作提取成task,放入佇列
  3. 使用者另外的執行緒,處理task佇列中的task。

多路服用的特點就是可以處理很多socket。

上面的task列表和執行緒處理task列表中的task就是生產者和消費者模式

那我們在redis中的消費者,即執行task的執行緒只有一個執行緒,所以redis是單執行緒。tomcat卻有一個執行緒池,執行緒池中有多個執行緒一起消費task列表。

為什麼tomcat和redis選擇了不同的路線呢?這跟tomcat和redis處理的業務場景有關,tomcat在啟動分web服務中,很多請求需要請求資料庫,檔案伺服器等,這些又是一些外部裝置,操作時間常,cpu利用率低,所以可以多執行緒,增加吞吐量。

優點:但是redis是記憶體儲存服務,只需要訪問記憶體就能範圍,而且大部分內容訪問時間複雜度是O(1),所以處理訪問的時間非常短,不需要執行緒等待太長時間,單個執行緒還可以避免多執行緒併發造成的死鎖問題,還可以避免執行緒上下文切換造成的時間消耗。

缺點:但是單執行緒處理也有個問題,如果task佇列中出現一個複雜訪問,比如說訪問時間是1s,那麼佇列後面的任務都要阻塞到該任務執行完。

但是redis不僅有記憶體訪問模組一個功能,主從同步的時候,也有單獨的執行緒。持久化的時候,也有單獨的執行緒。這些功能性的執行緒也一起為redis的高可用提供的了支撐

相關文章