什麼是 Redis ?

什麼是 Redis ?

Redis,全稱 Remote Dictionary Server,是一個基於內存的高性能 Key-Value 數據庫。html

另外,Redis 已經成爲互聯網公司在緩存組件選擇的惟一,更多的關注點是,如何使用好 Redis 。java

Redis 有什麼優勢?

一、速度快node

由於數據存在內存中,相似於 HashMap ,HashMap 的優點就是查找和操做的時間複雜度都是O (1) 。git

Redis 本質上是一個 Key-Value 類型的內存數據庫,很像Memcached ,整個數據庫通通加載在內存當中進行操做,按期經過異步操做把數據庫數據 flush 到硬盤上進行保存。github

由於是純內存操做,Redis 的性能很是出色,每秒能夠處理超過 10 萬次讀寫操做,是已知性能最快的 Key-Value 數據庫。面試

二、支持豐富數據類型redis

支持 String ,List,Set,Sorted Set,Hash 。算法

Redis 的出色之處不只僅是性能,Redis 最大的魅力是支持保存多種數據結構,此外單個 Value 的最大限制是1GB,不像 Memcached只能保存1MB的數據,所以Redis能夠用來實現不少有用的功能。比方說:數據庫

  • 用他的 List 來作 FIFO 雙向鏈表,實現一個輕量級的高性能消息隊列服務。
  • 用他的 Set 能夠作高性能的 tag 系統等等。

三、豐富的特性緩存

  • 訂閱發佈 Pub / Sub 功能
  • Key 過時策略
  • 事務
  • 支持多個 DB
  • 計數

而且在 Redis 5.0 增長了 Stream 功能,一個新的強大的支持多播的可持久化的消息隊列,提供相似 Kafka 的功能。

四、持久化存儲

Redis 提供 RDB 和 AOF 兩種數據的持久化存儲方案,解決內存數據庫最擔憂的萬一 Redis 掛掉,數據會消失掉。

Redis 有什麼缺點?

  • 因爲 Redis 是內存數據庫,因此,單臺機器,存儲的數據量,跟機器自己的內存大小。雖然 Redis 自己有 Key 過時策略,可是仍是須要提早預估和節約內存。若是內存增加過快,須要按期刪除數據。

    另外,可以使用 Redis Cluster、Codis 等方案,對 Redis 進行分區,從單機 Redis 變成集羣 Redis 。

  • 若是進行完整重同步,因爲須要生成 RDB 文件,並進行傳輸,會佔用主機的 CPU ,並會消耗現網的帶寬。不過 Redis2.8 版本,已經有部分重同步的功能,可是仍是有可能有完整重同步的。好比,新上線的備機。

  • 修改配置文件,進行重啓,將硬盤中的數據加載進內存,時間比較久。在這個過程當中,Redis 不能提供服務。

Redis 和 Memcached 的區別有哪些?

一、Redis 支持複雜的數據結構

  • Memcached 僅提供簡單的字符串。
  • Redis 提供複雜的數據結構,豐富的數據操做。

也由於 Redis 支持複雜的數據結構,Redis 即便往於 Memcached 推出,卻得到更多開發者的青睞。

Redis 相比 Memcached 來講,擁有更多的數據結構,能支持更豐富的數據操做。若是須要緩存可以支持更復雜的結構和操做,Redis 會是不錯的選擇。

二、Redis 原生支持集羣模式

  • 在 Redis3.x 版本中,官方便能支持 Cluster 模式。
  • Memcached 沒有原生的集羣模式,須要依靠客戶端來實現往集羣中分片寫入數據。

三、性能對比

  • Redis 只使用單核,而 Memcached 可使用多核,因此平均每個核上 Redis在存儲小數據時比 Memcached 性能更高。
  • 在 100k 以上的數據中,Memcached 性能要高於 Redis 。雖然 Redis 最近也在存儲大數據的性能上進行優化,可是比起 Memcached,仍是稍有遜色。

更多關於性能的對比,能夠看看 《Memcached 與 Redis 的關鍵性能指標比較》 。

四、內存使用效率對比

  • 簡單的 Key-Value 存儲的話,Memcached 的內存利用率更高,可使用相似內存池。
  • 若是 Redis 採用 hash 結構來作 key-value 存儲,因爲其組合式的壓縮, 其內存利用率會高於 Memcached 。

  • Redis 和 Memcached 的內存管理方法不一樣,Redis 採用的是包裝的 malloc/free , 相較於 Memcached 的內存管理方法 tcmalloc / jmalloc 來講,要簡單不少 。

五、網絡 IO 模型

  • Memcached 是多線程,非阻塞 IO 複用的網絡模型,原型上接近 Nignx 。
  • Redis 使用單線程的 IO 複用模型,本身封裝了一個簡單的 AeEvent 事件處理框架,主要實現了 epoll, kqueue 和 select ,更接近 Apache 早期的模式。

TODO 有點看不懂,找亞普表弟確認中。

六、持久化存儲

  • Memcached 不支持持久化存儲,重啓時,數據被清空。
  • Redis 支持持久化存儲,重啓時,能夠恢復已持久化的數據。

也推薦閱讀下 《腳踏兩隻船的困惑 - Memcached 與 Redis》 。

請說說 Redis 的線程模型?

艿艿:這個是我從網絡上找的資料,講的灰常不錯。

redis 內部使用文件事件處理器 file event handler,這個文件事件處理器是單線程的,因此 redis 才叫作單線程的模型。它採用 IO 多路複用機制同時監聽多個 socket,根據 socket 上的事件來選擇對應的事件處理器進行處理。

文件事件處理器的結構包含 4 個部分:

  • 多個 socket
  • IO 多路複用程序
  • 文件事件分派器
  • 事件處理器(鏈接應答處理器、命令請求處理器、命令回覆處理器)

多個 socket 可能會併發產生不一樣的操做,每一個操做對應不一樣的文件事件,可是 IO 多路複用程序會監聽多個 socket,會將 socket 產生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應的事件處理器進行處理。

來看客戶端與 redis 的一次通訊過程:

redis-single-thread-model

  • 客戶端 socket01 向 redis 的 server socket 請求創建鏈接,此時 server socket 會產生一個 AE_READABLE 事件,IO 多路複用程序監聽到 server socket 產生的事件後,將該事件壓入隊列中。文件事件分派器從隊列中獲取該事件,交給鏈接應答處理器。鏈接應答處理器會建立一個能與客戶端通訊的 socket01,並將該 socket01 的 AE_READABLE事件與命令請求處理器關聯。
  • 假設此時客戶端發送了一個 set key value 請求,此時 redis 中的 socket01 會產生 AE_READABLE 事件,IO 多路複用程序將事件壓入隊列,此時事件分派器從隊列中獲取到該事件,因爲前面 socket01 的 AE_READABLE 事件已經與命令請求處理器關聯,所以事件分派器將事件交給命令請求處理器來處理。命令請求處理器讀取 socket01 的 key value 並在本身內存中完成 key value 的設置。操做完成後,它會將 socket01 的 AE_WRITABLE 事件與令回覆處理器關聯。
  • 若是此時客戶端準備好接收返回結果了,那麼 redis 中的 socket01 會產生一個 AE_WRITABLE 事件,一樣壓入隊列中,事件分派器找到相關聯的命令回覆處理器,由命令回覆處理器對 socket01 輸入本次操做的一個結果,好比 ok,以後解除 socket01 的 AE_WRITABLE 事件與命令回覆處理器的關聯。

這樣便完成了一次通訊。😈 耐心理解一下,灰常重要。若是仍是不能理解,能夠在網絡上搜一些資料,在理解理解。

爲何 Redis 單線程模型也能效率這麼高?

  • 一、純內存操做。

    Redis 爲了達到最快的讀寫速度,將數據都讀到內存中,並經過異步的方式將數據寫入磁盤。因此 Redis 具備快速和數據持久化的特徵。

    若是不將數據放在內存中,磁盤 I/O 速度爲嚴重影響 Redis 的性能。

  • 二、核心是基於非阻塞的 IO 多路複用機制。

  • 三、單線程反而避免了多線程的頻繁上下文切換問題。

    Redis 利用隊列技術,將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷

  • 四、Redis 全程使用 hash 結構,讀取速度快,還有一些特殊的數據結構,對數據存儲進行了優化,如壓縮表,對短數據進行壓縮存儲,再如,跳錶,使用有序的數據結構加快讀取的速度。

Redis 有幾種持久化方式?

持久化方式

Redis 提供了兩種方式,實現數據的持久化到硬盤。

  • 【全量】RDB 持久化,是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。實際操做過程是,fork 一個子進程,先將數據集寫入臨時文件,寫入成功後,再替換以前的文件,用二進制壓縮存儲。
  • 【增量】AOF持久化,以日誌的形式記錄服務器所處理的每個寫、刪除操做,查詢操做不會記錄,以文本的方式記錄,能夠打開文件看到詳細的操做記錄。

兩者的區別

RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤,實際操做過程是fork一個子進程,先將數據集寫入臨時文件,寫入成功後,再替換以前的文件,用二進制壓縮存儲。

img

AOF持久化以日誌的形式記錄服務器所處理的每個寫、刪除操做,查詢操做不會記錄,以文本的方式記錄,能夠打開文件看到詳細的操做記錄。

img

兩者優缺點

RDB存在哪些優點呢?

  • 一旦採用該方式,那麼你的整個Redis數據庫將只包含一個文件,這對於文件備份而言是很是完美的。好比,你可能打算每一個小時歸檔一次最近24小時的數據,同時還要天天歸檔一次最近30天的數據。經過這樣的備份策略,一旦系統出現災難性故障,咱們能夠很是容易的進行恢復。
  • 對於災難恢復而言,RDB是很是不錯的選擇。由於咱們能夠很是輕鬆的將一個單獨的文件壓縮後再轉移到其它存儲介質上。
  • 性能最大化。對於Redis的服務進程而言,在開始持久化時,它惟一須要作的只是fork出子進程,以後再由子進程完成這些持久化的工做,這樣就能夠極大的避免服務進程執行IO操做了。
  • 相比於AOF機制,若是數據集很大,RDB的啓動效率會更高。

RDB又存在哪些劣勢呢?

  • .若是你想保證數據的高可用性,即最大限度的避免數據丟失,那麼RDB將不是一個很好的選擇。由於系統一旦在定時持久化以前出現宕機現象,此前沒有來得及寫入磁盤的數據都將丟失。
  • 因爲RDB是經過fork子進程來協助完成數據持久化工做的,所以,若是當數據集較大時,可能會致使整個服務器中止服務幾百毫秒,甚至是1秒鐘。

AOF的優點有哪些呢?

  • 該機制能夠帶來更高的數據安全性,即數據持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不一樣步。事實上,每秒同步也是異步完成的,其效率也是很是高的,所差的是一旦系統出現宕機現象,那麼這一秒鐘以內修改的數據將會丟失。而每修改同步,咱們能夠將其視爲同步持久化,即每次發生的數據變化都會被當即記錄到磁盤中。能夠預見,這種方式在效率上是最低的。至於無同步,無需多言,我想你們都能正確的理解它。
  • 因爲該機制對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機現象,也不會破壞日誌文件中已經存在的內容。然而若是咱們本次操做只是寫入了一半數據就出現了系統崩潰問題,不用擔憂,在Redis下一次啓動以前,咱們能夠經過redis-check-aof工具來幫助咱們解決數據一致性的問題。
  • 若是日誌過大,Redis能夠自動啓用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會建立一個新的文件用於記錄此期間有哪些修改命令被執行。所以在進行rewrite切換時能夠更好的保證數據安全性。
  • AOF包含一個格式清晰、易於理解的日誌文件用於記錄全部的修改操做。事實上,咱們也能夠經過該文件完成數據的重建。

AOF的劣勢有哪些呢?

  • 對於相同數量的數據集而言,AOF文件一般要大於RDB文件。RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
  • 根據同步策略的不一樣,AOF在運行效率上每每會慢於RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB同樣高效。

兩者選擇的標準,就是看系統是願意犧牲一些性能,換取更高的緩存一致性(aof),仍是願意寫操做頻繁的時候,不啓用備份來換取更高的性能,待手動運行save的時候,再作備份(rdb)。rdb這個就更有些 eventually consistent 的意思了。

經常使用配置

RDB持久化配置

Redis會將數據集的快照dump到dump.rdb文件中。此外,咱們也能夠經過配置文件來修改Redis服務器dump快照的頻率,在打開6379.conf文件以後,咱們搜索save,能夠看到下面的配置信息:

1
2
3
save 900 1         # 在900秒(15分鐘)以後,若是至少有1個key發生變化,則dump內存快照。
save 300 10        # 在300秒(5分鐘)以後,若是至少有10個key發生變化,則dump內存快照。
save 60 10000      # 在60秒(1分鐘)以後,若是至少有10000個key發生變化,則dump內存快照。

AOF持久化配置

在Redis的配置文件中存在三種同步方式,它們分別是:

1
2
3
appendfsync always     # 每次有數據修改發生時都會寫入AOF文件。
appendfsync everysec   # 每秒鐘同步一次,該策略爲AOF的缺省策略。
appendfsync no         # 從不一樣步。高效可是數據不會被持久化。

如何選擇

  • 不要僅僅使用 RDB,由於那樣會致使你丟失不少數據

  • 也不要僅僅使用 AOF,由於那樣有兩個問題,第一,你經過 AOF 作冷備,沒有 RDB 作冷備,來的恢復速度更快; 第二,RDB 每次簡單粗暴生成數據快照,更加健壯,能夠避免 AOF 這種複雜的備份和恢復機制的 bug 。

  • Redis 支持同時開啓開啓兩種持久化方式,咱們能夠綜合使用 AOF 和 RDB 兩種持久化機制,用 AOF 來保證數據不丟失,做爲數據恢復的第一選擇; 用 RDB 來作不一樣程度的冷備,在 AOF 文件都丟失或損壞不可用的時候,還可使用 RDB 來進行快速的數據恢復。

    • 若是同時使用 RDB 和 AOF 兩種持久化機制,那麼在 Redis 重啓的時候,會使用 AOF 來從新構建數據,由於 AOF 中的數據更加完整

      通常來講, 若是想達到足以媲美 PostgreSQL 的數據安全性, 你應該同時使用兩種持久化功能。若是你很是關心你的數據, 但仍然能夠承受數分鐘之內的數據丟失,那麼你能夠只使用 RDB 持久化。

      有不少用戶都只使用 AOF 持久化,但並不推薦這種方式:由於定時生成 RDB 快照(snapshot)很是便於進行數據庫備份, 而且 RDB 恢復數據集的速度也要比AOF恢復的速度要快,除此以外,使用 RDB 還能夠避免以前提到的 AOF 程序的 bug。

在 Redis4.0 版本開始,容許你使用 RDB-AOF 混合持久化方式,詳細可見 《Redis4.0 之 RDB-AOF 混合持久化》 。也所以,RDB 和 AOF 同時使用,是但願達到安全的持久化的推薦方式。

自動化觸發 RDB 持久化的方式

  • 根據 redis.conf 配置中 SAVE m n 定時觸發(使用的BGSAVE)
  • 主從複製時,主節點自動觸發
  • 執行 Debug Reload
  • 執行 Shutdown 且沒有開啓 AOF 持久化

BGSAVE 原理:

timg

重要知識:

  • bgsave 作鏡像全量持久化,AOF 作增量持久化。由於 bgsave 會耗費較長時間,不夠實時,在停機的時候會致使大量丟失數據,因此須要 AOF 來配合使用。在 Redis 實例重啓時,會使用 bgsave 持久化文件從新構建內存,再使用 AOF 重放近期的操做指令來實現完整恢復重啓以前的狀態。
  • 對方追問那若是忽然機器掉電會怎樣?取決於 AOF 日誌 sync 屬性的配置,若是不要求性能,在每條寫指令時都 sync 一下磁盤,就不會丟失數據。可是在高性能的要求下每次都 sync 是不現實的,通常都使用定時 sync ,好比 1 秒 1 次,這個時候最多就會丟失 1 秒的數據。
  • 對方追問 bgsave 的原理是什麼?你給出兩個詞彙就能夠了,fork 和 cow 。fork 是指 Redis 經過建立子進程來進行 bgsave 操做。cow 指的是 copy on write ,子進程建立後,父子進程共享數據段,父進程繼續提供讀寫服務,寫髒的頁面數據會逐漸和子進程分離開來。

Redis 有幾種數據「過時」策略?

Redis 的過時策略,就是指當 Redis 中緩存的 key 過時了,Redis 如何處理。

Redis 提供了 3 種數據過時策略:

  • 被動刪除:當讀/寫一個已通過期的 key 時,會觸發惰性刪除策略,直接刪除掉這個過時 key 。
  • 主動刪除:因爲惰性刪除策略沒法保證冷數據被及時刪掉,因此 Redis 會按期主動淘汰一批已過時的 key 。
  • 主動刪除:當前已用內存超過 maxmemory 限定時,觸發主動清理策略,即 「數據「淘汰」策略」 。

在 Redis 中,同時使用了上述 3 種策略,即它們非互斥的。

想要進一步瞭解,能夠看看 《關於 Redis 數據過時策略》 文章。

Redis 有哪幾種數據「淘汰」策略?

Redis 內存數據集大小上升到必定大小的時候,就會進行數據淘汰策略。

Redis 提供了 6 種數據淘汰策略:

  1. volatile-lru
  2. volatile-ttl
  3. volatile-random
  4. allkeys-lru
  5. allkeys-random
  6. no-enviction

具體的 每種數據淘汰策略的定義,和 如何選擇討論策略,可見 《Redis實戰(二) 內存淘汰機制》 。

Redis LRU 算法

另外,Redis 的 LRU 算法,並非一個嚴格的 LRU 實現。這意味着 Redis 不能選擇最佳候選鍵來回收,也就是最久未被訪問的那些鍵。相反,Redis 會嘗試執行一個近似的 LRU 算法,經過採樣一小部分鍵,而後在採樣鍵中回收最適合(擁有最久未被訪問時間)的那個。

艿艿:這個是從網絡上找到的一個神奇的問題,而且看了答案以後,以爲有點莫名的對不上。

因此,感受這個問題的目的是,如何保證熱點數據不要被淘汰。

在 「Redis 有哪幾種數據「淘汰」策略?」 問題中,咱們已經看到,「Redis 內存數據集大小上升到必定大小的時候,就會進行數據淘汰策略。」 。

那麼,若是咱們此時要保證熱點數據不被淘汰,那麼須要選擇 volatile-lru 或 allkeys-lru 這兩個基於 LRU 算法的淘汰策略。

相比較來講,最終會選擇 allkeys-lru 淘汰策略。緣由是,若是咱們的應用對緩存的訪問符合冪律分佈,也就是存在相對熱點數據,或者咱們不太清楚咱們應用的緩存訪問分佈情況,咱們能夠選擇 allkeys-lru 策略。

Redis 回收進程如何工做的?

理解回收進程如何工做是很是重要的:

  • 一個客戶端運行了新的命令,添加了新的數據
  • Redis 檢查內存使用狀況,若是大於 maxmemory 的限制, 則根據設定好的策略進行回收。
  • Redis 執行新命令……

因此咱們不斷地穿越內存限制的邊界,經過不斷達到邊界而後不斷地回收回到邊界如下(跌宕起伏)。

若是有大量的 key 須要設置同一時間過時,通常須要注意什麼?

若是大量的 key 過時時間設置的過於集中,到過時的那個時間點,Redis可能會出現短暫的卡頓現象。

通常須要在時間上加一個隨機值,使得過時時間分散一些。

Redis 有哪些數據結構?

若是你是 Redis 普通玩家,可能你的回答是以下五種數據結構:

  • 字符串 String
  • 字典Hash
  • 列表List
  • 集合Set
  • 有序集合 SortedSet

若是你是 Redis 中級玩家,還須要加上下面幾種數據結構:

  • HyperLogLog
  • Geo
  • Pub / Sub

若是你是 Redis 高端玩家,你可能玩過 Redis Module ,能夠再加上下面幾種數據結構:

  • BloomFilter
  • RedisSearch
  • Redis-ML
  • JSON

另外,在 Redis 5.0 增長了 Stream 功能,一個新的強大的支持多播的可持久化的消息隊列,提供相似 Kafka 的功能。😈 默默跟面試官在裝一波。

聊聊 Redis 使用場景

Redis 可用的場景很是之多:

  • 數據緩存
  • 會話緩存
  • 時效性數據
  • 訪問頻率
  • 計數器
  • 社交列表
  • 記錄用戶斷定信息
  • 交集、並集和差集
  • 熱門列表與排行榜
  • 最新動態
  • 消息隊列
  • 分佈式鎖

詳細的介紹,能夠看看以下文章:

請用 Redis 和任意語言實現一段惡意登陸保護的代碼,限制 1 小時內每用戶 Id 最多隻能登陸 5 次。

用列表實現,列表中每一個元素表明登錄時間,只要最後的第 5 次登錄時間和如今時間差不超過 1 小時就禁止登錄。

具體的代碼實現,能夠看看 《一道 Redis 面試題》 。

Redis 支持的 Java 客戶端都有哪些?

使用比較普遍的有三個 Java 客戶端:

  • Redisson

    Redisson ,是一個高級的分佈式協調 Redis 客服端,能幫助用戶在分佈式環境中輕鬆實現一些 Java 的對象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

  • Jedis

    Jedis 是 Redis 的 Java 實現的客戶端,其 API 提供了比較全面的 Redis 命令的支持。

    Redisson 實現了分佈式和可擴展的 Java 數據結構,和 Jedis 相比,Jedis 功能較爲簡單,不支持字符串操做,不支持排序、事務、管道、分區等 Redis 特性。

    Redisson 的宗旨是促進使用者對 Redis 的關注分離,從而讓使用者可以將精力更集中地放在處理業務邏輯上。

  • Lettuce

    Lettuce 是一個可伸縮線程安全的 Redis 客戶端。多個線程能夠共享同一個 RedisConnection 。它利用優秀 Netty NIO 框架來高效地管理多個鏈接。

Redis 官方推薦使用 Redisson 或 Jedis 。

Spring Boot 2.x 內置使用 Lettuce 。

如何使用 Redis 實現分佈式鎖?

方案一:set 指令

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

  • 這時候對方會告訴你說你回答得不錯,而後接着問若是在 setnx 以後執行 expire 以前進程意外 crash 或者要重啓維護了,那會怎麼樣?
  • 這時候你要給予驚訝的反饋:唉,是喔,這個鎖就永遠得不到釋放了。緊接着你須要抓一抓本身得腦殼,故做思考片刻,好像接下來的結果是你主動思考出來的,而後回答:我記得 set 指令有很是複雜的參數,這個應該是能夠同時把 setnx 和 expire 合成一條指令來用的!對方這時會顯露笑容,內心開始默唸:摁,這小子還不錯。

因此,咱們可使用 set 指令,實現分佈式鎖。指令以下:

1
SET key value [EX seconds] [PX milliseconds] [NX|XX]

方案二:redlock

set 指令的方案,適合用於在單機 Redis 節點的場景下,在多 Redis 節點的場景下,會存在分佈式鎖丟失的問題。因此,Redis 做者 Antirez 基於分佈式環境下提出了一種更高級的分佈式鎖的實現方式:Redlock 。

具體的方案,胖友能夠看看老友飛哥的兩篇博客:

對比 Zookeeper 分佈式鎖

  • 從可靠性上來講,Zookeeper 分佈式鎖好於 Redis 分佈式鎖。
  • 從性能上來講,Redis 分佈式鎖好於 Zookeeper 分佈式鎖。

因此,沒有絕對的好壞,能夠根據本身的業務來具體選擇。

如何使用 Redis 實現消息隊列?

通常使用 list 結構做爲隊列,rpush 生產消息,lpop 消費消息。當 lpop 沒有消息的時候,要適當 sleep 一會再重試。

  • 若是對方追問可不能夠不用 sleep 呢?list 還有個指令叫 blpop ,在沒有消息的時候,它會阻塞住直到消息到來。
  • 若是對方追問能不能生產一次消費屢次呢?使用 pub / sub 主題訂閱者模式,能夠實現 1:N 的消息隊列。
  • 若是對方追問 pub / sub 有什麼缺點?在消費者下線的狀況下,生產的消息會丟失,得使用專業的消息隊列如 rabbitmq 等。
  • 若是對方追問 redis 如何實現延時隊列?我估計如今你很想把面試官一棒打死若是你手上有一根棒球棍的話,怎麼問的這麼詳細。可是你很剋制,而後神態自若的回答道:使用 sortedset ,拿時間戳做爲 score ,消息內容做爲 key 調用 zadd 來生產消息,消費者用 zrangebyscore 指令獲取 N 秒以前的數據輪詢進行處理。

到這裏,面試官暗地裏已經對你豎起了大拇指。可是他不知道的是此刻你卻豎起了中指,在椅子背後。

固然,實際上 Redis 真的真的真的不推薦做爲消息隊列使用,它最多隻是消息隊列的存儲層,上層的邏輯,還須要作大量的封裝和支持。

另外,在 Redis 5.0 增長了 Stream 功能,一個新的強大的支持多播的可持久化的消息隊列,提供相似 Kafka 的功能。

什麼是 Redis Pipelining ?

一次請求/響應服務器能實現處理新的請求即便舊的請求還未被響應。這樣就能夠將多個命令發送到服務器,而不用等待回覆,最後在一個步驟中讀取該答覆。

這就是管道(pipelining),是一種幾十年來普遍使用的技術。例如許多 POP3 協議已經實現支持這個功能,大大加快了從服務器下載新郵件的過程。

Redis 很早就支持管道(pipelining)技術,所以不管你運行的是什麼版本,你均可以使用管道(pipelining)操做 Redis。

Redis 如何作大量數據插入?

Redis2.6 開始,Redis-cli 支持一種新的被稱之爲 pipe mode 的新模式用於執行大量數據插入工做。

具體可見 《Redis 大量數據插入》 文章。

什麼是 Redis 事務?

和衆多其它數據庫同樣,Redis 做爲 NoSQL 數據庫也一樣提供了事務機制。在Redis中,MULTI / EXEC / DISCARD / WATCH 這四個命令是咱們實現事務的基石。相信對有關係型數據庫開發經驗的開發者而言這一律念並不陌生,即使如此,咱們仍是會簡要的列出 Redis 中事務的實現特徵:

  • 一、在事務中的全部命令都將會被串行化的順序執行,事務執行期間,Redis 不會再爲其它客戶端的請求提供任何服務,從而保證了事物中的全部命令被原子的執行。

  • 二、和關係型數據庫中的事務相比,在 Redis 事務中若是有某一條命令執行失敗,其後的命令仍然會被繼續執行。

  • 三、咱們能夠經過 MULTI 命令開啓一個事務,有關係型數據庫開發經驗的人能夠將其理解爲 "BEGIN TRANSACTION"語句。在該語句以後執行的命令都,將被視爲事務以內的操做,最後咱們能夠經過執行 EXEC / DISCARD 命令來提交 / 回滾該事務內的全部操做。這兩個 Redis 命令,可被視爲等同於關係型數據庫中的 COMMIT / ROLLBACK 語句。

  • 四、在事務開啓以前,若是客戶端與服務器之間出現通信故障並致使網絡斷開,其後全部待執行的語句都將不會被服務器執行。然而若是網絡中斷事件是發生在客戶端執行 EXEC 命令以後,那麼該事務中的全部命令都會被服務器執行。

  • 五、當使用 Append-Only 模式時,Redis 會經過調用系統函數 write 將該事務內的全部寫操做在本次調用中所有寫入磁盤。然而若是在寫入的過程當中出現系統崩潰,如電源故障致使的宕機,那麼此時也許只有部分數據被寫入到磁盤,而另一部分數據卻已經丟失。

    Redis 服務器會在從新啓動時執行一系列必要的一致性檢測,一旦發現相似問題,就會當即退出並給出相應的錯誤提示。此時,咱們就要充分利用 Redis 工具包中提供的 redis-check-aof 工具,該工具能夠幫助咱們定位到數據不一致的錯誤,並將已經寫入的部分數據進行回滾。修復以後咱們就能夠再次從新啓動Redis服務器了。

如何實現 Redis CAS 操做?

在 Redis 的事務中,WATCH 命令可用於提供CAS(check-and-set)功能。

假設咱們經過 WATCH 命令在事務執行以前監控了多個 keys ,假若在 WATCH 以後有任何 Key 的值發生了變化,EXEC 命令執行的事務都將被放棄,同時返回 nil 應答以通知調用者事務執行失敗。

具體的示例,能夠看看 《Redis 事務鎖 CAS 實現以及深刻誤區》 。

Redis 集羣都有哪些方案?

Redis 集羣方案以下:

  • 一、Redis Sentinel
  • 二、Redis Cluster
  • 三、Twemproxy
  • 四、Codis
  • 五、客戶端分片

關於前四種,能夠看看 《Redis 實戰(四)集羣機制》 這篇文章。

關於最後一種,客戶端分片,在 Redis Cluster 出現以前使用較多,目前已經使用比較少了。實現方式以下:

在業務代碼層實現,起幾個毫無關聯的 Redis 實例,在代碼層,對 Key 進行 hash 計算,而後去對應的 Redis 實例操做數據。

這種方式對 hash 層代碼要求比較高,考慮部分包括,節點失效後的替代算法方案,數據震盪後的自動腳本恢復,實例的監控,等等。

選擇

目前通常在選型上來講:

  • 體量較小時,選擇 Redis Sentinel ,單主 Redis 足以支撐業務。
  • 體量較大時,選擇 Redis Cluster ,經過分片,使用更多內存。

    Redis 集羣如何擴容?

這個問題,艿艿瞭解的也不是不少,建議在搜索有什麼方案。

  • 若是 Redis 被當作緩存使用,使用一致性哈希實現動態擴容縮容。
  • 若是 Redis 被當作一個持久化存儲使用,必須使用固定的 keys-to-nodes 映射關係,節點的數量一旦肯定不能變化。不然的話(即Redis 節點須要動態變化的狀況),必須使用能夠在運行時進行數據再平衡的一套系統,而當前只有 Redis Cluster、Codis 能夠作到這樣。

什麼是 Redis 主從同步?

Redis 主從同步

Redis 的主從同步(replication)機制,容許 Slave 從 Master 那裏,經過網絡傳輸拷貝到完整的數據備份,從而達到主從機制。

  • 主數據庫能夠進行讀寫操做,當發生寫操做的時候自動將數據同步到從數據庫,而從數據庫通常是隻讀的,並接收主數據庫同步過來的數據。
  • 一個主數據庫能夠有多個從數據庫,而一個從數據庫只能有一個主數據庫。
  • 第一次同步時,主節點作一次 bgsave 操做,並同時將後續修改操做記錄到內存 buffer ,待完成後將 RDB 文件全量同步到複製節點,複製節點接受完成後將 RDB 鏡像加載到內存。加載完成後,再通知主節點將期間修改的操做記錄同步到複製節點進行重放就完成了同步過程。

好處

經過 Redis 的複製功,能能夠很好的實現數據庫的讀寫分離,提升服務器的負載能力。主數據庫主要進行寫操做,而從數據庫負責讀操做。

Redis 主從同步,是不少 Redis 集羣方案的基礎,例如 Redis Sentinel、Redis Cluster 等等。

更多詳細,能夠看看 《Redis 主從架構》 。

如何使用 Redis Sentinel 實現高可用?

能夠看看 《Redis 哨兵集羣實現高可用》 。

若是使用 Redis Cluster 實現高可用?

能夠看看

說說 Redis 哈希槽的概念?

Redis Cluster 沒有使用一致性 hash ,而是引入了哈希槽的概念。

Redis 集羣有 16384 個哈希槽,每一個 key 經過 CRC16 校驗後對 16384 取模來決定放置哪一個槽,集羣的每一個節點負責一部分 hash 槽。

由於最大是 16384 個哈希槽,因此考慮 Redis 集羣中的每一個節點都能分配到一個哈希槽,因此最多支持 16384 個 Redis 節點。

Redis Cluster 的主從複製模型是怎樣的?

爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有 N-1 個複製節點。

因此,Redis Cluster 能夠說是 Redis Sentinel 帶分片的增強版。也能夠說:

  • Redis Sentinel 着眼於高可用,在 master 宕機時會自動將 slave 提高爲 master ,繼續提供服務。
  • Redis Cluster 着眼於擴展性,在單個 Redis 內存不足時,使用Cluster 進行分片存儲。

Redis Cluster 方案什麼狀況下會致使整個集羣不可用?

有 A,B,C 三個節點的集羣,在沒有複製模型的狀況下,若是節點 B 宕機了,那麼整個集羣就會覺得缺乏 5501-11000 這個範圍的槽而不可用。

Redis Cluster 會有寫操做丟失嗎?爲何?

Redis 並不能保證數據的強一致性,而是【異步複製】,這意味這在實際中集羣在特定的條件下可能會丟失寫操做。

Redis 集羣如何選擇數據庫?

Redis 集羣目前沒法作數據庫選擇,默認在 0 數據庫。

請說說生產環境中的 Redis 是怎麼部署的?

重點問題,仔細理解。

  • Redis Cluster,10 臺機器,5 臺機器部署了 redis 主實例,另外 5 臺機器部署了 redis 的從實例,每一個主實例掛了一個從實例,5 個節點對外提供讀寫服務,每一個節點的讀寫高峯 qps 可能能夠達到每秒 5 萬,5 臺機器最可能是 25 萬讀寫請求每秒。
  • 機器是什麼配置?32G 內存 + 8 核 CPU + 1T 磁盤,可是分配給 Redis 進程的是 10g 內存,通常線上生產環境,Redis 的內存儘可能不要超過 10g,超過 10g 可能會有問題。那麼,5 臺機器對外提供讀寫,一共有 50g 內存。
  • 由於每一個主實例都掛了一個從實例,因此是高可用的,任何一個主實例宕機,都會自動故障遷移,Redis 從實例會自動變成主實例繼續提供讀寫服務。
  • 你往內存裏寫的是什麼數據?每條數據的大小是多少?商品數據,每條數據是 10kb 。100 條數據是 1mb ,10 萬條數據是 1g 。常駐內存的是 200 萬條商品數據,佔用內存是 20g,僅僅不到總內存的 50%。目前高峯期每秒就是 3500 左右的請求量。
  • 其實大型的公司,會有基礎架構的 team 負責緩存集羣的運維。

什麼是 Redis 分區?

這個問題,和 「Redis 集羣都有哪些方案?」 是同類問題。

關於以下四個問題,直接看 《Redis 分區》 文章。

  • Redis 分區是什麼?
  • 分區的優點?
  • 分區的不足?
  • 分區類型?

可能有胖友會懵逼,又是 Redis 主從複製,又是 Redis 分區,又是 Redis 集羣。傻傻分不清啊!

  • Redis 分區是一種模式,將數據分區到不一樣的 Redis 節點上,而 Redis 集羣的 Redis Cluster、Twemproxy、Codis、客戶端分片( 不包括 Redis Sentinel ) 這四種方案,是 Redis 分區的具體實現。
  • Redis 每一個分區,若是想要實現高可用,須要使用到 Redis 主從複製。

你知道有哪些 Redis 分區實現方案

Redis 分區方案,主要分紅兩種類型:

  • 客戶端分區,就是在客戶端就已經決定數據會被存儲到哪一個 Redis 節點或者從哪一個 Redis 節點讀取。大多數客戶端已經實現了客戶端分區。
    • 案例:Redis Cluster 和客戶端分區。
  • 代理分區,意味着客戶端將請求發送給代理,而後代理決定去哪一個節點寫數據或者讀數據。代理根據分區規則決定請求哪些 Redis 實例,而後根據 Redis 的響應結果返回給客戶端。
    • 案例:Twemproxy 和 Codis 。

查詢路由(Query routing)的意思,是客戶端隨機地請求任意一個 Redis 實例,而後由 Redis 將請求轉發給正確的 Redis 節點。Redis Cluster 實現了一種混合形式的查詢路由,但並非直接將請求從一個Redis 節點轉發到另外一個 Redis 節點,而是在客戶端的幫助下直接 redirect 到正確的 Redis 節點。

分佈式 Redis 是前期作仍是後期規模上來了再作好?爲何??

以下是網絡上的一個大答案:

既然 Redis 是如此的輕量(單實例只使用1M內存),爲防止之後的擴容,最好的辦法就是一開始就啓動較多實例。即使你只有一臺服務器,你也能夠一開始就讓 Redis 以分佈式的方式運行,使用分區,在同一臺服務器上啓動多個實例。

一開始就多設置幾個 Redis 實例,例如 32 或者 64 個實例,對大多數用戶來講這操做起來可能比較麻煩,可是從長久來看作這點犧牲是值得的。

這樣的話,當你的數據不斷增加,須要更多的 Redis 服務器時,你須要作的就是僅僅將 Redis 實例從一臺服務遷移到另一臺服務器而已(而不用考慮從新分區的問題)。一旦你添加了另外一臺服務器,你須要將你一半的 Redis 實例從第一臺機器遷移到第二臺機器。

  • 和飛哥溝通了下,這個操做不是很合理。
  • 不管怎麼說,建議,須要搭建下 Redis Sentinel 高可用,至於拓展性,根據本身的狀況,是否使用 Redis Cluster 集羣

Redis 有哪些重要的健康指標?

推薦閱讀 《Redis 幾個重要的健康指標》

  • 存活狀況
  • 鏈接數
  • 阻塞客戶端數量
  • 使用內存峯值
  • 內存碎片率
  • 緩存命中率
  • OPS
  • 持久化
  • 失效KEY
  • 慢日誌

如何提升 Redis 命中率?

推薦閱讀 《如何提升緩存命中率(Redis)》 。

怎麼優化 Redis 的內存佔用

推薦閱讀 《Redis 的內存優化》

  • redisObject 對象
  • 縮減鍵值對象
  • 共享對象池
  • 字符串優化
  • 編碼優化
  • 控制 key 的數量

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

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

理論上,Redis 能夠處理多達 2^32 的 keys ,而且在實際中進行了測試,每一個實例至少存放了 2 億 5 千萬的 keys。

任何 list、set、和 sorted set 均可以放 2^32 個元素。

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

使用 keys 指令能夠掃出指定模式的 key 列表。

  • 對方接着追問:若是這個 Redis 正在給線上的業務提供服務,那使用keys指令會有什麼問題?
  • 這個時候你要回答 Redis 關鍵的一個特性:Redis 的單線程的。keys 指令會致使線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可使用 scan 指令,scan 指令能夠無阻塞的提取出指定模式的 key 列表,可是會有必定的重複機率,在客戶端作一次去重就能夠了,可是總體所花費的時間會比直接用 keys 指令長。

Redis 常見的性能問題都有哪些?如何解決?

一、Master 最好不要作任何持久化工做,如 RDB 內存快照和 AOF 日誌文件。

  • Master 寫內存快照,save 命令調度 rdbSave 函數,會阻塞主線程的工做,當快照比較大時對性能影響是很是大的,會間斷性暫停服務,因此 Master 最好不要寫內存快照。
  • Master AOF 持久化,若是不重寫 AOF 文件,這個持久化方式對性能的影響是最小的,可是 AOF 文件會不斷增大,AOF 文件過大會影響 Master 重啓的恢復速度。
  • 因此,Master 最好不要作任何持久化工做,包括內存快照和 AOF 日誌文件,特別是不要啓用內存快照作持久化。若是數據比較關鍵,某個 Slave 開啓AOF備份數據,策略爲每秒同步一次

二、Master 調用 BGREWRITEAOF 重寫 AOF 文件,AOF 在重寫的時候會佔大量的 CPU 和內存資源,致使服務 load 太高,出現短暫服務暫停現象。

三、儘可能避免在壓力很大的主庫上增長從庫。

四、主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即:Master <- Slave1 <- Slave2 <- Slave3... 。

  • 這樣的結構,也方便解決單點故障問題,實現 Slave 對 Master 的替換。若是 Master掛了,能夠馬上啓用 Slave1 作 Master ,其餘不變。

五、Redis 主從複製的性能問題,爲了主從複製的速度和鏈接的穩定性,Slave 和 Master 最好在同一個局域網內。


和飛哥溝經過後,他們主節點開啓 AOF ,從節點開啓 AOF + RDB 。

和曉峯溝通後,他們主節點開啓 AOF ,從節點開啓 RDB 居多,也有開啓 AOF + RDB 的。

修改配置不重啓 Redis 會實時生效嗎?

針對運行實例,有許多配置選項能夠經過 CONFIG SET 命令進行修改,而無需執行任何形式的重啓。

從 Redis 2.2 開始,能夠從 AOF 切換到 RDB 的快照持久性或其餘方式而不須要重啓 Redis。檢索 CONFIG GET * 命令獲取更多信息。

但偶爾從新啓動是必須的,如爲升級 Redis 程序到新的版本,或者當你須要修改某些目前 CONFIG 命令還不支持的配置參數的時候。

其餘問題

有些比較兇殘的面試官,可能會問咱們一些 Redis 數據結構的問題,例如:

  • Skiplist 插入和查詢原理?

  • 壓縮列表的原理?

  • Redis 底層爲何使用跳躍表而不是紅黑樹?

    跳躍表在範圍查找的時候性能比較高。

參考連接

相關文章
相關標籤/搜索