12.19 面試官:Redis 這些我必問

分佈式緩存

緩存好處:高性能 + 高併發

高性能(常用)

面試官:Redis 這些我必問


數據庫查詢耗費了800ms,其他用戶對同一個數據再次查詢 ,假設該數據在10分鐘以內沒有變化過,並且 10 分鐘之內有 1000 個用戶 都查詢了同一數據,10 分鐘之內,那 1000 個用戶,每個人查詢這個數據都感覺很慢 800ms
比如 :某個商品信息,在 一天之內都不會改變,但是這個商品每次查詢一次都要耗費2s,一天之內被瀏覽 100W次
mysql 單機也就 2000qps,緩存單機輕鬆幾萬幾十萬qps,單機 承載併發量是 mysql 單機的幾十倍。

高併發

面試官:Redis 這些我必問


在中午高峰期,有 100W 個用戶訪問系統 A,每秒有 4000 個請求去查詢數據庫,數據庫承載每秒 4000 個請求會宕機,加上緩存後,可以 3000 個請求走緩存 ,1000 個請求走數據庫。
緩存是走內存的,內存天然可以支撐4w/s的請求,數據庫(基於磁盤)一般建議併發請求不要超過 2000/s

緩存不良後果

  1. 緩存與數據庫雙寫不一致
  2. 緩存雪崩
  3. 緩存穿透
  4. 緩存併發競爭

Redis 線程模型

redis 單線程 ,memcached 多線程
redis 是單線程 nio 異步線程模型

Redis 和 Memcached 區別

  1. Redis 支持服務器端的數據操作:Redis比Memcached來說,擁有更多的數據結構和並支持更豐富的數據操作,通常在Memcached裡,你需要將數據拿到客戶端來進行類似的修改再set回去。這大大增加了網絡 IO 的次數和數據體積。在Redis中,這些複雜的操作通常和一般的GET/SET一樣高效。所以,如果需要緩存能支持更復雜的結構和操作,那麼Redis會是不錯的選擇
  2. 集群模式:memcached 沒有原生的集群模式,需要依靠客戶端來實現往集群中分片寫入數據,但是 Redis 目前是原生支持 cluster模式的

Redis 單線程模型

一個線程+一個隊列

面試官:Redis 這些我必問

redis 基於 reactor 模式開發了網絡事件處理器,這個處理器叫做文件事件處理器,file event handler,這個文件事件處理器是單線程的,所以redis 是單線程的模型,採用 io多路複用機制同時監聽多個 socket,根據socket上的事件來選擇對應的事件處理器來處理這個事件。


文件事件處理器包含:多個 socket,io多路複用程序,文件事件分派器,事件處理器(命令請求處理器、命令回覆處理器、連接應答處理器)
文件事件處理器是單線程的,通過 io 多路複用機制監聽多個 socket,實現高性能和線程模型簡單性
被監聽的 socket 準備好執行 accept,read,write,close等操作的時候,會產生對應的文件事件,調用之前關聯好的時間處理器處理
多個 socket併發操作,產生不同的文件事件,i/o多路複用會監聽多個socket,將這些 socket放入一個隊列中排隊。事件分派器從隊列中取出socket給對應事件處理器。
一個socket時間處理完後,事件分派器才能從隊列中拿到下一個socket,給對應事件處理器來處理。

文件事件:
AE_READABLE 對應 socket變得可讀(客戶端對redis執行 write操作)
AE_WRITABLE 對應 socket 變得可寫(客戶端對 redis執行 read操作)
I/O 多路複用可以同時監聽AE_REABLE和 AE_WRITABLE ,如果同時達到則優先處理 AE_REABLE 時間
文件事件處理器:
連接應答處理器 對應 客戶端要連接 redis
命令請求處理器 對應 客戶端寫數據到 redis
命令回覆處理器 對應 客戶端從 redis 讀數據

流程:

  1. redis 初始化時,會將連接應答處理器跟 AE_READABLE事件關聯
  2. 客戶端對 redis 發起連接,產生一個 AE_READABLE 事件
  3. 連接應答處理器處理客戶端 AE_READABLE 事件,創建客戶端對應的 socket,同時將這個 socket的 AE_READABLE 事件和命令請求處理器關聯
  4. 客戶端對 redis 發起讀請求,會在 socket上產生一個 AE_READABLE 事件
  5. 綁定 AE_READABLE 事件的命令請求處理器會從 socket 中讀取請求相關數據,執行對應操作,當執行完畢後,將 socket的 AE_WRITABLE 事件跟命令回覆處理器關聯
  6. 當客戶端這邊準備好讀取響應時,會在 socket上產生一個AE_WRITABLE事件
  7. 綁定 AE_WRITABLE 事件的命令回覆處理器將準備好的響應數據寫入 socket,供客戶端來讀取
  8. 命令回覆處理器寫完後,刪掉 socket的 AE_WRITABLE 事件和命令回覆處理器的綁定關係

Redis 單線程模型效率高

一秒鐘可以處理幾萬個請求

  1. 非阻塞 I/O 多路複用機制(不處理事件,只輪詢請求壓入隊列)
  2. 純內存操作(操作只有幾微秒)
  3. 單線程反而 避免了多線程頻繁上下文切換的問題

Redis 數據類型

  • string

普通的 set,get kv緩存

  • hash

類型 map結構,比如一個對象(沒有嵌套對象)緩存到 redis裡面,然後讀寫緩存的時候,可以直接操作hash的字段(比如把 age 改成 21,其他的不變)
key=150
value = {

<code>"id":150,
"name":"zhangsan",
"age":20/<code>

}

  • list

有序列表 ,元素可以重複
可以通過 list 存儲一些列表型數據結構,類似粉絲列表,文章評論列表。


例如:微信大 V的粉絲,可以以 list 的格式放在 redis 裡去緩存
key=某大 V value=[zhangsan,lisi,wangwu]
比如 lrange 可以從某個元素開始讀取多少個元素,可以基於 list 實現分頁查詢功能,基於 redis實現高性能分頁,類似微博下來不斷分頁東西。
可以搞個簡單的消息隊列,從 list頭懟進去(lpush),list尾巴出來 (brpop)

  • set

無序集合,自動去重
需要對一些數據快速全局去重,(當然也可以基於 HashSet,但是單機)
基於 set 玩差集、並集、交集的操作。比如:2 個人的粉絲列表整一個交集,看看 2 個人的共同好友是誰?
把 2 個大 V 的粉絲都放在 2 個 set中,對 2 個 set做交集(sinter)

  • sorted set

排序的 set,去重但是可以排序,寫進去的時候給一個分數,自動根據分數排序

排行榜:

  1. 將每個用戶以及其對應的分數寫入進去

zadd board score username

  1. zrevrange board 0 99 可以獲取排名前 100 的用戶
  2. zrank board username 可以看到用戶在排行榜裡的排名

例如:
zadd board 85 zhangsan
zadd board 72 wangwu
zadd board 96 lis
zadd board 62 zhaoliu

自動排序為:
96 lisi
85 zhangsan
72 wangwu
62 zhaoliu

獲取排名前 3 的用戶 : zrevrange board 0 3
96 lisi
85 zhangsan
72 wangwu

查看zhaoliu的排行 :zrank board zhaoliu 返回 4

Redis 過期策略

內存是寶貴的,磁盤是廉價的
給key設置過期時間後,redis對這批key是定期刪除+惰性刪除
定期刪除:
redis 默認每隔 100ms隨機抽取一些設置了過期時間的 key,檢查其是否過期了,如果過期就刪除。
注意:redis是每隔100ms隨機抽取一些 key來檢查和刪除,而不是遍歷所有的設置過期時間的key(否則CPU 負載會很高,消耗在檢查過期 key 上)


惰性刪除:
獲取某個key的時候, redis 會檢查一下,這個key如果設置了過期時間那麼是否過期,如果過期了則刪除。
如果定期刪除漏掉了許多過期key,然後你也沒及時去查,也沒走惰性刪除,如果大量過期的key堆積在內存裡,導致 redis 內存塊耗盡,則走內存淘汰機制。

內存淘汰策略:

  1. noeviction:當內存不足以容納新寫入數據時,新寫入操作直接報錯(沒人用)
  2. allkeys-lru: 當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key(最常用)
  3. allkeys-random: 當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個 key,(沒人用)
  4. volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key(不合適)
  5. volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的 key 優先移除(不合適)

LRU 算法:

<code>package com.mousycoder.mycode; 


import java.util.LinkedHashMap;
import java.util.Map;

/**
* @version 1.0
* @author: mousycoder
* @date: 2019/10/31 17:55
*/
public class LRUCache extends LinkedHashMap {

private final int CACHE_SIZE;

public LRUCache( int cacheSize) {
super((int)Math.ceil(cacheSize / 0.75) + 1 ,0.75f,true);
this.CACHE_SIZE = cacheSize;
}

@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > CACHE_SIZE;
}

public static void main(String[] args) {
LRUCache<integer> lruCache = new LRUCache<>(10);
for (int i = 0; i < 15; i++) {
lruCache.put(i,i);
}

Integer integer1 = lruCache.get(0);
for (Integer integer : lruCache.keySet()) {
System.out.println(integer);
}

}
}
/<integer>
/<code>

Redis 高併發和高可用

緩存架構(多級緩存架構、熱點緩存)
redis 高併發瓶頸在單機,讀寫分離,一般是支撐讀高併發,寫請求少,也就 一秒一兩千,大量請求讀,一秒鐘二十萬次。


面試官:Redis 這些我必問

主從架構

面試官:Redis 這些我必問


一主多從,主負責寫,將數據同步複製到其他 slave節點,從節點負責讀,所有讀的請求全部走從節點。主要是解決讀高併發。、
主從架構->讀寫分離->支撐10W+讀QPS架構

Redis Replication

面試官:Redis 這些我必問


master->slave 複製,是異步的
核心機制:

  1. redis 採用異步方式複製數據到 slave 節點
  2. 一個 master node是可以配置多個 slave node的
  3. slave node也可以連接其他的 slave node
  4. slave node 做複製的時候,是不會 block master node的正常工作
  5. slave node 在做複製的時候,也不會 block對自己的查詢操作,它會用舊的數據集來提供服務。但是複製完成時,需要刪除舊數據集,加載新的數據集,這個時候就會暫停對外服務了。
  6. slave node 主要用來進行橫向擴容,做讀寫分離,擴容 slave node 可以提高讀的吞吐量

master持久化對主從架構的意義:
如果開啟了主從架構,一定要開啟 master node的持久化,不然 master宕機重啟數據是空的,一經複製,slave的數據也丟了

主從複製原理:

面試官:Redis 這些我必問


第一次啟動或者斷開重連情況:

  1. 當啟動一個 slave node的時候,它會發送一個 PSYNC 命令給 master node
  2. master 會觸發一次 full resynchronization (如果不是第一次連接,master 只會複製給 slave 部分缺少的數據,從backlog裡找)
  3. master會啟動一個後臺線程,開始生成一份 RDB 快照( bgsave,也可以直接在內存中創建),同時將從客戶端收到的所有寫命令緩存在內存中。RDB 文件生成完畢之後,master會將這個RDB發送給slave,slave會先寫入本地磁盤,然後再從本地磁盤加載到內存中。然後 master會將內存中緩存的寫命令發送給 slave,slave也會同步這些數據(slave如果跟 master網絡故障,斷開連接,會自動重連,master如果發現有多個 slave 來重新連接,僅僅只會啟動一個 RDB save 操作,用一份數據服務所有 slave node)

正常情況下:
master 來一條數據,就異步給 slave

Redis高可用性

全年 99.99%的時間,都是出於可用的狀態,那麼就可以稱為高可用性
redis 高可用架構叫故障轉移,failover,也可以叫做主備切換,切換的時間不可用,但是整體高可用。


sentinal node(哨兵)

Sentinal

作用:

  1. 集群監控,負責監控 redis master 和 slave進程是否正常
  2. 消息通知,如果某個 redis 實例有故障,那麼哨兵負責發送消息作為報警通知給管理員
  3. 故障轉移,如果 master 掛掉,會自動轉移到 slave
  4. 配置中心,如果故障轉移了,通知 client 客戶端新的 master地址

兩節點哨兵集群

面試官:Redis 這些我必問


quorum = 1 (代表哨兵最低個數可以嘗試故障轉移,選舉執行的哨兵)
master 宕機,只有 S2 存活,因為 quorum =1 可以嘗試故障轉移,但是沒達到 majority =2 (最低允許執行故障轉移的哨兵存活數)的標準,無法執行故障轉移

三節點哨兵集群(經典)

面試官:Redis 這些我必問


如果 M1 宕機了,S2,S3 認為 master宕機,選舉一個執行故障轉移,因為 3 個哨兵的 majority = 2,所以可以執行故障轉移

Redis 主從 + 哨兵

丟數據:

面試官:Redis 這些我必問

  1. master內存中數據異步同步到 slave master 就掛掉了,丟掉了 master 內存中的數據
面試官:Redis 這些我必問

  1. 腦裂,某個 master 所在機器突然脫離了正常的網絡,其他 slave機器不能連接,但是實際上 master還在運行,哨兵認為 master 宕機,選舉 slave為master,此時集群裡有 2 個 master, client還沒來得及切換到新的master,還繼續寫在舊的 master上,數據丟了,此時舊的 master再次恢復,被被作為一個 slave 掛到新的 master 上,自己的數據被清空 (腦裂,大腦一分為 2,同時指揮同一個人)

解決方案:

  1. min-slaves-max-lag 10 (至少一個 slave同步的延遲不能超過 10s) 減少異步複製的數據丟失,發現slave複製數據和 ack延時過長,拒絕寫入,減少同步數據損失。讓client做降級寫到本地磁盤裡和限流,或者先暫存到消息隊列,然後重新發回 master
  2. min-slaves-to-write 1 減少腦裂帶來的數據丟失,最多損失 10 s數據,假設master 不能繼續給 slave發送數據,並且 slave 10s沒給自己的 ack消息,直接拒絕客戶端寫請求,同時 client做降寫到本地磁盤、限流,或者先暫存到消息隊列,然後重新發回 master

哨兵

sdown 主觀宕機,哨兵覺得一個 master 宕機(ping 超過了 is-master-down-after-milliseconds毫秒數)


odown 客觀宕機,quorum數量的哨兵都覺得 master宕機
哨兵互相感知通過 redis的 pub/sub系統,每隔 2 秒往同一個 channel裡發消息(自己的 host,ip,runid),其他哨兵可以消費這個消息
以及同步交換master的監控信息。
哨兵確保其他slave修改master信息為新選舉的master
當一個 master被認為 odown && marjority哨兵都同意,那麼某個哨兵會執行主備切換,選舉一個slave成為master(考慮 1. 跟master斷開連接的時長 2. slave 優先級 3.複製 offset 4. runid)
選舉算法:

  1. 如果slave跟master斷開連接已經超過 down-after-milliseconds * 10 + master宕機時間,則放棄
  2. 按 slave 優先級排序 ,slave-priority 越小越靠前
  3. replica offset ,哪個slave複製越多的數據,越靠前
  4. runid 越小,越靠前

quorum 數量哨兵認為odown->選舉一個哨兵切換->獲得 majority哨兵的授權(quorum < majority 需要 majority個哨兵授權,quorum >= majority 需要 quorum 哨兵授權)
第一個選舉出來的哨兵切換失敗了,其他哨兵等待 failover-time之後,重新拿confiuration epoch做為新的version 切換,保證拿到最新配置,用於 configuration傳播(通過 pu/sub消息機制,其他哨兵對比 version 新舊更新 master配置)

Redis 優化方案

高併發:主從架構
高容量:Redis集群,支持每秒幾十萬的讀寫併發
高可用:主從+哨兵

Redis 持久化

持久化的意義在於故障恢復數據備份(到其他服務器)+故障恢復(遇到災難,機房斷電,電纜被切)

  • RDB 對 Redis 中的數據執行週期性的持久化。
  • AOF 機制,每條寫命令作為日誌,以 append-only模式寫入一個日誌文件總,在 redis重啟的時候,可以通過回放AOF日誌中的寫入指令來重新構建整個數據集

AOF 只有一個,Redis 中的數據是有一定限量的,內存大小是一定的,AOF 是存放寫命令的,當大到一定的時候,AOF 做 rewrite 操作,就會基於當時 redis 內存中的數據,來重新構造一個更小的 AOF 文件,然後將舊的膨脹很大的文件給刪掉,AOF 文件一直會被限制在和Redis內存中一樣的數據。AOF同步間隔比 RDB 小,數據更完整

RDB

優點:

  • RDB 會生成多個數據文件,每個數據文件都代表了某一個時刻中 redis 的數據,這種多個數據文件的方式,非常適合做冷備,可以將這種完整的數據文件發送到一些遠程的安全存儲上去,RDB 做冷備,生成多個文件,每個文件都代表某一個時刻的完整的數據快照,AOF 也可以做冷備,只有一個文件,每隔一定時間去 copy一份這個文件出來。 RDB 做冷備,由Redis控制固定時長去生成快照文件,比較方便。AOF,需要自己寫腳本定時控制。
  • RDB 對 redis對外提供的讀寫服務,影響非常小,可以讓 redis 保持高性能,因為 redis 主進程只需要 fork一個子進程,讓子進程執行磁盤 IO 操作來進行 RDB 持久化
  • 相對於 AOF 持久化機制來說,直接基於 RDB 數據文件來重啟和恢復 redis 進程,更加快速

缺點:

  • 如果想要在 redis故障時,儘可能少丟數據,那麼 RDB 沒有 AOF 好,一般 RDB 數據快照,都是間隔 5 分鐘,或者更長的時候生成一次,這個時候就得接受一旦 redis 進程宕機,那麼會丟失最近 5 分鐘數據
  • RDB 每次在 fork子進程來執行 RDB 快早數據文件生成的時候,如果數據文件特別大,可能會導致對客戶端提供的服務暫停數毫秒,甚至數秒(RDB 生成間隔不要太長)

AOF 存放的指令日誌,數據恢復的時候,需要回放執行所有指令日誌,RDB 就是一份數據文件,直接加載到內存中。

AOF

優點:

  1. 更好保護數據不丟失,後臺線程 fsync 操作,最多丟失一秒鐘數據,保證 os cache中的數據寫入磁盤中
  2. AOF 用 append-only 模式,沒有磁盤尋址開銷,寫入性能非常高,文件不容易損壞。
  3. AOF 日誌過大的時候,後臺 rewrite log時候,老的日誌文件照常寫入,新的merge後的日誌文件 ready的時候,再交換新老日誌文件
  4. 適合災難性恢復,某人不小心 flushall清空所有數據,只要後臺 rewrite還沒發生,那麼可以立刻拷貝 AOF 文件,將最後一條 flushall命令給刪了,然後再將該 AOF 文件放回去,可以通過恢復機制,自動恢復所有數據

缺點:

  1. AOF 日誌文件比 RDB 數據快照文件大
  2. 降低 Redis的寫 QPS
  3. AOF 複雜,Bug多
  4. 數據恢復比較慢

最佳方案

AOF 來保證數據不丟失,RDB 做不同時間的冷備


Redis Cluster

面試官:Redis 這些我必問


支持 N 個 Redis master node,每個 master node掛載多個 slave node
多master + 讀寫分離 + 高可用

數據量很少,高併發 -> replication + sentinal 集群
海量數據 + 高併發 + 高可用 -> redis cluster

分佈式算法

hash算法->一致性 hash 算法-> redis cluster->hash slot算法

redis cluster :自動對數據進行分片,每個 master 上放一部分數據,提供內置的高可用支持,部分master不可用時,還是可以繼續工作


cluster bus 通過 16379進行通信,故障檢測,配置更新,故障轉移授權,另外一種二進制協議,主要用於節點間進行高效數據交換,佔用更少的網絡帶寬和處理時間

hash算法

key進行hash,然後對節點數量取模,最大問題只有任意一個 master 宕機,大量數據就要根據新的節點數取模,會導致大量緩存失效。

一致性 hash 算法

面試官:Redis 這些我必問


key進行hash,對應圓環上一個點,順時針尋找距離最近的一個點。保證任何一個 master 宕機,只受 master 宕機那臺影響,其他節點不受影響,此時會瞬間去查數據庫。

緩存熱點問題:
可能集中在某個 hash區間內的值特別多,那麼會導致大量的數據都湧入同一個 master 內,造成 master的熱點問題,性能出現瓶頸。

解決方法:
給每個 master 都做了均勻分佈的虛擬節點,這樣每個區間內大量數據都會均勻的分佈到不同節點內,而不是順時針全部湧入到同一個節點中。

Hash Slot算法

redis cluster 有固定 16384 個 hash slot,對每個key計算 CRC16 值,然後對16384取模,可以獲取 key對應的 hash slot
redis cluster 中每個 master 都會持有部分 slot ,當一臺 master 宕機時候,會最快速度遷移 hash slot到可用的機器上(只會短暫的訪問不到)
走同一個 hash slot 通過 hash tag實現

Redis Cluster 核心

  1. 基礎通信

通過 gossip 協議通信(小道留言,所有節點都持有一份元數據,不同的節點如果出現了元數據的變更,就不斷將元數據發送給其他節點,讓其他節點也進行元數據的變更)

面試官:Redis 這些我必問


集群元數據:包括 hashslot->node之間的映射表關係,master->slave之間的關係,故障的信息


集群元數據集中式存儲(storm),底層基於zookeeper(分佈式協調中間件)集群所有元數據的維護。好處:元數據的更新和讀取,時效性好,一旦變更,其他節點立刻可以感知。缺點:所有元數據的更新壓力全部集中在一個地方,可能會導致元數據的存儲有壓力。
goosip: 好處:元數據的更新比較分散,有一定的延時,降低了壓力。缺點:更新有延時,集群的一些操作會滯後。(reshared操作時configuration error)

  1. 10000 端口

自己提供服務的端口號+ 10000 ,每隔一段時間就會往另外幾個節點發送ping消息,同時其他幾點接收到ping之後返回pong

  1. 交換的信息

故障信息,節點的增加和移除, hash slot 信息

  1. gossip協議

meet:某個節點發送 meet給新加入的節點,讓新節點加入集群中,然後新節點就會開始於其他節點進行通信
ping:每個節點都會頻繁給其他節點發送ping,其中包含自己的狀態還有自己維護的集群元數據,互相通過ping交換元數據


ping:返回ping和meet,包含自己的狀態和其他信息
fail:某個節點判斷另一個節點fail之後,就發送 fail 給其他節點,通知其他節點,指定的節點宕機了

  1. ping消息

ping 很頻繁,且攜帶元數據,會加重網絡負擔
每個節點每秒會執行 10 次 ping,每次選擇 5 個最久沒有通信的其他節點
當如果發現某個節點通信延遲達到了 cluster_node_timeout /2 ,那麼立即發送 ping, 避免數據交換延遲過長,落後時間太長(2 個節點之間 10 分鐘沒有交換數據,整個集群處於嚴重的元數據不一致的情況)。
每次ping,一個是帶上自己的節點信息,還有就是帶上1/10其他節點的信息,發送出去,進行數據交換
至少包含 3 個其他節點信息,最多包含總節點-2 個其他節點的信息

  1. JRedis原理
  • 請求重定向

客戶端發送到任意一個redis實例發送命令,每個redis實例接受到命令後,都會計算key對應的hash slot,如果在本地就本地處理,否則返回moved給客戶端,讓客戶端進行重定向 (redis-cli -c)

  • hash slot

通過tag指定key對應的slot,同一個 tag 下的 key,都會在一個 hash slot中,比如 set key1:{100} 和 set key2:{100}

  • smart jedis

本地維護一份hashslot->node的映射表。
JedisCluster 初始化的時候,隨機選擇一個 node,初始化 hashslot->node 映射表,同時為每個節點創建一個JedisPool連接池,每次基於JedisCluster執行操作,首先JedisCluster都會在本地計算key的hashslot,然後再本地映射表中找到對應的節點,如果發現對應的節點返回moved,那麼利用該節點的元數據,更新 hashslot->node映射表(重試超過 5 次報錯)

  • hashslot遷移和ask重定向

hash slot正在遷移,那麼會返回ask 重定向給jedis,jedis 接受到ask重定向之後,,會重定向到目標節點去執行

  • 高可用性和主備切換原理

判斷節點宕機:
如果一個節點認為另外一個節點宕機了, 就是pfail,主觀宕機
如果多個節點都認為另外一個節點宕機了,那麼就是fail,客觀宕機(跟哨兵原理一樣)


在cluster-node-timeout內,某個節點一直沒有返回 pong,那麼就被認為是 pfail
如果一個節點認為某個節點pfail了,那麼會在gossip消息中,ping給其他節點,如果超過半數的節點認為pfail了,那麼就會變成fail。
從節點過濾:
對宕機的 mster node ,從其所有的 slave node中,選擇一個切換成 master node
檢查每個 slave node與master node斷開連接的時間,如果超過了cluster-node-timeout * cluster-slave-validity-factor,那麼就沒資格切換成 master(和哨兵一致)
從節點選舉:
每個從節點,根據自己對 master 複製數據的 offset,設置一個選舉時間,offset越大(複製數據越多)的從節點,選舉時間越靠前,所有的 master node 開始投票,給要進行選舉的 slave進行投票,如果大部分 master node(N/2 +1) 都投票給某個從節點,那麼選舉通過,從節點執行主備切換,從節點切換成主節點
總結:和哨兵很像,直接集成了 replication 和 sentinal

緩存雪崩

面試官:Redis 這些我必問

方案:
事前:保證 redis 集群高可用性 (主從+哨兵或 redis cluster),避免全盤崩潰
事中:本地 ehcache 緩存 + hystrix 限流(保護數據庫) & 降級,避免 MySQL被打死
事後: redis持久化,快速恢復緩存數據,繼續分流高併發請求

限制組件每秒就 2000 個請求通過限流組件進入數據庫,剩餘的 3000 個請求走降級,返回一些默認 的值,或者友情提示
好處 :

  1. 數據庫絕對不會死,確保了每秒只會過去 2000 個請求
  2. 只要數據庫不死,對於用戶來說 2/5的請求可以被處理
  3. 系統沒死,用戶多點幾次可能就刷出來了

緩存穿透

面試官:Redis 這些我必問


4000 個請求黑客攻擊請求數據庫裡沒有的數據
解決方案:把黑客查數據庫中不存在的數據的值,寫到緩存中,比如: set -999 UNKNOWN

緩存與數據庫雙寫一致性

  1. cache aside pattern
面試官:Redis 這些我必問


讀的時候,先讀緩存,緩存沒有,就讀數據庫,然後取出數據後放入緩存,同時返回響應


更新的時候,刪除緩存,更新數據庫
為什麼不更新緩存:
更新緩存代價太高(更新 20 次,只讀 1 次),lazy思想,需要的時候再計算,不需要的時候不計算

  1. 修改數據庫成功,刪除緩存失敗,導致數據庫是新的數據,緩存中是舊的數據

方案:先刪除緩存,再修改數據庫

面試官:Redis 這些我必問


面試官:Redis 這些我必問

  1. 修改數據庫還沒修改完,同時又有查詢請求,把舊的數據放到緩存中(高併發,每秒併發讀幾萬,每秒只要有數據更新請求,就可能出現數據庫+緩存不一致情況)

方案:寫,讀路由到相同的一個內存隊列(唯一標識,hash,取模)裡,更新和讀操作進行串行化(後臺線程異步執行隊列串行化操作),(隊列裡只放一個更新查詢操作即可,多餘的過濾掉,內存隊列裡沒有該數據更新操作,直接返回 )有該數據更新操作則輪詢取緩存值,超時取不到緩存值,直接取一次數據庫的舊值


面試官:Redis 這些我必問


TP 99 意思是99%的請求可以在200ms內返回
注意點:多個商品的更新操作都積壓在一個隊列裡面(太多操作積壓只能增加機器),導致讀請求發生大量的超時,導致大量的讀請求走數據庫
一秒 500 寫操作,每200ms,100 個寫操作,20 個內存隊列,每個隊列積壓 5 個寫操作,一般在20ms完成

Redis 併發競爭問題

面試官:Redis 這些我必問


方案:分佈式鎖 + 時間戳比較

Redis 集群部署架構

10臺機器,5 主 5 從,每個節點QPS 5W ,一共 25W QPS(Redis cluster 32G + 8 核 ,Redis 進程不超過 10G)總內存 50g,每條數據10kb,10W 條數據1g,200W 條數據 20G,佔用總內存不到50%,目前高峰期 3500 QPS


分享到:


相關文章: