突破Java面試(20)-Redis執行緒模型

firefule發表於2021-09-09

1 面試題

redis和memcached有什麼區別?redis的執行緒模型是什麼?為什麼單執行緒的redis比多執行緒的memcached效率要高得多(為什麼redis是單執行緒的但是還可以支撐高併發)?

2 考點分析

這個是問redis的時候,最基本的問題,redis最基本的一個內部原理和特點,就是redis實際上是個單執行緒工作模型,你要是這個都不知道,那後面玩兒redis的時候,出了問題豈不是什麼都不知道?

還有可能面試官會問問你redis和memcached的區別,不過說實話,最近這兩年,作為面試官都不太喜歡這麼問了,memched是早些年各大網際網路公司常用的快取方案,但是現在近幾年基本都是redis,沒什麼公司用memcached了

同學,你要是現在還不知道redis和memcached是啥?那你趕緊百度一下redis入門和memcahced入門,簡單啟動一下,然後試一下幾個簡單操作,先感受一下。接著回來繼續看,我覺得1小時以內你就搞定了。
要聽明白redis的執行緒模型,你需要了解socket網路相關的基本知識,如果不懂,那我覺得你java沒學好吧。初學者都該學習java的socket網路通訊相關知識

4 詳解

4.1 redis和memcached的區別

這個事兒吧,你可以比較出N多個區別來,但是我還是採取redis作者給出的幾個比較吧

4.1.1 Redis支援伺服器端的資料操作

Redis相比Memcached來說,擁有更多的資料結構和並支援更豐富的資料操作

  • 通常在Memcached裡,你需要將資料拿到客戶端來進行類似的修改再set回去,這大大增加了網路IO的次數和資料體積
  • 在Redis中,這些複雜的操作通常和一般的GET/SET一樣高效。所以,如果需要快取能夠支援更復雜的結構和操作,那麼Redis會是不錯的選擇。

4.1.2 記憶體使用效率對比

使用簡單的KV儲存的話,Memcached的記憶體利用率更高,而如果Redis採用hash結構來做key-value儲存,由於其組合式的壓縮,其記憶體利用率會高於Memcached。

4.1.3 效能對比

  • Redis只使用單核
  • Memcached可以使用多核

所以平均每一個核上Redis在儲存小資料時比Memcached效能更高
而在100k以上的資料中,Memcached效能要高於Redis,雖然Redis最近也在儲存大資料的效能上進行最佳化,但是比起Memcached,稍有遜色。

4.1.4 叢集模式

  • memcached沒有原生的叢集模式,需要依靠客戶端來實現往叢集中分片寫入資料
  • 但是redis目前是原生支援cluster模式的,redis官方就是支援redis cluster叢集模式的,比memcached來說要更好

4.2 Redis的執行緒模型

圖片描述

4.2.1 檔案事件處理器

redis基於reactor模式開發了網路事件處理器,這個處理器叫做檔案事件處理器,file event handler

這個檔案事件處理器,是單執行緒的,redis才叫做單執行緒的模型,採用IO多路複用機制同時監聽多個socket,根據socket上的事件來選擇對應的事件處理器來處理這個事件。

如果被監聽的socket準備好執行acceptreadwriteclose等操作時,跟操作對應的檔案事件就會產生,這個時候檔案事件處理器就會呼叫之前關聯好的事件處理器來處理對應事件。

檔案事件處理器是單執行緒模式執行的,但是透過IO多路複用機制監聽多個socket,實現高效能的網路通訊模型,又可以跟內部其他單執行緒的模組進行對接,保證了redis內部的執行緒模型的簡單性。

檔案事件處理器的結構包含4個部分

  • 多個socket
  • IO多路複用程式
  • 檔案事件分派器
  • 事件處理器(命令請求處理器、命令回覆處理器、連線應答處理器,等等)

多個socket可能併發的產生不同的操作,每個操作對應不同的檔案事件,但是IO多路複用程式會監聽多個socket,但是會將socket放入一個佇列中排隊,每次從佇列中取出一個socket給事件分派器,事件分派器把socket給對應的事件處理器。

然後一個socket的事件處理完之後,IO多路複用程式才會將佇列中的下一個socket給事件分派器。檔案事件分派器會根據每個socket當前產生的事件,來選擇對應的事件處理器來處理。

4.2.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兩種事件,那麼檔案事件分派器優先處理AE_REABLE事件,然後才是AE_WRITABLE事件。

4.2.3 檔案事件處理器

如果是客戶端要連線redis,那麼會為socket關聯連線應答處理器
如果是客戶端要寫資料到redis,那麼會為socket關聯命令請求處理器
如果是客戶端要從redis讀資料,那麼會為socket關聯命令回覆處理器

4.2.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事件和命令回覆處理器的關聯關係。

4.3 redis的單執行緒模型為何效率高

  • 純記憶體操作
  • 核心是基於非阻塞的IO多路複用機制
  • 單執行緒反而避免了多執行緒的頻繁上下文切換問題

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1834/viewspace-2822856/,如需轉載,請註明出處,否則將追究法律責任。

相關文章