1. 程式人生 > >Redis單執行緒理解

Redis單執行緒理解

簡介
從接觸Redis到現在,一直被它的單執行緒問題困擾,這對於一個苛求原理的我來說是種折磨,今天吃飯途中看了幾篇部落格,茅塞頓開。

個人理解
        redis分客戶端和服務端,一次完整的redis請求事件有多個階段(客戶端到伺服器的網路連線-->redis讀寫事件發生-->redis服務端的資料處理(單執行緒)-->資料返回)。平時所說的redis單執行緒模型,本質上指的是服務端的資料處理階段,不牽扯網路連線,這是理解redis單執行緒的第一步。接下來,針對不同階段分別闡述個人的一些理解。

1:客戶端到伺服器的網路連線
首先,客戶端和伺服器是socket通訊方式,socket服務端監聽可同時接受多個客戶端請求,這點很重要,如果不理解可先記住。注意這裡可以理解為本質上與redis無關,這裡僅僅做網路連線,或者可以理解為,為redis服務端提供網路互動api。

        假設建立網路連線需要30秒(為了更容易理解,所以時間上擴大了N倍)

2:redis讀寫事件發生並向服務端傳送請求資料
        首先確定一點,redis的客戶端與伺服器端通訊是基於TCP連線(不懂去看,基礎很重要),第一階段僅僅是建立了客戶端到伺服器的網路連線,然後才是發生第二階段的讀寫事件。

        完成了上一個階段的網路連線,redis客戶端開始真正向伺服器發起讀寫事件,假設是set(寫)事件,此時redis客戶端開始向建立的網路流中送資料,服務端可以理解為給每一個網路連線建立一個執行緒同時接收客戶端的請求資料。

        假設從客戶端發資料,到服務端接收完資料需要10秒。

3:redis服務端的資料處理
        服務端完成了第二階段的資料接收,接下來開始依據接收到的資料做邏輯處理,然後得到處理後的資料。資料處理可以理解為一次方法呼叫,帶參呼叫方法,最終得到方法返回值。不要想複雜,重在理解流程。

        假設redis服務端處理資料需要0.1秒

3:資料返回
        這一階段很簡單,當reids服務端資料處理完後 就會立即返回處理後的資料,沒什麼特別需要強調的。

        假設服務端把處理後的資料回送給客戶端需要5秒。

那麼什麼是Reids的單執行緒
        第一階段說過,redis是以socket方式通訊,socket服務端可同時接受多個客戶端請求連線,也就是說,redis服務同時面對多個redis客戶端連線請求,而redis服務本身是單執行緒執行。

        假設,現在有A,B,C,D,E五個客戶端同時發起redis請求,A優先稍微一點點第一個到達,然後是B,C,D,E依次到達,此時redis服務端開始處理A請求,建立連線需要30秒,獲取請求資料需要10秒,然後處理資料需要0.1秒,回送資料給客戶端需要5秒,總共大概需要45秒。也就是說,下一個B請求需要等待45秒,這裡注意,也許這五個幾乎同時請求,由於socket可以同時處理多個請求,所以建立網路連線階段時間差可忽略,但是在第二階段,服務端需要什麼事都不幹,坐等10秒中,對於CPU和客戶端來說是無法忍受的。所以說單執行緒效率非常,非常低,但是正是因為這些類似問題,Redis單執行緒本質上並不是如此執行。接下來討論redis真正的單執行緒執行方式。

        客戶端與服務端建立連線交由socket,可以同時建立多個連線(這裡應該是多執行緒/多程序),建立的連線redis是知道的(為什麼知道,去看socket程式設計,再次強調基礎很重要),然後redis會基於這些建立的連線去探測哪個連線已經接收完了客戶端的請求資料(注意:不是探測哪個連線建立好了,而是探測哪個接收完了請求資料),而且這裡的探測動作就是單執行緒的開始,一旦探測到則基於接收到的資料開始資料處理階段,然後返回資料,再繼續探測下一個已經接收完請求資料的網路連線。注意,從探測到資料處理再到資料返回,全程單執行緒。這應該就是所謂的redis單執行緒。至於內部有多複雜我們無需關心,我們追求的是理解流程,苛求原理,但不能把內臟都挖出來。

        從探測到接受完請求資料的網路連線到最終的資料返回,伺服器只需要5.1秒,這個時間是我放大N倍後的資料,實際時間遠遠小於這個,可能是5.1的N萬分之一時間,為什麼這麼說,因為資料的處理是在本地記憶體中,速度有多快任你想象,最終的返回資料雖然牽扯到網路,但是網路連線已經建立,這個速度也是非常非常快的,只是比資料處理階段慢那麼一點點。因此單執行緒方式在效率上其實並不需要擔心。