面試被吊打系列 - Redis原理

小張興沖沖去面試,結果被面試官吊打!面試

小張:redis

面試官,你好。我是來參加面試的。算法

面試官:服務器

你好,小張。我看了你的簡歷,熟練掌握Redis,那麼我就隨便問你幾個Redis相關的問題吧。首先個人問題是,Redis是單線程仍是多線程呢?網絡

小張:數據結構

Redis不一樣版本之間採用的線程模型是不同的,在Redis4.0版本以前使用的是單線程模型,在4.0版本以後增長了多線程的支持。多線程

在4.0以前雖然咱們說Redis是單線程,也只是說它的網絡I/O線程以及Set 和 Get操做是由一個線程完成的。可是Redis的持久化、集羣同步仍是使用其餘線程來完成。併發

4.0以後添加了多線程的支持,主要是體如今大數據的異步刪除功能上,例如 unlink keyflushdb asyncflushall async異步

面試官:async

回答的很好,那爲何Redis在4.0以前會選擇使用單線程?並且使用單線程還那麼快?

小張:

選擇單線程我的以爲主要是使用簡單,不存在鎖競爭,能夠在無鎖的狀況下完成全部操做,不存在死鎖和線程切換帶來的性能和時間上的開銷,但同時單線程也不能徹底發揮出多核CPU的性能。

至於爲何單線程那麼快我以爲主要有如下幾個緣由:

  1. Redis 的大部分操做都在內存中完成,內存中的執行效率自己就很快,而且採用了高效的數據結構,好比哈希表和跳錶。
  2. 使用單線程避免了多線程的競爭,省去了多線程切換帶來的時間和性能開銷,而且不會出現死鎖。
  3. 採用 I/O 多路複用機制處理大量客戶端的Socket請求,由於這是基於非阻塞的 I/O 模型,這就讓Redis能夠高效地進行網絡通訊,I/O的讀寫流程也再也不阻塞。

面試官:

不錯,那Redis是如何實現數據不丟失的呢?

小張:

Redis數據是存儲在內存中的,爲了保證Redis數據不丟失,那就要把數據從內存存儲到磁盤上,以便在服務器重啓後還可以從磁盤中恢復原有數據,這就是Redis的數據持久化。Redis數據持久化有三種方式。

  • AOF 日誌(Append Only File,文件追加方式):記錄全部的操做命令,並以文本的形式追加到文件中。
  • RDB 快照(Redis DataBase):將某一個時刻的內存數據,以二進制的方式寫入磁盤。
  • 混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的優勢。

面試官:

那你分別說說 AOF和 RDB的實現原理吧。

小張:

AOF採用的是寫後日志的方式,Redis先執行命令把數據寫入內存,而後再記錄日誌到文件中。AOF日誌記錄的是操做命令,不是實際的數據,若是採用AOF方法作故障恢復時須要將全量日誌都執行一遍。image.png

RDB採用的是內存快照的方式,它記錄的是某一時刻的數據,而不是操做,因此採用RDB方法作故障恢復時只須要直接把RDB文件讀入內存便可,實現快速恢復。

面試官:

你剛提到了AOF採用的是 「寫後日志」 的方式,咱們平時用的MySQL則採用的是 「寫前日誌」,那 Redis爲何要先執行命令,再把數據寫入日誌呢?

小張:額頭開始冒汗,問的是些啥問題呀。。。

額,這個主要是因爲Redis在寫入日誌以前,不對命令進行語法檢查,因此只記錄執行成功的命令,避免出現記錄錯誤命令的狀況,並且在命令執行後再寫日誌不會阻塞當前的寫操做。

面試官:

後寫日誌又有什麼風險呢?

小張:

我... 這個我不會。

面試官:

好吧,後寫日誌主要有兩個風險可能會發生:

  • 數據可能會丟失: 若是 Redis 剛執行完命令,此時發生故障宕機,會致使這條命令存在丟失的風險。
  • 可能阻塞其餘操做: AOF 日誌其實也是在主線程中執行,因此當 Redis 把日誌文件寫入磁盤的時候,仍是會阻塞後續的操做沒法執行。

我還有個問題是 RDB作快照時會阻塞線程嗎?

小張:

Redis 提供了兩個命令來生成 RDB 快照文件,分別是 savebgsavesave 命令在主線程中執行,會致使阻塞。而 bgsave 命令則會建立一個子進程,用於寫入 RDB 文件的操做,避免了對主線程的阻塞,這也是 Redis RDB 的默認配置。

面試官:

RDB 作快照的時候數據能修改嗎?

小張:

save是同步的會阻塞客戶端命令,bgsave的時候是能夠修改的。

面試官:

那Redis是怎麼解決在bgsave作快照的時候容許數據修改呢?

小張:(你咋還問。。。我™不會啊!)

額,這個我不太清楚...

image.png

面試官:

這裏主要是利用 bgsave的子線程實現的,具體操做以下:

  • 若是主線程執行讀操做,則主線程和bgsave 子進程互相不影響;
  • 若是主線程執行寫操做,則被修改的數據會複製一份副本,而後bgsave子進程會把該副本數據寫入 RDB 文件,在這個過程當中,主線程仍然能夠直接修改原來的數據。

image.png

要注意,Redis 對 RDB 的執行頻率很是重要,由於這會影響快照數據的完整性以及 Redis 的穩定性,因此在 Redis 4.0 後,增長了 AOF 和 RDB 混合的數據持久化機制: 把數據以 RDB 的方式寫入文件,再將後續的操做命令以 AOF 的格式存入文件,既保證了 Redis 重啓速度,又下降數據丟失風險。

小張:

學到了學到了。

面試官:

那你再跟我說說Redis如何實現高可用吧?

小張:

Redis實現高可用主要有三種方式:主從複製、哨兵模式,以及 Redis 集羣。

主從複製

將從前的一臺 Redis 服務器,同步數據到多臺從 Redis 服務器上,即一主多從的模式,這個跟MySQL主從複製的原理同樣。

image.png

哨兵模式

使用 Redis 主從服務的時候,會有一個問題,就是當 Redis 的主從服務器出現故障宕機時,須要手動進行恢復,爲了解決這個問題,Redis 增長了哨兵模式(由於哨兵模式作到了能夠監控主從服務器,而且提供自動容災恢復的功能)。

image.png

Redis Cluster(集羣)

Redis Cluster 是一種分佈式去中心化的運行模式,是在 Redis 3.0 版本中推出的 Redis 集羣方案,它將數據分佈在不一樣的服務器上,以此來下降系統對單主節點的依賴,從而提升 Redis 服務的讀寫性能。

image.png

面試官:

使用哨兵模式在數據上有副本數據作保證,在可用性上又有哨兵監控,一旦master宕機會選舉salve節點爲master節點,這種已經知足了咱們的生產環境須要,那爲何還須要使用集羣模式呢?

小張:

額,哨兵模式歸根節點仍是主從模式,在主從模式下咱們能夠經過增長salve節點來擴展讀併發能力,可是沒辦法擴展寫能力和存儲能力,存儲能力只能是master節點可以承載的上限。因此爲了擴展寫能力和存儲能力,咱們就須要引入集羣模式。

面試官:

集羣中那麼多Master節點,redis cluster在存儲的時候如何肯定選擇哪一個節點呢?

小張:

這應該是使用了某種hash算法,可是我不太清楚。。。

image.png

面試官:

那好,今天的面試就到這裏吧,你先回去等咱們的面試通知。

小張:

好的,謝謝面試官,你能告訴我redis cluster怎麼實現節點選擇的嗎?

面試官:

Redis Cluster採用的是類一致性哈希算法實現節點選擇的,至於什麼是一致性哈希算法你本身回去看看。

Redis Cluster將本身分紅了16384個Slot(槽位),哈希槽相似於數據分區,每一個鍵值對都會根據它的 key,被映射到一個哈希槽中,具體執行過程分爲兩大步。

  • 根據鍵值對的 key,按照 CRC16 算法計算一個 16 bit 的值。
  • 再用 16bit 值對 16384 取模,獲得0~16383 範圍內的模數,每一個模數表明一個相應編號的哈希槽。

每一個Redis節點負責處理一部分槽位,加入你有三個master節點 ABC,每一個節點負責的槽位以下:

節點 處理槽位
A 0-5000
B 5001 - 10000
C 10001 - 16383

這樣就實現了cluster節點的選擇。

好了,各位看官朋友們,Redis原理的這些面試點大家記住了嗎?但願大家的面試不會被這個問題難倒喲~

相關文章
相關標籤/搜索