redis為何單線程 效率還這么高 為何使用跳表不使用B+樹做索引(阿里)


如果想了解 redis 與Memcache的區別參考:Redis和Memcache的區別總結

阿里的面試官問問我為何redis 使用跳表做索引,卻不是用B+樹做索引

因為B+樹的原理是 葉子節點存儲數據,非葉子節點存儲索引,B+樹的每個節點可以存儲多個關鍵字,它將節點大小設置為磁盤頁的大小,充分利用了磁盤預讀的功能。每次讀取磁盤頁時就會讀取一整個節點,每個葉子節點還有指向前后節點的指針,為的是最大限度的降低磁盤的IO;因為數據在內存中讀取耗費的時間是從磁盤的IO讀取的百萬分之一

而Redis是 內存中讀取數據,不涉及IO,因此使用了跳表; 

至於redis的跳表原理 參考:聊聊Mysql索引和redis跳表 ---redis的有序集合zset數據結構底層采用了跳表原理 時間復雜度O(logn)(阿里)

mysql的B+索引原理 參考:一步步分析為什么B+樹適合作為索引的結構 以及索引原理 (阿里面試)

Kafka索引 參考:kafka如何實現高並發存儲-如何找到一條需要消費的數據(阿里)

接下來問題來了:為何 redis使用單線程 讀取速度還這么塊呢

今天下午,煙哥吃飽了撐着沒事干,上班時間到處工(zhuang)作(bi)!只見同事小劉的桌上擺了一本Redis相關的書籍,內心嘿嘿一笑:“終於,又有機會勾搭小劉了!”

於是有了如下對話

 

 

"嗯,不要方,跟着我思路來想!"煙哥道。

"假設,此刻有任務A和任務B,現在有如下兩種執行方式"

方式一:兩個線程,一個線程執行A,另一個線程執行B方式二:一個線程,先執行A,執行完以后繼續執行B

"請問,哪種方式執行更快?"

 

 

只見煙哥眉頭微微一皺,說道:"我夜觀天象,掐指一算,小劉你大學在上《計算機組成原理》這門課的時候,一定逃課了!"

"應該是方式二更快,因為方式一中,CPU在切換線程的時候,有一個上下文切換時間,而這個上下文切換時間是非常耗時的!打個比方,一個CPU主頻是 2.6GHz,這意味着每秒可以執行:2.6*10^9 個指令,那么每個指令的時間大概是0.38ns!而一次上下文切換,將近需要耗時2000ns!而這個時間內,CPU什么都干不了,只是做了保存上下文都動作!"

 

 

"OK,就是在I/O操作都時候,例如磁盤I/O,網絡I/O等!為什么一般是在I/O操作都時候,要用多線程呢(面試高頻題,必背)?因為I/O操作一般可以分為兩個階段:即等待I/O准備就緒和真正操作I/O資源!"

"以磁盤操作為例,磁盤的結構如下"

 

 

"在磁盤上數據是分磁道、分簇存儲的,而數據往往並不是連續排列在同一磁道上,所以磁頭在讀取數據時往往需要在磁道之間反復移動,因此這里就有一個尋道耗時!另外,盤面旋轉將請求數據所在扇區移至讀寫頭下方也是需要時間,這里還存在一個旋轉耗時!"

"那么,在這一時間段(即"I/O等待")內,線程是在“阻塞”着等待磁盤,此時操作系統可以將那個空閑的CPU核心用於服務其他線程。因此在I/O操作的情況下,使用多線程,效率會更高!"

"OK,現在回到我們的問題!Redis讀寫數據有涉及到I/O操作么?"

 

 

"所以啊,Redis不涉及I/O操作,因此設計為單線程是效率最高的!那么,既然你知道既然Redis的性能和CPU無關,那你知道Redis的性能瓶頸在哪么?"

小劉無奈的搖了搖頭!

一般在兩個地方

其一是機器內存大小,內存大小關系到Redis存儲的數據量其二是網絡帶寬,這點我仔細說一下Redis客戶端執行一條命令分為四個過程:發送命令、命令排隊、命令執行、返回結果

而其中發送命令+返回結果這一過程被稱為Round Trip Time(RTT,往返時間)

Redis的客戶端和服務端可能部署在不同的機器上。例如客戶端在北京,Redis服務端在上海,兩地直線距離約為1300公里,那么1次RTT時間=1300×2/(300000×2/3)=13毫秒(光在真空中傳輸速度為每秒30萬公里,這里假設光纖為光速的2/3),那么客戶端在1秒內大約只能執行80次左右的命令,這就和Redis的高並發高吞吐特性背道而馳啦!所以一般情況下,都是就近部署!

參考:Redis為什么設計成單線程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM