簡介
從接觸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萬分之一時間,為什麼這麼說,因為資料的處理是在本地記憶體中,速度有多快任你想象,最終的傳回資料雖然牽扯到網絡,但是網絡連接配接已經建立,這個速度也是非常非常快的,隻是比資料處理階段慢那麼一點點。是以單線程方式在效率上其實并不需要擔心。