原文連接java
能堅持別人不能堅持的,才能擁有別人不能擁有的。
關注編程大道
公衆號,讓咱們一同堅持心中所想,一塊兒成長!!面試
《【面試突擊】— Redis篇》-- Redis的線程模型瞭解嗎?爲啥單線程效率還這麼高?redis
在這個系列裏,我整理了一些面試題與你們分享,幫助想要在金三銀四準備跳槽的同窗。
鞏固、突擊面試官常問的一些面試題,加油!!算法
Redis和Memcached有什麼區別?編程
Redis的線程模型是什麼?緩存
爲何Redis是單線程的可是還能夠支撐高併發?服務器
問這個的時候就是問你Redis的原理了,看你是否是思考過,研究過。Redis最基本的一個內部原理和特色,就是Redis其實是個單線程工做模型。你要是連這個都不知道,那後面在使用Redis的時候,若是出了問題豈不是什麼都不知道,無從下手?網絡
還有可能面試官會問問你Redis和Memcached的區別。不過說實話,近幾年,面試官都不太喜歡這麼問了。由於memcached是早些年各大互聯網公司經常使用的緩存方案,可是如今近幾年基本都是Redis,沒什麼公司用memcached了。數據結構
若是你要是如今還不知道redis和memcached是啥,那你趕忙百度一下redis入門和memcahced入門,找兩篇博客教程什麼的簡單啓動一下,而後試一下幾個簡單操做,先感覺一下,跟博客、教程作個demo程序,一小時之內就搞定了,就能初步瞭解和入門了。而後接着回來繼續看。多線程
另一個友情提示,要弄明白redis的線程模型的話,前提是你須要瞭解socket網絡相關的基本知識。若是你socket都不瞭解的話那我以爲你java沒學好吧。初學者都該學習java的socket網絡通訊相關知識的。
這個問題,其實能夠比較出不少區別,可是這裏仍是採起redis做者給出的幾個來進行比較吧,畢竟面試不是背博客,不是說的越多越好,你只要答出來關鍵的那幾點其實就能夠了。可是並非說除了這裏列出來的幾個你就不須要知作別的了,你能夠說:要說兩者的區別其實還挺多的,這裏我就挑幾個最典型的說吧。
1)Redis支持服務器端的數據操做
Redis相比Memcached來講,擁有更多的數據結構和並支持更豐富的數據操做,一般在Memcached裏,你須要將數據拿到客戶端來進行相似的修改再set回去。這大大增長了網絡IO的次數和數據體積。在Redis中,這些複雜的操做一般和通常的GET/SET同樣高效。因此,若是須要緩存可以支持更復雜的結構和操做,那麼Redis會是不錯的選擇。
2)內存使用效率對比
使用簡單的key-value存儲的話,Memcached的內存利用率更高,而若是Redis採用hash結構來作key-value存儲,因爲其組合式的壓縮,其內存利用率會高於Memcached。
3)性能對比
因爲Redis只使用單核,而Memcached可使用多核,因此平均每個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,可是比起Memcached,仍是稍有遜色。
4)集羣模式
memcached沒有原生的集羣模式,須要依靠客戶端來實現往集羣中分片寫入數據;可是redis目前是原生支持cluster模式的,redis官方就是支持redis cluster集羣模式的,比memcached來講要更好。
其實第二、3個說不說均可以,關鍵是1和4。
問這個原理性的問題,其實你能夠結合着圖來給面試官講這個問題,邊畫圖邊講最有說服力,面試官在內心會給你默默地豎起大拇指。
1)文件事件處理器
Redis基於Reactor模式開發了網絡事件處理器,這個處理器叫作文件事件處理器 file event handler。這個文件事件處理器,它是單線程的,因此 Redis 才叫作單線程的模型,它採用IO多路複用機制來同時監聽多個Socket,根據Socket上的事件類型來選擇對應的事件處理器來處理這個事件。
若是被監聽的 Socket 準備好執行accept、read、write、close等操做的時候,跟操做對應的文件事件就會產生,這個時候文件事件處理器就會調用以前關聯好的事件處理器來處理這個事件。
文件事件處理器是單線程模式運行的,可是經過IO多路複用機制監聽多個Socket,能夠實現高性能的網絡通訊模型,又能夠跟內部其餘單線程的模塊進行對接,保證了 Redis 內部的線程模型的簡單性。
文件事件處理器的結構包含4個部分:多個Socket、IO多路複用程序、文件事件分派器以及事件處理器(命令請求處理器、命令回覆處理器、鏈接應答處理器等)。
多個 Socket 可能併發的產生不一樣的操做,每一個操做對應不一樣的文件事件,可是IO多路複用程序會監聽多個 Socket,會將 Socket 放入一個隊列中排隊,每次從隊列中取出一個 Socket 給事件分派器,事件分派器把 Socket 給對應的事件處理器。
而後一個 Socket 的事件處理完以後,IO多路複用程序纔會將隊列中的下一個 Socket 給事件分派器。文件事件分派器會根據每一個 Socket 當前產生的事件,來選擇對應的事件處理器來處理。
2)文件事件
當 Socket 變得可讀時(好比客戶端對redis執行write操做,或者close操做),或者有新的能夠應答的 Sccket 出現時(客戶端對redis執行connect操做),Socket就會產生一個AE_READABLE事件。
當 Socket 變得可寫的時候(客戶端對redis執行read操做),Socket 會產生一個AE_WRITABLE事件。
IO 多路複用程序能夠同時監聽 AE_REABLE 和 AE_WRITABLE 兩種事件,若是一個Socket同時產生了這兩種事件,那麼文件事件分派器優先處理 AE_READABLE 事件,而後纔是 AE_WRITABLE 事件。
3)文件事件處理器
若是是客戶端要鏈接redis,那麼會爲 Socket 關聯鏈接應答處理器。
若是是客戶端要寫數據到redis,那麼會爲 Socket 關聯命令請求處理器。
若是是客戶端要從redis讀數據,那麼會爲 Socket 關聯命令回覆處理器。
4)客戶端與redis通訊的一次流程
在 Redis 啓動初始化的時候,Redis 會將鏈接應答處理器跟 AE_READABLE 事件關聯起來,接着若是一個客戶端跟Redis發起鏈接,此時會產生一個 AE_READABLE 事件,而後由鏈接應答處理器來處理跟客戶端創建鏈接,建立客戶端對應的 Socket,同時將這個 Socket 的 AE_READABLE 事件跟命令請求處理器關聯起來。
當客戶端向Redis發起請求的時候(不論是讀請求仍是寫請求,都同樣),首先就會在 Socket 產生一個 AE_READABLE 事件,而後由對應的命令請求處理器來處理。這個命令請求處理器就會從Socket中讀取請求相關數據,而後進行執行和處理。
接着Redis這邊準備好了給客戶端的響應數據以後,就會將Socket的AE_WRITABLE事件跟命令回覆處理器關聯起來,當客戶端這邊準備好讀取響應數據時,就會在 Socket 上產生一個 AE_WRITABLE 事件,會由對應的命令回覆處理器來處理,就是將準備好的響應數據寫入 Socket,供客戶端來讀取。
命令回覆處理器寫完以後,就會刪除這個 Socket 的 AE_WRITABLE 事件和命令回覆處理器的關聯關係。
1)純內存操做
Redis 將全部數據放在內存中,內存的響應時長大約爲 100 納秒,這是 redis 的 QPS 過萬的重要基礎。
2)核心是基於非阻塞的IO多路複用機制
有了非阻塞 IO 意味着線程在讀寫 IO 時能夠沒必要再阻塞了,讀寫能夠瞬間完成而後線程能夠繼續幹別的事了。
redis 須要處理多個 IO 請求,同時把每一個請求的結果返回給客戶端。因爲 redis 是單線程模型,同一時間只能處理一個 IO 事件,因而 redis 須要在合適的時間暫停對某個 IO 事件的處理,轉而去處理另外一個 IO 事件,這就須要用到IO多路複用技術了, 就比如一個管理者,可以管理個socket的IO事件,當選擇了哪一個socket,就處理哪一個socket上的 IO 事件,其餘 IO 事件就暫停處理了。
3)單線程反而避免了多線程的頻繁上下文切換帶來的性能問題。(百度多線程上下文切換)
第一,單線程能夠簡化數據結構和算法的實現。併發數據結構實現不但困難並且開發測試比較麻
第二,單線程避免了線程切換和競態產生的消耗,對於服務端開發來講,鎖和線程切換一般是性能殺手。
單線程的問題:對於每一個命令的執行時間是有要求的。若是某個命令執行過長,會形成其餘命令的阻塞,因此 redis 適用於那些須要快速執行的場景。
本系列文章在於面試突擊,不是教程,要是細挖,Redis線程模型能講好多,而面試你只須要把這個原理說出來就好了。該系列文章在於快速突擊,快速拾遺,溫習。
以爲好看,請點贊哦~
歡迎支持,歡迎關注