面試突擊——Redis

一. memcache和Redis的區別

  • Memcache:代碼層次類似Hash

    • 支持簡單數據類型
    • 不支持數據持久化存儲
    • 不支持主從
    • 不支持分片
  • Redis:

    • 數據類型豐富
    • 支持數據磁盤持久化存儲
    • 支持主從
    • 支持分片

二. 爲什麼Redis那麼快?

  • 完全基於內存,絕對部分請求是純粹的內存操作。
  • 數據結構結構簡單,對數據操作也簡單。不使用表,不需要對多個表進行關聯,存儲結構是鍵值對,查找速度比較快.
  • redis採用單線程(並不是說redis server也是單線程!), 天然的不會出現同步問題,鎖競爭,線程切換等額外開銷。而之所以使用單線程是因爲,cpu並不是限制redis性能的瓶頸,真正的瓶頸依然是磁盤,網路的IO帶寬。並且,又多線程需求時,可以開啓多個redis來完成對應的需求。
  • 使用多路IO複用模型,非阻塞IO

三. 數據類型

數據類型 可以存儲的值 操作
STRING 字符串、整數或者浮點數 對整個字符串或者字符串的其中一部分執行操作 對整數和浮點數執行自增或者自減操作
LIST 列表 從兩端壓入或者彈出元素 對單個或者多個元素進行修剪, 只保留一個範圍內的元素
SET 無序集合 添加、獲取、移除單個元素 檢查一個元素是否存在於集合中 計算交集、並集、差集 從集合裏面隨機獲取元素
HASH 包含鍵值對的無序散列表 添加、獲取、移除單個鍵值對 獲取所有鍵值對 檢查某個鍵是否存在
ZSET 有序集合 添加、獲取、刪除元素 根據分值範圍或者成員來獲取元素 計算一個鍵的排名

四. Redis的使用場景

4.1. 從海量Key裏查詢出某一固定前綴的Key

kyes pattern: 查找所有符合給定模式pattern的key

  • 一次性返回所有匹配的key
  • 鍵的數量過大會使服務卡頓

可以使用scan cursor [Match pattern][COUNT count]

  • 基於遊標的迭代器,需要基於上一次的遊標延續之前的迭代過程。
  • 以0作爲遊標開始一次新的迭代,直到命令返回遊標0完成一次遍歷。
  • 不保證每次執行都返回給定數量的元素(count數大於key總數的時候)一次返回數量不可控,只能是大概率符合count。
  • 支持模糊查詢,即能夠返回滿足pattern匹配的key

例如:scan 0 match k1* count 10 ,注意,返回的值有可能的是重複的! 因此需要去重!(例如寫程序的時候用hashset)

blpop

4.2. 如何通過Redis實現分佈式鎖

即分佈式系統中,訪問共同資源時的一種鎖的實現。

在分佈式場景下,無法使用單機環境下的鎖來對多個節點上的進程進行同步。

可以使用 Redis 自帶的 SETNX 命令實現分佈式鎖,setnx key val 就是如果不存在key的話,那麼就設置key爲val。設置成功返回1, 失敗返回0

SET lock_key random_value NX PX 5000

一定要放到一個語句裏,保證“獲取鎖”和“設置超時時間”的原子性。如果設置完setnx以後,程序就掛掉了,那麼這個key(鎖)就一直被佔用!

4.3. 使用Redis做異步隊列

除了使用list的rpush, lpop, blpop 以外,可以用pub/sub:主題訂閱者模式,來做。

例子:

  • 訂閱一個頻道:
    • redis-cli1: subscribe myTopic ,之後進入監聽狀態
    • redis-cli2: subscribe myTopic ,之後進入監聽狀態
    • redis-cli3: subscribe myTopic ,之後進入監聽狀態
    • redis-cli4: publish myTopic "hello!!"
      • 這條消息發送出去之後,監聽myTopic的3個客戶端都收到了“hello!!”這個字符串。

缺點
但需要注意的是,消息的發佈是無狀態的,也就是無法保證可達。對於發佈者來說,消息是即發即失的。 若想解決這個問題,需要用專業的消息隊列,如kafka,rocketmq等。

五、Redis如何做持久化

5.1. RDB ( 快照 ) 持久化:保存某一個時間點的全數據快照.

redis服務器加載時,會啓用reids.conf文件中的配置信息,裏面的:

....

save 900 1   # 就是900秒內如果有1條是寫入指令,那麼就觸發一次快照
save 300 10
save 60 10000

...
stop-writes-on-bgsave-error yes #當設置成yes,
# 就是備份進程若出錯了,則主進程就停止
# 接受新的寫入操作, 這是爲了保證數據一致性!
....

可以根據不同的情況來合理配置。 src目錄下的dump.rdb文件,就是redis系統定期備份的rdb文件. 它是一個二進制文件。

5.1.1 生成RDB備份文件的方式:

  • 主動生成
    • SAVE: 阻塞Redis的服務器進程,直到RDB文件被創建完畢。 很少被使用,因爲佔用了主線程!! 主線程是用來處理client的請求的!!
    • BGSAVE:Fork一個子進程創建RBD文件,不阻塞服務器進程!此時,主進程依然繼續工作,子進程將內存中的數據寫入臨時文件中,因爲copy-on-write的機制,父子進程此時會共享相同的物理頁面,當(主)父進程處理寫請求時,os會爲父進程要寫的頁面創建一個副本(這個副本用於備份),而不是寫入共享的頁面! RDB文件的載入,一般情況下是自動的,redis服務器啓動時,若檢測到rdb文件的存在,那麼會載入這個文件
      在這裏插入圖片描述
      在fork時,子進程和父進程共享同一塊資源空間,只有當父進程對此空間進行修改時,纔會觸發給子進程的資源複製,這一機制爲copy-on-write. ,juc的copyOnWriteArrayList也是使用的這一原理。
  • 被動生成
    • 根據redis.conf裏的save m n 定時觸發 (用的是BGSAVE)
    • 主從複製時,主節點自動觸發(主節點發送rdb文件給從結點,這時,主節點會觸發一次!)
    • 執行debug reload
    • 執行shutdown且沒有開啓AOF持久化,那麼會觸發一次RDB持久化

RDB持久化的缺點:

  • 內存數據的全部同步! 數據量大的時候會因爲IO而嚴重影響性能!
  • 可能會因爲redis掛掉而丟失從當前到最近一次備份期間的所有數據!

5.2 AOF ( Append-Only-File )持久化:保存寫狀態

  • 記錄下除了查詢以外的所有變更數據庫狀態的指令
  • 以append的形式追加保存到AOF文件中
  • AOF持久化默認是關閉的,可以修改redis.conf來讓其生效:
    • appendonly yes # 啓動 aof
    • appendfsync everysec/always/no:
      • always: 一旦緩存區發生改變,就立刻將內容寫到文件中!
      • everysec: 每隔1s,寫入一次
      • no: 什麼時候寫交給os判斷, 一般是等緩存區寫滿了就寫入一次。

日誌重寫解決AOF文件大小不斷增大的問題(例如100條incr 可以用一條add 100實現), 其原理如下:

  • 調用fork(), 創建一個子進程。
  • 子進程把新的AOF寫到一個臨時文件裏,新的AOF是根據內存數據生成對應的命令,並不需要區依賴原來的AOF文件。
  • 主進程持續將新的變動寫到內存中,並更新到“舊”的AOF文件裏。
  • 重寫結束之後,會給主進程一個信號,然後把內存的buff追加到新生成的AOF文件。
  • 用新的AOF替換掉舊的AOF。

5.3 從Redis中恢復數據

其實只要重啓就可以了。。

  • 檢查AOF是否存在,若存在則直接加載AOF,不再去找RDB
  • 若不存在AOF,則嘗試加載RDB

5.4 RDB和AOF的優缺點

  • RDB優點:創建RDB那一瞬間的全部內存數據快照,文件小,恢復快

  • RDB缺點:無法保存最近一次快照之後的數據

  • AOF優點:可讀性高,適合保存增量數據,數據不易丟失

  • AOF缺點:文件體積大,恢復時間長

5.5 redis 4.0之後的備份就是混合模式,即RDB-AOF.

rdb用於全量備份,aof用於增量備份,爲redis4.0之後的默認備份方式。

bgsave做全量持久化,aof做增量持久化

六、Redis主從同步

主從同步原理

redis的一個Master用於寫操作,其他的Slave都是用於讀操作。每一個Master和Slave都是一個Redis server實例。期間只保證主從的最終一致性!
在這裏插入圖片描述
主從同步分爲全同步增量同步

  • 全同步過程(上圖中的1,2,3,4)

    • Salve發送sync命令給Master請求同步
    • Master進行一次BGSAVE(注意,如果是diskless模式的話,可以不用在本地生成rdb,參考
    • 在進行BGSAVE期間,將所有寫操作命令保存至緩存區中。
    • Slave得到Master發送的rdb文件之後進行數據載入。
    • Master再將期間生成的增量寫命令發送給slave端。
  • 增量同步(上圖中的5):

  • Master接受到用戶的操作命令,如果是寫命令,就先將操作記錄追加到AOF文件中;然後確定將此條寫命令傳給哪些Salve,然後往響應緩存中寫入這條指令。最後將緩存中的數據發送給Slave。(注意,這裏並不是收到一條就發送一條,因爲需要保證的是最終一致性!)

七、Redis哨兵

但Redis這種主從結構,如果Master服務器當機了,那就全完了。。因此,解決主從同步Master宕機後的主從切換問題: 哨兵模式(Redis Sential)

Redis Sential

Redis Sential是redis官方提供的集羣管理工具,其本身也是個獨立運行的進程,提供以下幾點服務:

  • 監控:檢查主從服務器是否運行正常
  • 提醒:當被監控的某個redis服務器出現問題時,sential通過API向管理員或其他應用程序發送故障通知
  • 自動故障遷移:主從切換(主服務器掛了以後,將一個Salve服務器升級成Master服務器,做的事情包括:通知之前的Slave已經修改了Master並告訴新的Master是哪個,當用戶發送請求到來時,會返回一個通知,幷包括新的Master的地址,使得集羣能夠正常運行)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章