天天看點

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

  • Redis主從
  • Redis哨兵
  • Redis Cluster叢集
  • 公衆号:撿田螺的小男孩

\1. Redis 主從

面試官經常會問到Redis的高可用。Redis高可用回答包括兩個層面,一個就是資料不能丢失,或者說盡量減少丢失;另外一個就是保證Redis服務不中斷。

  • 對于盡量減少資料丢失,可以通過AOF和RDB保證。
  • 對于保證服務不中斷的話,Redis就不能單點部署,這時候我們先看下Redis主從。

1.1 Redsi主從概念

  • Redis主從模式,就是部署多台Redis伺服器,有主庫和從庫,它們之間通過主從複制,以保證資料副本的一緻。
  • 主從庫之間采用的是讀寫分離的方式,其中主庫負責讀操作和寫操作,從庫則負責讀操作。
  • 如果Redis主庫挂了,切換其中的從庫成為主庫。

1.2 Redis 主從同步過程

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

Redis主從同步包括三個階段。

第一階段:主從庫間建立連接配接、協商同步。

  • 從庫向主庫發送

    psync

    指令,告訴它要進行資料同步。
  • 主庫收到

    psync

    指令後,響應

    FULLRESYNC

    指令(它表示第一次複制采用的是全量複制),并帶上主庫

    runID

    和主庫目前的複制進度

    offset

    第二階段:主庫把資料同步到從庫,從庫收到資料後,完成本地加載。

  • 主庫執行

    bgsave

    指令,生成

    RDB

    檔案,接着将檔案發給從庫。從庫接收到

    RDB

    檔案後,會先清空目前資料庫,然後加載 RDB 檔案。
  • 主庫把資料同步到從庫的過程中,新來的寫操作,會記錄到

    replication buffer

    第三階段,主庫把新寫的指令,發送到從庫。

  • 主庫完成RDB發送後,會把

    replication buffer

    中的修改操作發給從庫,從庫再重新執行這些操作。這樣主從庫就實作同步啦。

    1.3 Redis主從的一些注意點

    1.3.1 主從資料不一緻

    因為主從複制是異步進行的,如果從庫滞後執行,則會導緻主從資料不一緻。

    主從資料不一緻一般有兩個原因:

  • 主從庫網路延遲。
  • 從庫收到了主從指令,但是它正在執行阻塞性的指令(如

    hgetall

    等)。

如何解決主從資料不一緻問題呢?

  1. 可以換更好的硬體配置,保證網絡暢通。
  2. 監控主從庫間的複制進度

1.3.2 讀取過期資料

Redis删除資料有這幾種政策:

  • 惰性删除:隻有當通路一個key時,才會判斷該key是否已過期,過期則清除。
  • 定期删除:每隔一定的時間,會掃描一定數量的資料庫的expires字典中一定數量的key,并清除其中已過期的key。
  • 主動删除:目前已用記憶體超過最大限定時,觸發主動清理政策。

如果使用Redis版本低于3.2,讀從庫時,并不會判斷資料是否過期,而是會傳回過期資料。而3.2 版本後,Redis做了改進,如果讀到的資料已經過期了,從庫不會删除,卻會傳回空值,避免了用戶端讀到過期資料。

是以,在主從Redis模式下,盡量使用 Redis 3.2以上的版本。

1.3.3 一主多從,全量複制時主庫壓力問題

如果是一主多從模式,從庫很多的時候,如果每個從庫都要和主庫進行全量複制的話,主庫的壓力是很大的。因為主庫fork程序生成RDB,這個fork的過程是會阻塞主線程處理正常請求的。同時,傳輸大的RDB檔案也會占用主庫的網絡寬帶。

可以使用主-從-從模式解決。什麼是主從從模式呢?其實就是部署主從叢集時,選擇硬體網絡配置比較好的一個從庫,讓它跟部分從庫再建立主從關系。如圖:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

1.3.4 主從網絡斷了怎麼辦呢?

主從庫完成了全量複制後,它們之間會維護一個網絡長連接配接,用于主庫後續收到寫指令傳輸到從庫,它可以避免頻繁建立連接配接的開銷。但是,如果網絡斷開重連後,是否還需要進行一次全量複制呢?

如果是Redis 2.8之前,從庫和主庫重連後,确實會再進行一次全量複制,但是這樣開銷就很大。而Redis 2.8之後做了優化,重連後采用增量複制方式,即把主從庫網絡斷連期間主庫收到的寫指令,同步給從庫。

主從庫重連後,就是利用repl_backlog_buffer實作增量複制。

當主從庫斷開連接配接後,主庫會把斷連期間收到的寫操作指令,寫入replication buffer,同時也會把這些操作指令寫入repl_backlog_buffer這個緩沖區。repl_backlog_buffer是一個環形緩沖區,主庫會記錄自己寫到的位置,從庫則會記錄自己已經讀到的位置。

\2. Redis哨兵

主從模式中,一旦主節點由于故障不能提供服務,需要人工将從節點晉升為主節點,同時還要通知應用方更新主節點位址。顯然,多數業務場景都不能接受這種故障處理方式。Redis從2.8開始正式提供了Redis哨兵機制來解決這個問題。

  • 哨兵作用
  • 哨兵模式簡介
  • 哨兵如何判定主庫下線
  • 哨兵模式如何工作
  • 哨兵是如何選主的
  • 由哪個哨兵執行主從切換呢?
  • 哨兵下的故障轉移

2.1 哨兵作用

哨兵其實是一個運作在特殊模式下的Redis程序。它有三個作用,分别是:監控、自動選主切換(簡稱選主)、通知。

哨兵程序在運作期間,監視所有的Redis主節點和從節點。它通過周期性給主從庫發送

PING

指令,檢測主從庫是否挂了。如果從庫沒有在規定時間内響應哨兵的

PING

指令,哨兵就會把它标記為下線狀态;如果主庫沒有在規定時間内響應哨兵的

PING

指令,哨兵則會判定主庫下線,然後開始切換到選主任務。

所謂選主,其實就是從多個從庫中,按照一定規則,選出一個當做主庫。至于通知呢,就是選出主庫後,哨兵把新主庫的連接配接資訊發給其他從庫,讓它們和新主庫建立主從關系。同時,哨兵也會把新主庫的連接配接資訊通知給用戶端,讓它們把請求操作發到新主庫上。

2.2 哨兵模式

因為Redis哨兵也是一個Redis程序,如果它自己挂了呢,那是不是就起不了監控的作用啦。我們一起來看下Redis哨兵模式

哨兵模式,就是由一個或多個哨兵執行個體組成的哨兵系統,它可以監視所有的Redis主節點和從節點,并在被監視的主節點進入下線狀态時,自動将下線主伺服器屬下的某個從節點更新為新的主節點。,一個哨兵程序對Redis節點進行監控,就可能會出現問題(單點問題)。是以,一般使用多個哨兵來進行監控Redis節點,并且各個哨兵之間還會進行監控。

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

其實哨兵之間是通過釋出訂閱機制組成叢集的,同時,哨兵又通過

INFO

指令,獲得了從庫連接配接資訊,也能和從庫建立連接配接,進而進行監控。

2.3 哨兵如何判定主庫下線

哨兵是如何判斷主庫是否下線的呢?我們先來了解兩個基礎概念哈:主觀下線和客觀下線。

  • 哨兵程序向主庫、從庫發送PING指令,如果主庫或者從庫沒有在規定的時間内響應PING指令,哨兵就把它标記為主觀下線。
  • 如果是主庫被标記為主觀下線,則正在監視這個主庫的所有哨兵要以每秒一次的頻率,以确認主庫是否真的進入了主觀下線。 當有多數的哨兵(一般少數服從多數,由 Redis 管理者自行設定的一個值)在指定的時間範圍内确認主庫的确進入了主觀下線狀态,則主庫會被标記為客觀下線。這樣做的目的就是避免對主庫的誤判,以減少沒有必要的主從切換,減少不必要的開銷。

假設我們有

N

個哨兵執行個體,如果有

N/2+1

個執行個體判斷主庫主觀下線,此時就可以把節點标記為客觀下線,就可以做主從切換了。

2.4 哨兵的工作模式

  1. 每個哨兵以每秒鐘一次的頻率向它所知的主庫、從庫以及其他哨兵執行個體發送一個

    PING

    指令。
  2. 如果一個執行個體節點距離最後一次有效回複

    PING

    指令的時間超過

    down-after-milliseconds

    選項所指定的值, 則這個執行個體會被哨兵标記為主觀下線。
  3. 如果主庫被标記為主觀下線,則正在監視這個主庫的所有哨兵要以每秒一次的頻率确認主庫的确進入了主觀下線狀态。
  4. 當有足夠數量的哨兵(大于等于配置檔案指定的值)在指定的時間範圍内确認主庫的确進入了主觀下線狀态, 則主庫會被标記為客觀下線。
  5. 當主庫被哨兵标記為客觀下線時,就會進入選主模式。
  6. 若沒有足夠數量的哨兵同意主庫已經進入主觀下線, 主庫的主觀下線狀态就會被移除;若主庫重新向哨兵的

    PING

    指令傳回有效回複,主庫的主觀下線狀态就會被移除。

2.5 哨兵是如何選主的?

如果明确主庫已經客觀下線了,哨兵就開始了選主模式。

哨兵選主包括兩大過程,分别是:過濾和打分。其實就是在多個從庫中,先按照一定的篩選條件,把不符合條件的從庫過濾掉。然後再按照一定的規則,給剩下的從庫逐個打分,将得分最高的從庫選為新主庫

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂
  • 選主時,會判斷從庫的狀态,如果已經下線,就直接過濾。
  • 如果從庫網絡不好,老是逾時,也會被過濾掉。看這個參數

    down-after-milliseconds

    ,它表示我們認定主從庫斷連的最大連接配接逾時時間。
  • 過濾掉了不适合做主庫的從庫後,就可以給剩下的從庫打分,按這三個規則打分:從庫優先級、從庫複制進度以及從庫ID号。
  • 從庫優先級最高的話,打分就越高,優先級可以通過

    slave-priority

    配置。如果優先級一樣,就選與舊的主庫複制進度最快的從庫。如果優先級和從庫進度都一樣,從庫ID 号小的打分高。

2.6 由哪個哨兵執行主從切換呢?

一個哨兵标記主庫為主觀下線後,它會征求其他哨兵的意見,确認主庫是否的确進入了主觀下線狀态。它向其他執行個體哨兵發送

is-master-down-by-addr

指令。其他哨兵會根據自己和主庫的連接配接情況,回應

Y

N

(Y 表示贊成,N表示反對票)。如果這個哨兵擷取得足夠多的贊成票數(

quorum

配置),主庫會被标記為客觀下線。

标記主庫客觀下線的這個哨兵,緊接着向其他哨兵發送指令,再發起投票,希望它可以來執行主從切換。這個投票過程稱為Leader 選舉。因為最終執行主從切換的哨兵稱為Leader,投票過程就是确定Leader。一個哨兵想成為Leader需要滿足兩個條件:

  • 需要拿到

    num(sentinels)/2+1

    的贊成票。
  • 并且拿到的票數需要大于等于哨兵配置檔案中的

    quorum

    值。

舉個例子,假設有3個哨兵。配置的quorum值為2。即一個一個哨兵想成為Leader至少需要拿到2張票。為了更好了解,大家可以看下

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂
  • 在t1時刻,哨兵A1判斷主庫為客觀下線,它想成為主從切換的Leader,于是先給自己投一張贊成票,然後分别向哨兵A2 和A3發起投票指令,表示想成為 Leader。
  • 在 t2 時刻,A3 判斷主庫為客觀下線,它也想成為 Leader,是以也先給自己投一張贊成票,再分别向 A1 和 A2 發起投票指令,表示也要成為 Leader。
  • 在 t3 時刻,哨兵A1 收到了A3 的Leader投票請求。因為A1已經把票Y投給自己了,是以它不能再給其他哨兵投贊成票了,是以A1投票

    N

    給A3。
  • 在 t4時刻,哨兵A2收到A3 的Leader投票請求,因為哨兵A2之前沒有投過票,它會給第一個向它發送投票請求的哨兵回複贊成票

    Y

  • 在 t5時刻,哨兵A2收到A1 的Leader投票請求,因為哨兵A2之前已經投過贊成票給A3了,是以它隻能給A1投反對票

    N

  • 最後t6時刻,哨兵A1隻收到自己的一票

    Y

    贊成票,而哨兵A3得到兩張贊成票(A2和A3投的),是以哨兵A3成為了Leader。

假設網絡故障等原因,哨兵A3也沒有收到兩張票,那麼這輪投票就不會産生Leader。哨兵叢集會等待一段時間(一般是哨兵故障轉移逾時時間的2倍),再進行重新選舉。

2.7 故障轉移

假設哨兵模式架構如下,有三個哨兵,一個主庫M,兩個從庫S1和S2。

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

當哨兵檢測到Redis主庫M1出現故障,那麼哨兵需要對叢集進行故障轉移。假設選出了哨兵3作為Leader。故障轉移流程如下:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂
  1. 從庫S1解除從節點身份,更新為新主庫
  2. 從庫S2成為新主庫的從庫
  3. 原主節點恢複也變成新主庫的從節點
  4. 通知用戶端應用程式新主節點的位址。

故障轉移後:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

3.Redis Cluster叢集

哨兵模式基于主從模式,實作讀寫分離,它還可以自動切換,系統可用性更高。但是它每個節點存儲的資料是一樣的,浪費記憶體,并且不好線上擴容。是以,Reids Cluster叢集(切片叢集的實作方案)應運而生,它在Redis3.0加入的,實作了Redis的分布式存儲。對資料進行分片,也就是說每台Redis節點上存儲不同的内容,來解決線上擴容的問題。并且,它可以儲存大量資料,即分散資料到各個Redis執行個體,還提供複制和故障轉移的功能。

比如你一個Redis執行個體儲存15G甚至更大的資料,響應就會很慢,這是因為Redis RDB 持久化機制導緻的,Redis會fork子程序完成 RDB 持久化操作,fork執行的耗時與 Redis 資料量成正相關。

這時候你很容易想到,把15G資料分散來存儲就好了嘛。這就是Redis切片叢集的初衷。切片叢集是啥呢?來看個例子,如果你要用Redis儲存15G的資料,可以用單執行個體Redis,或者3台Redis執行個體組成切片叢集,對比如下:

切片叢集和Redis Cluster 的差別:Redis Cluster是從Redis3.0版本開始,官方提供的一種實作切片叢集的方案。

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

既然資料是分片分布到不同Redis執行個體的,那用戶端到底是怎麼确定想要通路的資料在哪個執行個體上呢?我們一起來看下Reids Cluster是怎麼做的哈。

3.1 哈希槽(Hash Slot)

Redis Cluster方案采用哈希槽(

Hash Slot

),來處理資料和執行個體之間的映射關系。

一個切片叢集被分為

16384

個slot(槽),每個進入Redis的鍵值對,根據key進行散列,配置設定到這16384插槽中的一個。使用的哈希映射也比較簡單,用

CRC16

算法計算出一個

16bit

的值,再對

16384

取模。資料庫中的每個鍵都屬于這16384個槽的其中一個,叢集中的每個節點都可以處理這16384個槽。

叢集中的每個節點負責一部分的哈希槽,假設目前叢集有A、B、C3個節點,每個節點上負責的哈希槽數 =16384/3,那麼可能存在的一種配置設定:

  • 節點A負責0~5460号哈希槽
  • 節點B負責5461~10922号哈希槽
  • 節點C負責10923~16383号哈希槽

用戶端給一個Redis執行個體發送資料讀寫操作時,如果這個執行個體上并沒有相應的資料,會怎麼樣呢?MOVED重定向和ASK重定向了解一下哈

3.2 MOVED重定向和ASK重定向

在Redis cluster模式下,節點對請求的處理過程如下:

  1. 通過哈希槽映射,檢查目前Redis key是否存在目前節點
  2. 若哈希槽不是由自身節點負責,就傳回MOVED重定向
  3. 若哈希槽确實由自身負責,且key在slot中,則傳回該key對應結果
  4. 若Redis key不存在此哈希槽中,檢查該哈希槽是否正在遷出(MIGRATING)?
  5. 若Redis key正在遷出,傳回ASK錯誤重定向用戶端到遷移的目的伺服器上
  6. 若哈希槽未遷出,檢查哈希槽是否導入中?
  7. 若哈希槽導入中且有ASKING标記,則直接操作,否則傳回MOVED重定向

3.2.1 Moved 重定向

用戶端給一個Redis執行個體發送資料讀寫操作時,如果計算出來的槽不是在該節點上,這時候它會傳回MOVED重定向錯誤,MOVED重定向錯誤中,會将哈希槽所在的新執行個體的IP和port端口帶回去。這就是Redis Cluster的MOVED重定向機制。流程圖如下:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

3.2.2 ASK 重定向

Ask重定向一般發生于叢集伸縮的時候。叢集伸縮會導緻槽遷移,當我們去源節點通路時,此時資料已經可能已經遷移到了目标節點,使用Ask重定向可以解決此種情況。

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

3.3 Cluster叢集節點的通訊協定:Gossip

一個Redis叢集由多個節點組成,各個節點之間是怎麼通信的呢?通過Gossip協定!Gossip是一種謠言傳播協定,每個節點周期性地從節點清單中選擇 k 個節點,将本節點存儲的資訊傳播出去,直到所有節點資訊一緻,即算法收斂了。

Gossip協定基本思想:一個節點想要分享一些資訊給網絡中的其他的一些節點。于是,它周期性的随機選擇一些節點,并把資訊傳遞給這些節點。這些收到資訊的節點接下來會做同樣的事情,即把這些資訊傳遞給其他一些随機選擇的節點。一般而言,資訊會周期性的傳遞給N個目标節點,而不隻是一個。這個N被稱為fanout

Redis Cluster叢集通過Gossip協定進行通信,節點之前不斷交換資訊,交換的資訊内容包括節點出現故障、新節點加入、主從節點變更資訊、slot資訊等等。gossip協定包含多種消息類型,包括ping,pong,meet,fail,等等

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂
  • meet消息:通知新節點加入。消息發送者通知接收者加入到目前叢集,meet消息通信正常完成後,接收節點會加入到叢集中并進行周期性的ping、pong消息交換。
  • ping消息:節點每秒會向叢集中其他節點發送 ping 消息,消息中帶有自己已知的兩個節點的位址、槽、狀态資訊、最後一次通信時間等
  • pong消息:當接收到ping、meet消息時,作為響應消息回複給發送方确認消息正常通信。消息中同樣帶有自己已知的兩個節點資訊。
  • fail消息:當節點判定叢集内另一個節點下線時,會向叢集内廣播一個fail消息,其他節點接收到fail消息之後把對應節點更新為下線狀态。

特别的,每個節點是通過叢集總線(cluster bus) 與其他的節點進行通信的。通訊時,使用特殊的端口号,即對外服務端口号加10000。例如如果某個node的端口号是6379,那麼它與其它nodes通信的端口号是 16379。nodes 之間的通信采用特殊的二進制協定。

3.4 故障轉移

Redis叢集實作了高可用,當叢集内節點出現故障時,通過故障轉移,以保證叢集正常對外提供服務。

redis叢集通過ping/pong消息,實作故障發現。這個環境包括主觀下線和客觀下線。

主觀下線: 某個節點認為另一個節點不可用,即下線狀态,這個狀态并不是最終的故障判定,隻能代表一個節點的意見,可能存在誤判情況。

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

客觀下線: 名額記一個節點真正的下線,叢集内多個節點都認為該節點不可用,進而達成共識的結果。如果是持有槽的主節點故障,需要為該節點進行故障轉移。

  • 假如節點A标記節點B為主觀下線,一段時間後,節點A通過消息把節點B的狀态發到其它節點,當節點C接受到消息并解析出消息體時,如果發現節點B的pfail狀态時,會觸發客觀下線流程;
  • 當下線為主節點時,此時Redis Cluster叢集為統計持有槽的主節點投票,看投票數是否達到一半,當下線報告統計數大于一半時,被标記為客觀下線狀态。

流程如下:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

故障恢複:故障發現後,如果下線節點的是主節點,則需要在它的從節點中選一個替換它,以保證叢集的高可用。流程如下:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂
  • 資格檢查:檢查從節點是否具備替換故障主節點的條件。
  • 準備選舉時間:資格檢查通過後,更新觸發故障選舉時間。
  • 發起選舉:到了故障選舉時間,進行選舉。
  • 選舉投票:隻有持有槽的主節點才有票,從節點收集到足夠的選票(大于一半),觸發替換主節點操作

3.5 加餐:為什麼Redis Cluster的Hash Slot 是16384?

對于用戶端請求過來的鍵值key,哈希槽=

CRC16(key) % 16384

,CRC16算法産生的哈希值是16bit的,按道理該算法是可以産生2^16=65536個值,為什麼不用65536,用的是

16384(2^14)

呢?

大家可以看下作者的原始回答:

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂

Redis 每個執行個體節點上都儲存對應有哪些slots,它是一個

unsigned char slots[REDIS_CLUSTER_SLOTS/8]

類型

Redis主從、哨兵、 Cluster叢集一鍋端,一篇文字搞懂
  • 在redis節點發送心跳包時需要把所有的槽放到這個心跳包裡,如果slots數量是

    65536

    ,占空間=

    65536 / 8(一個位元組8bit) / 1024(1024個位元組1kB) =8kB

    ,如果使用slots數量是

    16384

    ,所占空間 =

    16384 / 8(每個位元組8bit) / 1024(1024個位元組1kB) = 2kB

    ,可見16384個slots比 65536省 6kB記憶體左右,假如一個叢集有100個節點,那每個執行個體裡就省了600kB啦
  • 一般情況下Redis cluster叢集主節點數量基本不可能超過1000個,超過1000會導緻網絡擁堵。對于節點數在1000以内的Redis cluster叢集,16384個槽位其實夠用了。

既然為了節省記憶體網絡開銷,為什麼 slots不選擇用8192(即16384/2) 呢?

8192 / 8(每個位元組8bit) / 1024(1024個位元組1kB) = 1kB ,隻需要1KB!可以先看下Redis 把 Key 換算成所屬 slots 的方法

unsigned int keyHashSlot(char *key, int keylen) {



    int s, e; /* start-end indexes of { and } */



 



    for (s = 0; s < keylen; s++)



        if (key[s] == '{') break;



 



    /* No '{' ? Hash the whole key. This is the base case. */



    if (s == keylen) return crc16(key,keylen) & 0x3FFF;



 



    /* '{' found? Check if we have the corresponding '}'. */



    for (e = s+1; e < keylen; e++)



        if (key[e] == '}') break;



 



    /* No '}' or nothing betweeen {} ? Hash the whole key. */



    if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF;



 



    /* If we are here there is both a { and a } on its right. Hash



     * what is in the middle between { and }. */



    return crc16(key+s+1,e-s-1) & 0x3FFF;



}
           

Redis 将key換算成slots 的方法:其實就是是将crc16(key) 之後再和slots的數量進行與計算

這裡為什麼用

0x3FFF(16383)

來計算,而不是

16384

呢?因為在不産生溢出的情況下

x % (2^n)

等價于

x & (2^n - 1)

x % 16384 == x & 16383

那到底為什麼不用8192呢?

crc16 出來結果,理論上出現重複的機率為 1⁄65536,但實際結果重複機率可能比這個大不少,就像crc32 結果 理論上 1/40億 分之一,但實際有人測下來10萬碰撞的機率就比較大了。假如 slots 設定成 8192, 200個執行個體的節點情況下,理論值是 每40個不同key請求,命中就會失效一次,假如節點數增加到400,那就是20個請求。并且1kb 并不會比 2k 省太多,成本效益不是特别高,是以可能 選16384會更為通用一點。