超詳細的Redis面試題目(持續更新)

1. 什麼是 Redis?

Redis 本質上是一個 Key-Value 類型的內存數據庫,很像 memcached,整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據 flush 到硬盤上進行保存。因爲是純內存操作,Redis 的性能非常出色,每秒可以處理超過 10 萬次讀寫操作,是已知性能最快的 Key-Value DB。 Redis 的出色之處不僅僅是性能,Redis 最大的魅力是支持保存多種數據結構,此外單個 value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的數據,因此 Redis 可以用來實現很多有用的功能,比方說用他的 List 來做 FIFO 雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的 Set 可以做高性能的 tag 系統等等。另外 Redis 也可以對存入的 Key-Value 設置 expire 時間,因此也可以被當作一 個功能加強版的 memcached 來用。 Redis 的主要缺點是數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此 Redis 適合的場景主要侷限在較小數據量的高性能操作和運算上。


2. Redis 有哪些數據結構?

  • String 字符串:string 類型是二進制安全的。意思是 redis 的 string 可以包含任何數據。比如 jpg 圖片或者序列化的對象 。string 類型是 Redis 最基本的數據類型,一個鍵最大能存儲 512MB。

  • Hash(哈希):Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用於存儲對象。

  • List(列表):Redis 列表是簡單的字符串列表,按照插入順序排序。

  • Set(集合):Redis 的 Set 是 string 類型的無序集合。集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是 O (1)。

  • zset (sorted set:有序集合):Redis zset 和 set 一樣也是 string 類型元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個 double 類型的分數。redis 正是通過分數來爲集合中的成員進行從小到大的排序。


3. Redis 爲什麼是單線程的?

因爲 CPU 不是 Redis 的瓶頸。Redis 的瓶頸最有可能是機器內存或者網絡帶寬。(以上主要來自官方 FAQ)既然單線程容易實現,而且 CPU 不會成爲瓶頸,那就順理成章地採用單線程的方案了。


4. 使用 Redis 有哪些好處?

(1) 速度快,因爲數據存在內存中,類似於 HashMap,HashMap 的優勢就是查找和操作的時間複雜度都是 O (1)
(2) 支持豐富數據類型,支持 string,list,set,sorted set,hash
(3) 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要麼全部執行,要麼全部不執行
(4) 豐富的特性:可用於緩存,消息,按 key 設置過期時間,過期後將會自動刪除


5. Redis 相比 memcached 有哪些優勢?

(1) memcached 所有的值均是簡單的字符串,redis 作爲其替代者,支持更爲豐富的數據類型
(2) redis 的速度比 memcached 快很多
(3) redis 可以持久化其數據
(4) Redis 支持數據的備份,即 master-slave 模式的數據備份
(5) 使用底層模型不同
它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。
Redis 直接自己構建了 VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
(6)value 大小:redis 最大可以達到 1GB,而 memcache 只有 1MB


6.使用過 Redis 分佈式鎖麼,它是什麼回事?

先拿 setnx 來爭搶鎖,搶到之後,再用 expire 給鎖加一個過期時間防止鎖忘記了釋放。

如果在 setnx 之後執行 expire 之前進程意外 crash 或者要重啓維護了,那會怎麼樣?

set 指令有非常複雜的參數,這個應該是可以同時把 setnx 和 expire 合成一條指令來用的!


7. Redis 如何做持久化的?

Redis有兩種持久化方式:

  • RDB 持久化:redis 提供了 RDB 持久化的功能,這個功能可以將 redis 在內存中的的狀態保存到硬盤中,它可以手動執行,也可以再 redis.conf 中配置,定期執行。RDB 持久化產生的 RDB 文件是一個經過壓縮的二進制文件,這個文件被保存在硬盤中,redis 可以通過這個文件還原數據庫當時的狀態。

  • AOF 持久化:AOF 持久化(Append-Only-File),與 RDB 持久化不同,AOF 持久化是通過保存 Redis 服務器鎖執行的寫狀態來記錄數據庫的。具體來說,RDB 持久化相當於備份數據庫狀態,而 AOF 持久化是備份數據庫接收到的命令,所有被寫入 AOF 的命令都是以 redis 的協議格式來保存的。在 AOF 持久化的文件中,數據庫會記錄下所有變更數據庫狀態的命令,除了指定數據庫的 select 命令,其他的命令都是來自 client 的,這些命令會以追加 (append) 的形式保存到文件中。

  • 對比:
    AOF 更安全,可將數據及時同步到文件中,但需要較多的磁盤 IO,AOF 文件尺寸較大,文件內容恢復相對較慢,也更完整。
    RDB 持久化,安全性較差,它是正常時期數據備份及 master-slave 數據同步的最佳手段,文件尺寸較小,恢復數度較快。

RDB的實現方式有兩種:SAVE和BGSAVE

  • SAVE 直接調用 rdbSave ,阻塞 Redis 主進程,直到保存完成爲止。在主進程阻塞期間,服務器不能處理客戶端的任何請求。
  • BGSAVE 則 fork 出一個子進程,子進程負責調用 rdbSave ,並在保存完成之後向主進程發送信號,通知保存已完成。 Redis 服務器在 BGSAVE 執行期間仍然可以繼續處理客戶端的請求。BGSAVE 命令執行之後立即返回 OK ,然後 Redis fork 出一個新子進程,原來的 Redis 進程 (父進程) 繼續處理客戶端請求,而子進程則負責將數據保存到磁盤,然後退出。

如果突然機器掉電AOF持久化會怎樣?

  • 取決於 aof 日誌 sync 屬性的配置,如果不要求性能,在每條寫指令時都 sync 一下磁盤,就不會丟失數據。但是在高性能的要求下每次都 sync 是不現實的,一般都使用定時 sync,比如 1s1 次,這個時候最多就會丟失 1s 的數據。

8.假如 Redis 裏面有 1 億個 key,其中有 10w 個 key 是以某個固定的已知的前綴開頭的,如果將它們全部找出來?

  • 使用 keys 指令可以掃出指定模式的 key 列表

對方接着追問:如果這個 redis 正在給線上的業務提供服務,那使用 keys 指令會有什麼問題?

這個時候你要回答 redis 關鍵的一個特性:redis 的單線程的。keys 指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用 scan 指令,scan 指令可以無阻塞的提取出指定模式的 key 列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用 keys 指令長。


9.如果有大量的 key 需要設置同一時間過期,一般需要注意什麼?

如果大量的 key 過期時間設置的過於集中,到過期的那個時間點,redis 可能會出現短暫的卡頓現象(緩存雪崩)。一般需要在時間上加一個隨機值,使得過期時間分散一些。


10.什麼是緩存穿透?如何避免?

一般的緩存系統,都是按照 key 去緩存查詢,如果不存在對應的 value,就應該去後端系統查找(比如 DB)。一些惡意的請求會故意查詢不存在的 key, 請求量很大,就會對後端系統造成很大的壓力。這就叫做緩存穿透。

如何避免?

  • 對查詢結果爲空的情況也進行緩存,緩存時間設置短一點,或者該 key 對應的數據 insert 了之後清理緩存。

  • 對一定不存在的 key 進行過濾。可以把所有的可能存在的 key 放到一個大的 Bitmap 中,查詢時通過該 bitmap 過濾。


11.什麼是緩存雪崩?如何避免?

當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給後端系統帶來很大壓力。導致系統崩潰。

如何避免?

1:在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個 key 只允許一個線程查詢數據和寫緩存,其他線程等待。

2:做二級緩存,A1 爲原始緩存,A2 爲拷貝緩存,A1 失效時,可以訪問 A2,A1 緩存失效時間設置爲短期,A2 設置爲長期

3:不同的 key,設置不同的過期時間,讓緩存失效的時間點儘量均勻。


12.Redis 有哪些架構模式?講講各自的特點

(1)單機版

特點:內存容量有限 、處理能力有限、無法高可用。

(2)主從複製、讀寫分離

Redis 的複製(replication)功能允許用戶根據一個 Redis 服務器來創建任意多個該服務器的複製品,其中被複制的服務器爲主服務器(master),而通過複製創建出來的服務器複製品則爲從服務器(slave)。 只要主從服務器之間的網絡連接正常,主從服務器兩者會具有相同的數據,主服務器就會一直將發生在自己身上的數據更新同步 給從服務器,從而一直保證主從服務器的數據相同。

特點:master/slave 數據相同、降低 master 讀壓力在轉交從庫

問題:沒有解決 master 寫的壓力

(3)哨兵

Redis sentinel 是一個分佈式系統中監控 redis 主從服務器,並在主服務器下線時自動進行故障轉移。

特點:

  • 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。

  • 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知

  • 自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作。

缺點:沒有解決 master 寫的壓力

(4)集羣

特點:

  • 無中心架構(不存在哪個節點影響性能瓶頸)。

  • 數據按照 slot 存儲分佈在多個節點,節點間數據共享,可動態調整數據分佈。

  • 可擴展性,可線性擴展到 1000 個節點,節點可動態添加或刪除。

  • 高可用性,部分節點不可用時,集羣仍可用。通過增加 Slave 做備份數據副本

  • 實現故障自動 failover,節點之間通過 gossip 協議交換狀態信息,用投票機制完成 Slave 到 Master 的角色提升。


13.Redis 爲什麼這麼快?

  • 純內存數據庫,避免了磁盤 I/O 的瓶頸。
  • 單進程單線程,減少了線程上下文切換的開銷。
  • 利用隊列技術將並行訪問變爲串行訪問,消除了傳統數據庫併發訪問控制鎖的開銷。
  • Redis 全程使用 hash 結構,讀取速度快,還有一些特殊的數據結構,對數據存儲進行了優化,如壓縮表,對短數據進行壓縮存儲,再如,跳錶,使用有序的數據結構加快讀取的速度。
  • 使用多路 I/O 複用模型,非阻塞 I/O。

多路 I/O 複用模型:

  • 多路 I/O 複用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閒的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程序就會輪詢一遍所有的流(epoll 是隻輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。
  • 這裏 “多路” 指的是多個網絡連接,“複用” 指的是複用同一個線程。採用多路 I/O 複用技術可以讓單個線程高效的處理多個連接請求(儘量減少網絡 IO 的時間消耗),且 Redis 在內存中操作數據的速度非常快,也就是說內存內的操作不會成爲影響 Redis 性能的瓶頸。

14.AOF持久化方式存儲的內容,格式是什麼?

(1)在 AOF 持久化的文件中,數據庫會記錄下所有變更數據庫狀態的命令

內容是 redis 通訊協議 (RESP ) 格式的命令文本存儲。

(2)什麼是 RESP?有什麼特點?

RESP 是 redis 客戶端和服務端之前使用的一種通訊協議;

RESP 的特點:實現簡單、快速解析、可讀性好

  • For Simple Strings the first byte of the reply is “+” 回覆

  • For Errors the first byte of the reply is “-” 錯誤

  • For Integers the first byte of the reply is “:” 整數

  • For Bulk Strings the first byte of the reply is “$” 字符串

  • For Arrays the first byte of the reply is “*” 數組


15.Redis 常見的性能問題和解決方法?

  • Master寫內存快照:save命令調度rdbSave函數,會阻塞主線程的工作,當快照比較大時對性能影響是非常大的,會間斷性暫停服務,所以Master最好不要寫內存快照。
  • Master AOF持久化:如果不重寫AOF文件,這個持久化方式對性能的影響是最小的,但是AOF文件會不斷增大,AOF文件過大會影響Master重啓的恢復速度。
  • Redis主從複製的性能問題:第一次Slave向Master同步的實現是:Slave向Master發出同步請求,Master先dump出rdb文件,然後將rdb文件全量傳輸給slave,然後Master把緩存的命令轉發給Slave,初次同步完成。第二次以及以後的同步實現是:Master將變量的快照直接實時依次發送給各個Slave。不管什麼原因導致Slave和Master斷開重連都會重複以上過程。Redis的主從複製是建立在內存快照的持久化基礎上,只要有Slave就一定會有內存快照發生。雖然Redis宣稱主從複製無阻塞,但由於Redis使用單線程服務,如果Master快照文件比較大,那麼第一次全量傳輸會耗費比較長時間,且文件傳輸過程中Master可能無法提供服務,也就是說服務會中斷,對於關鍵服務,這個後果也是很可怕的。
  • 根本問題的原因都離不開系統io瓶頸問題,也就是硬盤讀寫速度不夠快,主進程 fsync()/write() 操作被阻塞。

16.Redis淘汰策略

大家可以想想,當我們的物理服務內存只有8G,但是數據卻有100G,如何慢慢的放在redis中呢?再加上公司近期資金不夠,不能擴展機器怎麼辦?就需要淘汰已有數據

  • voltile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
  • volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
  • volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
  • allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
  • allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
  • no-enviction(驅逐):禁止驅逐數據

17.redis 有哪些功能?

  • 全頁面緩存:整頁緩存。如果你正在使用服務器端呈現的內容,則不需要爲每個單獨的請求重新渲染每個頁面。使用如Redis這樣的緩存,你可以緩存經常請求的內容,從而大大減少請求最多的頁面的延遲,並且大多數框架針對Redis緩存頁面都有hooks。

  • 順序排列:由於Redis在內存中Set數據結構可以非常快速和高效進行遞增和遞減,性能遠遠高於SQL查詢。比較這與Redis的排序集相結合意味着你可以以毫秒爲單位抓取列表中評分最高的項目,而且實現起來非常容易。

    • 利用zset類型可以存儲排行榜

    • 利用list的自然時間排序存儲最新n個數據

  • 會話Session存儲:Redis最常見的用途是會話存儲。與其他會話存儲(如Memcache)不同,Redis可以保留數據,以便在緩存停止的情況下,在重新啓動時,所有數據仍然存在。

  • 隊列:使用Redis可以做的一個不太常見,但非常有用的事情是排隊。無論是電子郵件隊列還是其他應用程序使用的數據,你都可以在Redis中創建一個高效的隊列。任何熟悉堆棧以及會push和pop項目的開發人員都可以輕鬆自然地使用此功能。

  • 配合關係型數據庫做高速緩存


【Java 面試那點事】

這裏致力於分享 Java 面試路上的各種知識,無論是技術還是經驗,你需要的這裏都有!

這裏可以讓你【快速瞭解 Java 相關知識】,並且【短時間在面試方面有跨越式提升】

面試路上,你不孤單!
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章