【面試】Redis的要點筆記和大綱


1 數據類型與基本類型

數據類型 底層數據 特性 示例
String SDS set key vale
List 快速列表(雙向壓縮列表) rpush list-key value
Set 整數集合 不重複 sadd set-key item
Hash 字典等 hset hash-key key value
ZSet 調錶 有序 zadd zset-key score item
  • String:對整個字符串或者字符串的其中一部分執行操作對整數和浮點數執行自增或者自減操作
  • List:從兩端壓入或者彈出元素對單個或者多個元素進行修剪,只保留一個範圍內的元素
  • Set:添加、獲取、移除單個元素檢查一個元素是否存在於集合中;計算交集、並集、差集從集合裏面隨機獲取元素
  • Hash:添加、獲取、移除單個鍵值對獲取所有鍵值;對檢查某個鍵是否存在
  • ZSet:添加、獲取、刪除元素根據分值範圍或者成員來獲取元素計算一個鍵的排名

1.1 基本數據類型

1.1.1 Simple Dynamic String

SDS(簡單動態字符串)最後一個字符仍舊是 \0 ,目的是和C語言兼容。

String和SDS的區別:

  1. C語言API的二進制不安全,可能會導致緩存區溢出,只能保存文本數據;SDS安全可保存二進制文件。
  2. 前者可以使用所有 <string.h> ,後者只能使用一部分。
  3. 前者獲取一個字符串長度的複雜度爲 O(N) ,後者爲 O(1)
  4. 修改一個字符串前者需要 O(N) ,後者至多 O(N)

1.1.2 鏈表

是消息訂閱發佈、監視器、慢查詢等相關功能的基層實現。

1.1.3 壓縮列表

當一個列表/哈希鍵的鍵元素比較少時,且列表/鍵元素爲小整數或短字符串,就會用壓縮鏈表來實現鏈表鍵的底層。

壓縮列表:是一個順序型的數據結構,採用一種特殊編碼連續內存空間。

1.1.4 快速列表

Redis 3.2該類型是列表的新型實現,底層是由壓縮列表組成的雙向列表。

由於使用了entry節點,相對於壓縮列表可以存儲更多的數據

1.1.5 字典

字典採用拉鍊法解決哈希衝突。

1.1.6 整數集合

整數集合也是集合鍵的一種實現方式,當一個集合只包含整數值集合時且數目不是太多時,它就會被採用。

類型轉化:

  1. 按照高類型(如int32->int64)擴展併爲新元素分配空間。
  2. 將所有底層數組轉化爲高類型並按從小到大的順序依次放到正確的位置。
  3. 添加新的高類型元素。

1.1.7 跳錶

  • 跳錶是有序鏈表的底層實現之一。

1.png

查詢時,從上層指針開始掃描(使用前進指針進行遍歷),找到指定的區間再去下一層查找:

2.png

相比於紅黑樹:

  1. 跳錶插入速度塊(不需要旋轉變色)。
  2. 容易實現和無鎖操作。

2 事務處理

2.1 一般流程

  1. 使用 MULTI 開啓事務
  2. 除了 EXECWATCHDISCARD 之外的命令(),都不會立即執行和返回結果,而是放到一個事務隊列裏。
  3. DISCARD 將會放棄事務,並清空事務隊列裏的所有命令。
  4. EXEC 將會把事務隊列裏的命令按順序執行,並將結果返回客戶端。
  5. WATCH 命令是一個樂觀鎖,用來監視任一key是否被修改過。(使用 UNWATCH 撤銷)
  • Redis採用版本號實現的樂觀鎖

2.2 WATCH的監視機制

在執行 SET 等命令後都會堆 watched_keys 字典進行檢查,如果發現鍵被監視,就會打開 REDIS_DIRTY_CAS 標誌。

2.3 事務的性質

2.3.1 原子性

Redis事務可以一次執行多個命令,要麼全部成功要麼全部失敗。

2.3.2 一致性

把數據庫從數據庫從一個狀態變爲另一個狀態,數據庫中的數據也保證一致性(符合數據本身的定義和要求、無髒數據等)。

2.3.3 隔離性

當同時進行多個事務時,每個用戶的事務執行互不干擾。

2.3.4 持久性

當事務完成時,對數據庫的改變是永久性的。

2.4 緩存相關(雪崩、擊穿、滲透)

  • 緩存擊穿:緩存中沒有但數據庫中有的數據(即“熱點數據”),當對其的請求併發量較大時瞬間引起數據庫壓力激增。解決方案:設置熱點數據永不過期、對熱點數據的數據庫取值加互斥鎖以防止重複進入數據庫。
  • 緩存雪崩:緩存數據大批量過期,而此時恰好有較高的查詢請求。解決方案:緩存數據的過期時間加上隨機擾動、將熱點數據均勻分佈在不同的節點、設置熱點數據永不過期。
  • 緩存穿透:對緩存和數據庫中都不存在的數據不斷髮起請求。解決方案:增加鑑權校驗、將 key-value 寫爲 key-null 並給定一個較短的有效時間。

3. Redis持久化

3.1 AOF

  • 默認情況下AOF沒有被開啓。
  • 持久化方式:保存服務器執行的所有寫操作命令到單獨的日誌文件。在後臺,AOF文件會被重寫以控制體積。
  • 寫入時,並不是直接寫文件,而是協議給緩存區;當緩衝區達到閾值或達到指定週期時,統一將文件寫入硬盤。

3.1.1 AOF文件重寫

  • 定****義:定期重寫AOF文件以減小AOF文件的體積(創建一個新文件然後重寫替換舊的文件、去除冗餘)。
  • 重寫是通過讀取數據庫狀態來實現的,而不是對舊的AOF文件進行讀寫。
  • 重寫過程中,新的請求不會再被寫入舊的文件。
  • 減小體積的方式:1.丟棄過期數據、2.丟棄無效命令(重複設置某個值)、3.多條命令合併爲一條命令。
  • 觸發方式:手動觸發( BGREWRITEAOF )和自動觸發。
  • 由於Redis使用單線程來處理命令請求,爲避免阻塞,因此通過子進程來重寫這個文件。由此導致的數據不一致問題,通過AOF文件重寫緩衝區來解決——對於一個新的寫請求,Redis除了寫AOF緩衝區還會寫重寫緩衝區。

3.1.2 備份與恢復

  1. 創建一個無網絡的僞客戶端,讀取AOF文件。
  2. 執行每一條AOF中記錄的寫命令。

3.1.3 優點與缺點

  1. +兼容性較好;
  2. +支持後臺重寫;
  3. -文件體積逐漸變大、性能逐漸變低;
  4. -恢復速度慢於RDB;
  5. -若AOF文件損壞可能導致恢復失敗。
  6. -無法保存歷史快照。

3.2 RDB【默認】

  • 定義:在指定時間間隔內,生成數據集的時間點快照。
  • 觸發方****式:自動觸發(被修改的鍵達到閾值或達到時間間隔)或手動觸發( BGSAVE )。

3.2.1 快照過程

  1. 父進程調用 fork() 創建子進程,子進程持有父進程的數據。
  2. 父進程繼續處理客戶端的請求,子進程把內存中的數據寫到硬盤上的一個臨時RDB文件中。
  3. 通過寫時複製策略保證在執行 fork() 過程中的兩份內存數據副本不會加倍或前後數據差異過大。

寫時複製:當父進程要修改某個數據時,將內存共享數據複製一份給子進程使用。

3.2.2 優點與缺點

  1. +經過壓縮的二進制文件,適用於數據備份。
  2. +適用於災難恢復,且更快。
  3. +性能優異(父子進程協同,互不干擾)。
  4. -可能會丟失大量數據。
  5. -當內存數據量比較大時,會佔用CPU耗時。
  6. -兼容性問題。

4 Redis主從、哨兵與集羣

4.1 主從複製

  • 一個master可以有多個slave;一個slave只能有一個master。
  • Redis 2.8採用異步複製,從節點會每隔1秒向主服務器報告複製流的處理進度。
  • 複製過程中,並不會阻塞主服務器。
  • 需要注意的是,當一個節點B變爲A的從節點後,B之前保存的數據將會被清除以和A保持同步。

作用:

  1. 備份,防止節點宕機數據丟失。
  2. 讀寫分流,減輕服務器壓力。

4.1.1 全量同步與部分同步

  • 全量同步:用於處理第一次複製時的情況,即盡在第一次接入主節點時纔會進行。通過主節點向從節點發送RDB文件的方式實現。
  • 部分同步:當從節點離線重連後的情況。主節點向從節點發送它自離線以來新增的寫命令。
  • 通過一個運行ID來確認是否爲第一次接入主節點;
  • 通過一個複製偏移量來確認複製緩衝區中的數據;若存在則進行部分同步。
  • 通過每秒一次的心跳機制確認主從服務器間的網絡連接情況。

master宕機之後,slave會原地等待;slave宕機之後需要重新連接。

4.2 Redis讀寫分離

  • 用處:用於將讀流量分攤到每個節點。
  • 具體形式:master進行寫操作,slave進行讀操作。
  • 缺點:主從數據更新有延遲,導致讀取的數據不一致,如讀到過期數據等。

4.3 哨兵模式

  • 定義:由一個或多個哨兵組成的哨兵系統,監控任意多臺服務器是否發生故障;當主節點發生故障時將一個從節點選爲新主節點。
  • 意義:故障轉移、高可用、熱部署。

哨兵本身並不存放數據,但可以同時監控多套主從複製的集羣。

通過訂閱主節點的 _sentinel_:hello 頻道,查找新的哨兵、主服務器的信息。

  • 工作機制:當多個哨兵認爲一個master有問題,就從內部選出一個哨兵領導,它會從所有從服務器中選出一個成爲新的master、其它slave進行認主。隨後,哨兵通知客戶端新的master所在位置,並持續監視舊的master(當其復活後將變爲新master的slave)。

4.4 Redis集羣

  • 定義:不存在中心節點或代理節點,通過主從模式完成它的容錯性,主要用於解決高併發和大數據量的問題。

不支持需要同時處理多個鍵的命令,因爲需要再多個Redis間移動數據,會使整體性能降低和不穩定。

4.4.1 節點

集羣模式下,每一臺Redis服務器都是一個節點。

4.4.2 槽

  • Redis爲了能夠存儲大量的數據信息,採用分片的方式將大量數據保存在數據庫中,每個數據庫被劃分爲16384個
  • 每個槽映射一個大數據集,通過哈希來確認某個值的槽歸屬。
  • 某條命令操作的數據符合自己的槽歸屬,纔會進行相應操作。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章