Redis常見面試題連環問,你能回答到第幾問?(中)

 

​上次的Redis連環問問到了Redis是什麼,Redis支持的數據類型和緩存雪崩緩存穿透緩存擊穿。

 

 

Redis常見面試題連環問,你能回答到第幾問?(上)

Redis常見面試題連環問,你能回答到第幾問?(中)

Redis常見面試題連環問,你能回答到第幾問?(下)

 

 

這次來繼續問:

 

  • Redis爲什麼這麼快?

  • Redis和memcache的區別?

  • 內存過期策略和淘汰策略?

  • 數據如何持久化?

     

  • Redis爲何這麼快?

 

面試官:redis作爲緩存大家都在用,那redis一定很快咯?

 

我:當然了,官方提供的數據可以達到100000+的QPS(每秒內的查詢次數),這個數據不比Memcached差!

 

面試官:redis這麼快,它的“多線程模型”你瞭解嗎?(露出邪魅一笑)

 

我:您是想問Redis這麼快,爲什麼還是單線程的吧。Redis確實是單進程單線程的模型,因爲Redis完全是基於內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬。既然單線程容易實現,而且CPU不會成爲瓶頸,那就順理成章的採用單線程的方案了(畢竟採用多線程會有很多麻煩)。

 

面試官:嗯,是的。那你能說說Redis是單線程的,爲什麼還能這麼快嗎?

 

我:可以這麼說吧。

  • 第一:Redis完全基於內存,絕大部分請求是純粹的內存操作,非常迅速,數據存在內存中,類似於HashMap,HashMap的優勢就是查找的操作的時間複雜度是O(1)。

  • 第二:數據結構簡單,對數據操作也簡單。

  • 第三:採用單線程,避免了不必要的上下文切換和競爭條件,不存在多線程導致的CPU切換,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有死鎖問題導致的性能消耗。

  • 第四:使用多路複用非阻塞IO模型。

     

分析:這個問題其實是對redis內部機制的一個考察。

 

題外話:我們現在要仔細的說一說I/O多路複用機制,因爲這個說法實在是太通俗了,通俗到一般人都不懂是什麼意思。

 

博主打一個比方:小曲在S城開了一家快遞店,負責同城快送服務。小曲因爲資金限制,僱傭了一批快遞員,然後小曲發現資金不夠了,只夠買一輛車送快遞。

 

經營方式一:

客戶每送來一份快遞,小曲就讓一個快遞員盯着,然後快遞員開車去送快遞。一個快遞對應一個快遞員。

 

慢慢的小曲就發現了這種經營方式存在下述問題:

 

幾十個快遞員基本上時間都花在了排隊等車上了,大部分快遞員都處在閒置狀態,誰搶到了車,誰就能去送快遞。隨着快遞的增多,快遞員也越來越多,小曲發現快遞店裏越來越擠,沒辦法僱傭新的快遞員了。而且快遞員之間的協調很花時間。

 

綜合上述缺點,小曲痛定思痛,提出了下面的經營方式。

 

經營方式二:

小曲只僱傭一個快遞員。然後呢,客戶送來的快遞,小曲按送達地點標註好,然後依次放在一個地方。最後,那個快遞員依次的去取快遞,一次拿一個,然後開着車去送快遞,送好了就回來拿下一個快遞。

 

對比上述兩種經營方式對比,是不是明顯覺得第二種,效率更高,更好呢。
當然這只是按redis做的一個比喻,如果誰家開快遞真的這樣做恐怕造就倒閉了。

 

在上述比喻中:

每個快遞員------------------>每個線程
每個快遞-------------------->每個socket(I/O流)
快遞的送達地點-------------->socket的不同狀態
客戶送快遞請求-------------->來自客戶端的請求
小曲的經營方式-------------->服務端運行的代碼

一輛車---------------------->CPU的核數

 

於是我們有如下結論:

1、經營方式一就是傳統的併發模型,每個I/O流(快遞)都有一個新的線程(快遞員)管理。
2、經營方式二就是I/O多路複用。只有單個線程(一個快遞員),通過跟蹤每個I/O流的狀態(每個快遞的送達地點),來管理多個I/O流。

下面類比到真實的redis線程模型,如圖所示

 

參照上圖,可知redis-client在操作的時候,會產生具有不同事件類型的socket。在服務端,有一段I/0多路複用程序,將其置入隊列之中。然後,文件事件分派器,依次去隊列中取,轉發到不同的事件處理器中。

需要說明的是,這個I/O多路複用機制,redis還提供了select、epoll、evport、kqueue等多路複用函數庫,大家可以自行去了解。


 

  • Redis和Memcached的區別

 

面試官:嗯嗯,說的很詳細。那你爲什麼選擇Redis的緩存方案而不用memcached呢?


1、存儲方式上:memcache會把數據全部存在內存之中,斷電後會掛掉,數據不能超過內存大小。redis有部分數據存在硬盤上,這樣能保證數據的持久性。
2、數據支持類型上:memcache對數據類型的支持簡單,只支持簡單的key-value,,而redis支持五種數據類型。
3、使用底層模型不同:它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣。redis直接自己構建了VM機制,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
4、value的大小:redis可以達到512M,而memcache只有1MB。
更詳細的區別可以參考我上一篇文章:說說Redis和memcache有什麼區別與不同?

 

  • 內存淘汰策略

 

在內存淘汰之前redis有個內存過期策略。Redis使用的是定期刪除+惰性刪除策略。


定期刪除,redis默認每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,redis不是每個100ms將所有的key檢查一次,而是隨機抽取進行檢查(如果每隔100ms,全部key進行檢查,redis豈不是卡死)。因此,如果只採用定期刪除策略,會導致很多key到時間沒有刪除。


於是,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key如果設置了過期時間那麼是否過期了?如果過期了此時就會刪除。


採用定期刪除+惰性刪除就沒其他問題了麼?

 

不是的,如果定期刪除沒刪除key。然後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會越來越高。那麼就應該採用內存淘汰機制。

 

面試官:那你說說你知道的redis的淘汰策略有哪些?

 

我:Redis有六種淘汰策略

策略 描述
volatile-lru 從已設置過期時間的KV集中優先對最近最少使用(less recently used)的數據淘汰
volitile-ttl 從已設置過期時間的KV集中優先對剩餘時間短(time to live)的數據淘汰
volitile-random 從已設置過期時間的KV集中隨機選擇數據淘汰
allkeys-lru 從所有KV集中優先對最近最少使用(less recently used)的數據淘汰
allKeys-random 從所有KV集中隨機選擇數據淘汰
noeviction 不淘汰策略,若超過最大內存,返回錯誤信息,一般沒人用。

 

補充一下:Redis4.0加入了LFU(least frequency use)淘汰策略,包括volatile-lfu和allkeys-lfu,通過統計訪問頻率,將訪問頻率最少,即最不經常使用的KV淘汰。

 

  • 數據持久化

     

面試官:你對redis的持久化機制瞭解嗎?能講一下嗎?

 

我:redis爲了保證效率,數據緩存在了內存中,但是會週期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件中,以保證數據的持久化。


Redis的持久化策略有兩種:
1、RDB:快照形式會在指定的時間間隔能對你的數據進行快照存儲。
2、AOF:把所有的對Redis的服務器進行修改的命令都存到一個文件裏,命令的集合。

 

Redis默認是快照RDB的持久化方式。寫操作命令記錄的格式跟Redis協議一致,以追加的方式進行保存。

當Redis重啓的時候,它會優先使用AOF文件來還原數據集,因爲AOF文件保存的數據集通常比RDB文件所保存的數據集更完整。

持久化策略可以禁用,兩種策略也可以共存。

 

面試官:那你再說下RDB是怎麼工作的?

 

我:默認Redis是會以快照"RDB"的形式將數據持久化到磁盤的一個二進制文件dump.rdb。工作原理簡單說一下:當Redis需要做持久化時,Redis會fork一個子進程,子進程將數據寫到磁盤上一個臨時RDB文件中。當子進程完成寫臨時文件後,將原來的RDB替換掉,這樣的好處是可以copy-on-write。

 

RDB的優點是:這種文件非常適合用於備份:比如,你可以在最近的24小時內,每小時備份一次,並且在每個月的每一天也備份一個RDB文件。這樣的話,即使遇上問題,也可以隨時將數據集還原到不同的版本。RDB非常適合災難恢復。
RDB的缺點是:RDB容易造成數據的丟失。如果你需要儘量避免在服務器故障時丟失數據,那麼RDB不合適你。如果數據量比較大的話還有可能導致redis停止服務幾毫秒。

 

面試官:那你要不再說下AOF ?

 

我:(說就一起說下吧)使用AOF做持久化,每一個寫命令都通過write函數追加到appendonly.aof中,配置方式如下:

AOF可以做到全程持久化,只需要在配置中開啓 appendonly yes。這樣redis每執行一個修改數據的命令,都會把它添加到AOF文件中,當redis重啓時,將會讀取AOF文件進行重放,恢復到redis關閉前的最後時刻。

 

我頓了一下,繼續說:使用AOF的優點是會讓redis變得非常耐久。可以設置不同的fsync策略,aof的默認策略是每秒鐘fsync一次,在這種配置下,就算髮生故障停機,也最多丟失一秒鐘的數據。缺點是對於相同的數據集來說,AOF的文件體積通常要大於RDB文件的體積。根據所使用的fsync策略,AOF的速度可能會慢於RDB。而在禁止fsync的情況下速度可以達到RDB的水平。

 

面試官又問:你說了這麼多,那我該用哪一個呢?

 

我:如果你非常關心你的數據,但仍然可以承受數分鐘內的數據丟失,那麼可以額只使用RDB持久。AOF將Redis執行的每一條命令追加到磁盤中,處理巨大的寫入會降低Redis的性能,不知道你是否可以接受。


數據庫備份和災難恢復:定時生成RDB快照非常便於進行數據庫備份,並且RDB恢復數據集的速度也要比AOF恢復的速度快。當然了,redis支持同時開啓RDB和AOF,系統重啓後,redis會優先使用AOF來恢復數據,這樣丟失的數據會最少。

 

這期就講到這裏,下期繼續。

 

                                                        

發佈了51 篇原創文章 · 獲贊 85 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章