面試都說自己會Redis,看看這些問題都學廢了嗎?

本文問題總結:來自於,慕課網《Java架構師成長直通車》第八週第1-8節的彙總
本文問題參考回答:來自博主自己的學習筆記和瘋狂的Google現學的,由於學的不多瞭解有限,參考回答表述不正確的歡迎提出,共同進步。

文章目錄

1. 什麼是Redis?

  • Redis是一個高性能的key-values形式存儲的分佈式緩存中間件
  • 支持豐富的數據結構(五種):String、List、Set、Zset、Hash
  • 數據對象存儲在內存中,讀寫非常快
  • 單線程且所有操作都是原子操作

2. Redis的全稱是什麼

  • Remote Dictionary Server (遠程 字典 服務器)

3. Redis的數據類型?

  • String(字符串)

  • Hash(哈希)

  • List(列表)

  • Zset(有序集合)

  • Set(集合)

4. 使用Redis有哪些好處?

  • 數據存儲在內存中,讀寫速度快
  • 支持豐富的數據類型
  • 支持事務,操作都是原子操作
  • 豐富的特性:可用於緩存,消息,按key設置過期時間

5. Redis相比Memcache有哪些好處?

  • Redis與Memcache相比擁有更豐富的數據類型

    • Memcache只支持簡單的String類型的Key-value存儲,
    • Redis支持五種數據類型:String、List、Hash、Set、Zset
  • Redis支持數據持久化,重啓後可以從磁盤重新加載

  • Redis支持Master-slave模式的數據備份

6. Memcache和Redis的區別都有哪些?

  • Redis與Memcache相比擁有更豐富的數據類型
  • Redis支持數據持久化,Memcache不支持持久化
  • Redis支持Master-slave模式的數據備份,Memcache無法容災
  • Redis使用單核單線程,Memcache使用多核多線程

7. Redis是單進程單線程的嗎?爲什麼那麼快那麼高效?

  • Redis是單進程單線程的
  • 完全基於內存,絕大多數請求是純粹的內存操作,所以非常快速
  • 數據結構簡單,針對數據的操作也簡單
  • 單線程,避免不必要的上下文切換和競爭,不用考慮鎖的問題和死鎖問題
  • 多路I/O複用模型,非阻塞IO

8. 一個字符串類型的值能存儲最大容量是多少?

  • 一個鍵最大能存儲512M(官方給的)

9. Redis的持久化機制是什麼?各自的優缺點?

  • RDB(redis databases)

    • 把數據以快照的形式保存在磁盤上

    • 是Redis默認使用的持久化機制

      • 觸發方式

        • save觸發:該命令會阻塞當前Redis服務器,執行save命令期間,Redis不能處理其他命令,直到RDB過程完成爲止
        • bgsave觸發:進程執行fork操作子進程,然後由Redis會在後臺異步進行快照操作,快照同時還可以響應客戶端請求,阻塞只在fork創建子進程的短暫階段
      • 比較:

        • save是同步的線程阻塞的,不會消耗額外內存,缺點是阻塞客戶端
        • bgsave是異步的線程非阻塞的,不阻塞客戶端,缺點是fork會消耗內存
    • 配置文件參數

      • save: 如save 60 10000 表示60s內有10000個 key的值發生變化就觸發保存
      • stop-writes-on-bgsave-error:默認yes,RDB最後一次後臺保存數據失敗,Redis是否停止接收數據
      • rdbcompression:默認yes,設置快照壓縮存儲
      • rdbchecksum:默認yes ,設置開啓crc64校驗,影響性能
      • dbfilename:快照文件名
      • dir:快照文件存儲路徑
    • 優勢

      • RDB文件緊湊,全量備份,適用於備份和容災
      • RDB在恢復大數據集是速度比AOF快
      • RDB文件生成時主進程fork一個子進程進行操作,主進程不需要IO操作
    • 劣勢

      • RDB持久化期間主進程發生修改子進程不可見,可能造成持久化期間數據丟失
  • AOF

    • 通過追加日誌的方式存儲在磁盤上

    • 當接收到寫命令後將命令存儲到AOF文件中

    • 文件重寫機制

      • 持久化文件會變的越來越大。爲了壓縮aof的持久化文件。redis提供了bgrewriteaof命令。將內存中的數據以命令的方式保存到臨時文件中,同時會fork出一條新進程來將文件重寫。
      • 重寫過程不是讀舊的aof,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件
    • AOF觸發機制

      • always:每次發生數據變更都執行一次記錄,性能差,完整性能
      • everysec:每一秒發生一次記錄,宕機會丟失1s內數據
      • no:從不同步
    • 優勢

      • AOF可以更好的保護數據不丟失,一般AOF會每隔1秒,通過一個後臺線程執行一次fsync操作,最多丟失1秒鐘的數據。
      • AOF日誌文件沒有任何磁盤尋址的開銷,寫入性能非常高,文件不容易破損。
      • AOF日誌文件即使過大的時候,出現後臺重寫操作,也不會影響客戶端的讀寫。
      • 非常適合做緊急恢復和少量數據恢復
    • 劣勢

      • AOF文件比RDB大
      • AOF寫QPS會比RDB支持的寫QPS低
  • 比較
    還沒寫

10. Redis常見性能問題和解決方案有哪些?

  • Master最好不要做任何持久化工作,包括內存快照和AOF日誌文件,特別是不要啓用內存快照做持久化。

    • RDB方式如果使用save觸發會長時間阻塞主服務器
    • RDB方式如果使用bgsave觸發會產生子進程處理備份,會佔用CPU和內存,且生成子進程期間會造成主服務阻塞
    • AOF方式如果不重寫會導致文件過大影響Master重啓恢復速度
    • AOF方式如果重寫在重寫時會佔用大量CPU和內存資源
  • 主從之間的瓶頸在於IO瓶頸,爲了主從複製的速度和連接的穩定性,Slave和Master最好在同一個局域網內。

11. Redis過期鍵的刪除策略?

  • 主節點過期刪除策略

    • 定時刪除:在設置鍵的過期時間的同時,創建一個timer,讓定時器在鍵的過期時間到達時,立即執行對鍵的刪除操作。(主動刪除)

      • 對內存友好,對CPU時間不友好,短時間較多過期時會佔用較大的CPU時間
    • 定期刪除:每隔一段時間就對數據庫進行一次檢查,刪除裏面的過期鍵。(主動刪除)

      • 內存和CPU都折中友好的策略,每個一段時間執行一次刪除過期鍵操作,並通過限制操作執行的時長和頻率來減少對cpu時間的影響。難在選擇一個好的執行時長和執行頻率
    • 惰性刪除:放任過期鍵不管,但是每次從鍵空間中獲取鍵時,都檢查取到的鍵是否過期,如果過期就刪除,如果沒過期就返回該鍵。(被動刪除)

      • 對CPU友好,對內存不友好,如果不使用就會一直佔內存
  • 從節點過期刪除策略

    • AOF:過期鍵刪除後,AOF文件裏追加一條del指令,AOF文件同步到從節點後執行del指令刪除
    • RDB:過期鍵被過濾
    • 因爲AOF同步del指令是異步的,會導致主從節點的值不一致
    • 從節點不會主動掃描過期key,對於過期是被動的

12. Redis的回收策略(淘汰策略)?

  • noeviction: 不刪除策略, 達到最大內存限制時, 如果需要更多內存, 直接返回錯誤信息。大多數寫命令都會導致佔用更多的內存(有極少數會例外, 如 DEL )。
  • allkeys-lru: 所有key通用; 優先刪除最近最少使用(less recently used ,LRU) 的 key。
  • volatile-lru: 只限於設置了 expire 的部分; 優先刪除最近最少使用(less recently used ,LRU) 的 key。
  • allkeys-random: 所有key通用; 隨機刪除一部分 key。
  • volatile-random: 只限於設置了 expire 的部分; 隨機刪除一部分 key。* volatile-ttl: 只限於設置了 expire 的部分; 優先刪除剩餘時間(time to live,TTL) 短的key。

13. 爲什麼Redis需要把所有數據放入內存中?

  • Redis 爲了達到最快的讀寫速度將數據都讀到內存中,並通過異步的方式將數據寫入磁盤。所以 redis 具有快速和數據持久化的特徵。
  • 如果不將數據放在內存中,磁盤 I/O 速度爲嚴重影響 redis 的性能。在內存越來越便宜的今天,redis 將會越來越受歡迎。
  • 如果設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值。

14. Redis的同步機制瞭解嗎?

  • 全量同步

    • 將master本身的RDB文件同步給slave

      • 從節點連接到主節點,發送同步(SYNC)命令
      • 主節點開始執行BGSAVE,並用緩衝區記錄BGSAVE之後執行的所有命令
      • BGSAVE執行完成後主節點向從節點發送快照文件,發送期間繼續使用緩衝區記錄執行命令。從節點拋棄 所有舊數據,載入主節點發送的快照
      • 主節點快照發送完畢後,開始向從節點發送緩衝區中的寫命令。從節點完成對快照文件的解析後,開始接受命令請求
      • 主節點發送完緩衝區數據後,每執行一條寫命令都會向從節點發送相同的寫命令。從節點執行完了主節點緩衝區的命令後,接受之後發送的寫命令,並執行
    • 發生時機

      • redis slave首啓動或者重啓後,連接到master時
      • redis slave進程沒重啓,但是掉線了,重連後不滿足部分複製條件(傳輸偏移量不在緩衝區範圍內了)
    • 全局複製開銷

      • bgsave每次需要fork子進程,對內存和cup開銷大
      • RDB網絡傳輸耗時
      • 從節點清空數據的耗時
      • 從節點加載RDB的耗時
      • 如果設置了AOF會進行AOF重寫,重寫耗時
  • 部分同步

    • 當master和slave斷開連接時,master會將期間所做的操作記錄到複製緩存區當中(可以看成是一個隊列,其大小默認1M)。

    • 待slave重連後,slave會向master發送psync命令並傳入offset和runId,並進行判斷

      • 如果從節點的run id和主節點的run id一致
      • 如果master發現slave傳輸的偏移量的值,在緩存區隊列範圍中,
    • 就會將從offset開始到隊列結束的數據傳給slave,從而達到同步,降低了使用全量複製的開銷。

  • 無磁盤化同步(測試運行階段)

    • 不依賴與硬盤性能
    • 直接在內存中創建rdb,然後發送給slave

15. Pipeline(管道)有什麼好處?爲什麼要用Pipeline?

  • 多個指令之間沒有依賴關係,可以使用 pipeline 一次性執行多個指令,減少 IO,縮減時間。

16. 是否使用過Redis集羣,集羣的原理是什麼?

  • 原理:分庫分表,去中心化
  • 分庫分表:使用hash槽,每個節點維護部分槽及槽所映射的鍵值數據
  • 去中心化:每個Master節點都有一個或多個Slave節點。集羣中所有的Master節點都可以進行讀寫數據,不分主次
  • 主從集羣
  • 加哨兵的主從集羣
  • Cluster集羣

17. Redis集羣方案什麼情況下會導致整個集羣不可用?

  • 如果集羣任意master掛掉,且當前master沒有slave.集羣進入fail狀態,也可以理解成集羣的slot映射[0-16383]不完成時進入fail狀態
  • 如果集羣超過半數以上master掛掉,無論是否有slave集羣進入fail狀態

18. Redis支持的Java客戶端都有哪些?官方推薦用那個?

  • Redisson、Jedis、lettuce等等,官方推薦使用Redisson。

19. Jedis與Redisson對比有什麼優缺點?

  • Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支持
  • Redisson實現了分佈式和可擴展的Java數據結構,和Jedis相比,功能較爲簡單,不支持字符串操作,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。

20. Redis如何設置密碼和驗證密碼?

  • 初始化密碼 配置文件中設置: requirepass mypassword 修改完成需要重啓生效
  • 不重啓修改祕密: redis 127.0.0.1:6379> config set requirepass mypassword
  • 密碼驗證: redis 127.0.0.1:6379> authmy password

21. 說一說Redis哈希槽的概念?

  • Redis 集羣中內置了 16384 個哈希槽,當需要在 Redis 集羣中放置一個 key-value時,redis 先對 key 使用 crc16 算法算出一個結果,然後把結果對 16384 求餘數,
  • 每個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大致均等的將哈希槽映射到不同的節點。
  • master節點的slave節點不分配槽,只擁有讀權限。
  • 當需要增加節點時,只需要把其他節點的某些哈希槽挪到新節點就可以了;
  • 當需要移除節點時,只需要把移除節點上的哈希槽挪到其他節點就行了;

22. Redis集羣的主從複製模型是怎麼的?

  • 爲了使在部分節點失敗或者大部分節點無法通信的情況下集羣仍然可用,所以集羣使用了主從複製模型,每個節點都會有N-1個複製品.

  • 什麼是主從複製

    • 一臺Redis服務器的數據,複製到其他的Redis服務器。前者稱爲主節點(master/leader),後者稱爲從節點(slave/follower);數據的複製是單向的,只能由主節點到從節點。
    • 默認情況下,每臺Redis服務器都是主節點;且一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。
  • 主從複製的作用

    • 數據冗餘:主從複製實現了數據熱備份,是持久化之外的一種冗餘手段
    • 故障恢復:主節點出現問題可以由從節點提供服務,實現故障恢復
    • 負載均衡:配合讀寫分離分擔服務器負載(主寫,從讀),能大大提高併發量
    • 讀寫分離:讀寫分離除了能提高負載,還能根據也無需求調整從庫數量
  • 主從複製開啓方式

    • 配置文件:從節點配置文件中加入slaveof
    • 啓動命令:redis-server啓動命令後加上–slaveof
    • 客戶端命令:節點啓動後,客戶端執行slaveof
  • 主從複製過程

    • 從節點連接到主節點,發送同步(SYNC)命令
    • 主節點開始執行BGSAVE,並用緩衝區記錄BGSAVE之後執行的所有命令
    • BGSAVE執行完成後主節點向從節點發送快照文件,發送期間繼續使用緩衝區記錄執行命令。從節點拋棄 所有舊數據,載入主節點發送的快照
    • 主節點快照發送完畢後,開始向從節點發送緩衝區中的寫命令。從節點完成對快照文件的解析後,開始接受命令請求
    • 主節點發送完緩衝區數據後,每執行一條寫命令都會向從節點發送相同的寫命令。從節點執行完了主節點緩衝區的命令後,接受之後發送的寫命令,並執行
  • 部分複製和全量複製

    • 全量複製

      • 將master本身的RDB文件同步給slave,就是上述的主從複製過程

      • 發生時機

        • redis slave首啓動或者重啓後,連接到master時
        • redis slave進程沒重啓,但是掉線了,重連後不滿足部分複製條件(傳輸偏移量不在緩衝區範圍內了)
      • 全局複製開銷

        • bgsave每次需要fork子進程,對內存和cup開銷大
        • RDB網絡傳輸耗時
        • 從節點清空數據的耗時
        • 從節點加載RDB的耗時
        • 如果設置了AOF會進行AOF重寫,重寫耗時
    • 部分複製

      • 當master和slave斷開連接時,master會將期間所做的操作記錄到複製緩存區當中(可以看成是一個隊列,其大小默認1M)。
      • 待slave重連後,slave會向master發送psync命令並傳入offset和runId,並進行判斷
        • 如果從節點的run id和主節點的run id一致
        • 如果master發現slave傳輸的偏移量的值,在緩存區隊列範圍中,
      • 就會將從offset開始到隊列結束的數據傳給slave,從而達到同步,降低了使用全量複製的開銷。
    • 無磁盤化複製(測試運行階段)

      • 不依賴與硬盤性能
      • 直接在內存中創建rdb,然後發送給slave

23. Redis集羣會有寫操作丟失嗎?爲什麼?

  • Redis並不能保證數據的強一致性,這意味這在實際中集羣在特定的條件下可能會丟失寫操作

    • 主從複製模型,主服務器宕機後切換新主服務器期間客戶端發送給主服務器的數據會發生寫丟失
    • 全量複製期間主節點宕機,緩衝區數據丟失導致寫丟失

24. Redis集羣之間是如何複製的?

  • 全量複製

    • 將master本身的RDB文件同步給slave,就是上述的主從複製過程

    • 發生時機

      • redis slave首啓動或者重啓後,連接到master時
      • redis slave進程沒重啓,但是掉線了,重連後不滿足部分複製條件(傳輸偏移量不在緩衝區範圍內了)
    • 全局複製開銷

      • bgsave每次需要fork子進程,對內存和cup開銷大
      • RDB網絡傳輸耗時
      • 從節點清空數據的耗時
      • 從節點加載RDB的耗時
      • 如果設置了AOF會進行AOF重寫,重寫耗時
  • 部分複製

    • 當master和slave斷開連接時,master會將期間所做的操作記錄到複製緩存區當中(可以看成是一個隊列,其大小默認1M)。

    • 待slave重連後,slave會向master發送psync命令並傳入offset和runId,並進行判斷

      • 如果從節點的run id和主節點的run id一致
      • 如果master發現slave傳輸的偏移量的值,在緩存區隊列範圍中,
    • 就會將從offset開始到隊列結束的數據傳給slave,從而達到同步,降低了使用全量複製的開銷。

  • 無磁盤化複製(測試運行階段)

    • 不依賴與硬盤性能
    • 直接在內存中創建rdb,然後發送給slave

25. Redis集羣最大節點個數是多少?

  • 最大節點個數爲16384 個
  • Redis 集羣有 16384 個哈希槽,每個 key 通過 CRC16 算法計算的結果,對 16384 取模後放到對應的編號在 0-16383 之間的哈希槽,集羣的每個節點負責一部分哈希槽

26. Redis集羣如何選擇數據庫?

  • Cluster集羣模式下是沒有多database的概念的,不能通過select選擇

  • Redis 集羣中內置了 16384 個哈希槽,當需要在 Redis 集羣中放置一個 key-value時,redis 先對 key 使用 crc16 算法算出一個結果,然後把結果對 16384 求餘數,

  • 每個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大致均等的將哈希槽映射到不同的節點。

27. 怎麼測試Redis的連通性?

  • 控制檯測試連接: redis-cli -h host -p port -a password
  • 連接上之後輸入:ping,連通狀態下會返回:PONG

28. 怎麼理解Redis的事務?

  • 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。

  • Redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令

  • Redis的事務不保證原子性:單條命令是原子性執行的,但事務不保證原子性,且沒有回滾。事務中任意命令執行失敗,其餘的命令仍會被執行。

  • 事務執行的幾種情況

29. Redis事務相關的命令有哪幾個?

  • MULTI、:標記一個事務塊的開始

  • EXEC:執行所有事務塊的命令

  • DISCARD:取消事務,放棄事務塊中的所有命令

  • WATCH: 監視一或多個key,如果在事務執行之前,被監視的key被其他命令改動,則事務被打斷 ( 類似樂觀鎖 )

  • UNWATCH: 取消watch對所有key的監控

30. Redis key的過期時間和永久有效分別怎麼設置?

  • 設置過期時間:EXPIRE key timer
  • 設置永久有效:PERISIT KEY

31. Redis如何做內存優化?

  • 針對於使用層面,儘可能多使用hash表,對於一個對象的存儲,儘量使用hash實現而不是一個屬性一個key,而是應該將一個對象所有信息存儲到一張散列表

32. Redis回收進程如何工作的?

  • 一個客戶端運行了新的命令,添加了新的數據後
  • Redis檢查內存使用情況,如果大於maxmemory的限制,根據設定好的回收策略進行回收

33. 都有哪些方法可以降低Redis的內存使用情況呢?

  • 如果你使用的是32位的Redis實例,可以好好利用Hash,list,sorted set,set等集合類型數據,因爲通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。

34. Redis的內存用完了會發生什麼?

  • 如果沒有設置淘汰策略,默認使用noenviction,當內存用完後,寫數據會報錯,讀數據不會
  • 如果設置了淘汰策略,就會按設定的淘汰策略進行淘汰

35. 一個Redis實例最多能存放多少的keys?List、Set、Sorted Set他們最多能存放多少元素?

  • 理論上Redis可以處理多達‘2的32次方’的keys
  • 任何list、set、和sorted set都可以放‘2的32次方’個元素。
  • Redis的存儲極限是系統中的可用內存值

36. MySQL裏有2000w數據,Redis中只存20w數據,如何保證Redis中的數據都是熱點數據?

  • redis內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。
  • 爲了保證都是熱點,可以使用allkeys-lru淘汰策略

37. Redis最適合的場景是什麼?

  • 會話緩存:Redis提供持久化。能存儲緩存數據不丟失,如用戶的購物車信息
  • 消息隊列:通過list可以實現,但是通常都是使用專業的MQ
  • 排行榜/計數器:Redis對數字的遞增遞減支持非常好,Set和Zset也使得操作起來非常簡便
  • 發佈/訂閱
  • 分佈式會話
  • 分佈式鎖

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

  • 使用 keys 指令可以掃出指定模式的 key 列表(keys mypre*)。

  • redis 正在給線上的業務提供服務,那使用 keys 指令會有什麼問題?

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

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

  • 如果大量的key過期時間設置的過於集中,到過期的那個時間點,Redis可能會出現短暫的卡頓現象(因爲redis是單線程的).嚴重的話可能會導致服務器雪崩,
  • 所以一般在過期時間上加一個隨機值,讓過期時間儘量分散.

40. 使用過Redis做異步隊列嗎?怎麼用的?

  • 使用List作爲隊列:RPUSH生產消息,LPOP消費消息
  • 使用List作爲隊列:RPUSH生產消息,BLPOP阻塞消費,阻塞直到有消息消費或者超時
  • 發佈訂閱模式

41. 如何預防緩存穿透和雪崩?

  • 緩存穿透

    • 定義

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

      • 對查詢結果爲空的情況也進行緩存,緩存時間設置短一點,或者該 key 對應的數據 insert 了之後清理緩存
      • 對一定不存在的 key 進行過濾。可以把所有的可能存在的 key 放到一個大的 Bitmap 中,查詢時通過該 bitmap 過濾(布隆過濾器)
  • 緩存雪崩

    • 定義

      • 當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,如果還有大量的請求進來,就會直接打到DB上,會給後端系統帶來很大壓力。導致系統崩潰
    • 如何避免

      • 在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個 key 只允許一個線程查詢數據和寫緩存,其他線程等待。
      • 做二級緩存,A1 爲原始緩存,A2 爲拷貝緩存,A1 失效時,可以訪問 A2,A1 緩存失效時間設置爲短期,A2 設置爲長期
      • 不同的 key,設置不同的過期時間,讓緩存失效的時間點儘量均勻
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章