最近在看《Redis開發與運維》,把本身學會的知識點記錄下來,畢竟好記性不如爛筆頭。node
一.Redis是什麼。redis
Redis是一個Key-Value的NoSQL數據庫.算法
二.Redis的特色。數據庫
1.支持的數據類型:hash,list,set,zset,string(memacached只支持string)。後端
2.單線程執行命令。由於是單線程,因此減小了線程上下文切換的開銷,同時若是一個命令執行時間過長就會引發阻塞。數組
3.數據持久化到內存中,必定時間後會存儲到硬盤中。緩存
三.操做數據的命令
1.經常使用的命令服務器
命令 | 含義 |
---|---|
keys * | 查看所有的鍵,會遍歷Redis全部的鍵,時間複雜度是O(n) |
scan cursor match pattern | 遍歷鍵,cursor是遊標 |
type key | 查看鍵的類型,key是鍵的名稱 |
dbsize | 查看鍵的數量:dbsize 是直接獲取Redis內置的鍵總量,時間複雜度是O(1) |
exists key | 判斷某個鍵是否存在,存在返回1,不存在返回0. |
del key[ key...] | 返回成功刪除鍵的個數 |
expire key time | 設置鍵的過時時間 |
ttl key | 查詢某個鍵的剩餘過時時間 |
object encoding key | 查詢鍵的內部編碼 |
rename key newkey | 鍵重命名 |
renamenx key newkey | 當newkey不存在,鍵重命名成功 |
randomkey | 隨機選擇一個鍵 |
persist key | 清除鍵的過時時間 |
move key db | 在Redis內部進行數據庫遷移 |
dump + restore | 在不一樣Redis實例間遷移數據 |
migrate | 在數據庫實例間遷移數據 |
2.操做String數據類型的命令網絡
注意:操做String數據類型的命令基本以s做爲前綴開頭session
命令 | 含義 |
---|---|
set key value | 插入鍵值對,key是鍵,value是值 |
get key | 查看鍵的值 |
del key | 刪除鍵 |
setnx key value | 當key不存在時,設置值 |
setex key seconds value | seconds是過時時間,設置鍵值對 |
mset key value[key value..] | 批量獲取值 |
mget key [key ...] | 批量獲取值 |
incr key | 對值作自增1 |
decr key | 對值作自減1 |
incrby key incrment | 自增指定的數目 increment 數字 |
decrby key incrment | 自減指定的數目 increment 數字 |
incrbyfloat key incrment | 自增指定的浮點數 increment 數字 |
內部編碼有三種:int,embstr和raw
使用場景:
統一管理用戶的session
3.操做hash數據類型的命令
注意:操做hash數據類型的命令基本以h做爲前綴開頭
命令 | 含義 |
---|---|
hset key field value | 設置hash的內容key=[{field:value}{field:value}] |
hget key field | 獲取字段值 |
hdel key field | 刪除字段值 |
hlen key | 獲取key的字段數 |
hmset key field value [field value...] | 批量設置key的field-value |
hmget key field1[field2...] | 批量得到key的field的字段值 |
hexists key field | 判斷key的field是否存在 |
hkeys key | 獲取key的所有字段 |
hvals key | 獲取key的所有value值 |
hgetall key | 獲取key的所有field,value |
hincrby key field incrment | key的字段field自增increment |
hincrbyfloat key field increment | key的字段field自增浮點數increment |
hstrlen key field | 計算field的value的長度 |
內部編碼:ziplist和hashtable
4.操做list數據類型的命令
注意:操做list數據類型的命令基本以l或r或b做爲前綴開頭
命令 | 含義 |
---|---|
rpush key value[value...] | 從列表右邊添加元素 |
lpush key value[value...] | 從列表左邊添加元素 |
lrange key start end | 獲取指定索引範圍的元素,0表示第一個,-1表示最後一個 |
linsert key before/after pivot value | 在pivot元素前/後插入value元素 |
lindex key index | 獲取列表指定下標的元素 |
llen key | 獲取列表的長度 |
lpop key | 從列表的左側彈出元素 |
rpop key | 從列表的右側彈出元素 |
lrem key count value | 從左到右刪除count個值爲value的元素 |
lset key index value | 設置index位置的值 |
brpop/blpop key timeout | 阻塞彈出,timeout是超時時間,0表示一直等待下去 |
內部編碼:ziplist(壓縮列表),linkedlist(鏈表)和quicklist
使用場景:
5.操做set數據類型的命令
注意:操做set數據類型的命令基本以s做爲前綴開頭
命令 | 含義 |
---|---|
sadd key element[element...] | 添加元素 |
srem key element[element...] | 刪除元素 |
scard key | 計算元素個數 |
sismember key element | 判斷element元素是否在集合中 |
srandmember key [count] | 隨機生成count個元素,默認是1個 |
spop key | 隨機彈出一個元素 |
smembers key | 查詢所有的元素 |
sinter key [key...] | 查詢多個集合的並集 |
sunion key [key...] | 查詢多個集合的交集 |
sdiff key [key...] | 查詢多個集合的差集 |
sinterstore destination key [key...] | 查詢多個集合的並集,存儲到destination中 |
sunionstore destination key [key...] | 查詢多個集合的交集,存儲到destination中 |
sdiffstore destination key [key...] | 查詢多個集合的差集,存儲到destination中 |
內部編碼:intset,hashtable
使用場景:
sadd+sinter=Social Graph(社交需求)
6.操做zset數據類型的命令
注意:操做zset數據類型的命令基本以z做爲前綴開頭
命令 | 含義 |
---|---|
zadd key score memeber[score memeber...] | 添加成員 |
zcard key | 計算成員個數 |
zscore key member | 計算成員的分數 |
zrank/zrevrank key member | 計算成員的排名 |
zrem key member[member...] | 刪除成員 |
zincrby key increment member | 增長成員的分數 |
zrange/zrevrange key start end [withscores] | 從低到高,返回指定排名範圍的成員 |
zrangebyscore key min max [withscores] [limit offset count] | 從低到高,返回指定分數範圍的成員 |
zrevrangebyscore key max min [withscores] [limit offset count] | 返回指定分數範圍的成員 |
zcount key min max | 返回指定範圍的成員個數 |
zremrangebyrank key start end | 刪除指定排名內的升序元素 |
zremrangebyscore key min max | 刪除指定分數範圍的成員 |
zinterstore destination numberkeys key [key...] [weights weight [weight...]] [aggregate sum/min/max] | 兩個有序集合的交集,numberkeys指有序集合進行交集的個數 |
zunionstore destination numberkeys key [key...] [weights weight [weight...]] [aggregate sum/min/max] | 兩個有序集合的並集,numberkeys指有序集合進行並集的個數 |
內部編碼:ziplist(壓縮列表)和skiplist(跳躍表)
使用場景:
7.Jedis對五種數據類型的操做
Jedis jedis = null; try { jedis = new Jedis("127.0.0.1", 6379, 10000); //1.string String result1 = jedis.set("string1", "value1"); String result2 = jedis.get("string1"); System.out.println(result1);//OK System.out.println(result2);//value1 //2.list long result3 = jedis.lpush("list1", "math","math","score","score","name","xiaoming"); List<String> result4 = jedis.lrange("list1", 0, -1); System.out.println(result1);//OK System.out.println(result4);//xiaoming, name, score, score, math, math //3.hash jedis.hset("hash1", "subject","math"); jedis.hset("hash1", "score","99"); jedis.hset("hash1", "name","xiaoming"); List<String> result5 = jedis.hmget("hash1", "subject","score","name"); System.out.println(result5);//[math, 99, xiaoming] //4.set jedis.sadd("set1", "math","math","english","chinese"); jedis.sadd("set2", "math","chinese","art"); jedis.sinterstore("set3", "set1","set2"); System.out.println(jedis.smembers("set3"));//[math, chinese] //5.zset jedis.zadd("zset1", 100, "math"); jedis.zadd("zset1", 200, "chinese"); jedis.zadd("zset1", 300, "english"); Set<String> result6 = jedis.zrangeByScore("zset1", 100, 200); result6.forEach(string -> { System.out.print(string+" "); });//math chinese }catch(Exception e) { e.printStackTrace(); }finally { if(jedis != null) { jedis.close(); } }
四.客戶端操做
1.client list
列出與Redis服務器相連的全部客戶端信息。
屬性以下:
名稱 | 含義 |
---|---|
id | 客戶端的惟一標識。自增,重啓後重置爲0。 |
addr | 客戶端鏈接的地址和端口。 |
fd | socket的文件描述符。 |
name | 客戶端的名稱。 |
age | 當前客戶端的鏈接時間。 |
idle | 當前客戶端的最近一次空閒時間。當age等於idle表示鏈接一直處於空閒狀態。 |
flags | 標識當前客戶端的類型。 |
db | 當前客戶端正在使用的數據庫索引下標。 |
sub | 當前客戶端訂閱的頻道或者模式數。 |
psub | 當前客戶端訂閱的頻道或者模式數。 |
multi | 當前事務中已執行命令個數。 |
qbuf | 輸入緩衝區總容量。 |
qbuf-free | 輸入緩衝區的剩餘容量。 |
obl | 輸出緩衝區的固定緩衝區的大小。 |
oll | 輸出緩衝區的動態緩衝區的大小。 |
omem | 輸出緩衝區使用的字節數。 |
events | 文件描述符事件。 |
cmd | 當前客戶端最後一次執行的命令。 |
2.輸入緩衝區
做用:客戶端發送的命令不是直接發送給Redis服務器,而是先存放在輸入緩衝區,Redis服務器從輸入緩衝區中得到命令並執行。
當輸入緩衝區的輸入速度大於Redis服務器的處理速度且存在大量的bigkey或是Redis服務器發生阻塞,短時間不能執行命令時,都會形成輸入緩衝區過大,能夠經過client list查看qbuf和qbuf-free的大小或是經過info clients命令找到最大的輸入緩衝區。
3.輸出緩衝區
做用:Redis服務器執行命令後的結果不是直接返回給客戶端,而是先存放在輸出緩衝區。
輸出緩衝區分爲固定緩衝區和動態緩衝區,固定緩衝區是字節數組,動態緩衝區是列表,固定緩衝區使用完以後纔會使用動態緩衝區。
經過client list和info clients能夠監控輸出緩衝區的異常狀況。
4.客戶端的分類
(1)普通客戶端
(2)發佈訂閱客戶端
(3)slave客戶端
5.客戶端操做
命令 | 含義 |
---|---|
config set maxclients value | 設置最大鏈接數 |
config get maxclients | 設置最大鏈接數 |
info clients | 查看當前已經鏈接的客戶端數量 |
config set timeout value | 設置超時時間,空閒時間一旦大於超時時間,客戶端鏈接就會自動斷開。 |
client setName value | 設置客戶端的名稱 |
client getName | 得到客戶端的名稱 |
client kill ip:port | 關閉指定的ip:port的客戶端 |
client pause timeout | (時間單位毫秒) 阻塞客戶端timeout毫秒 |
五.持久化
1.RDB
(1)概念:將當前線程數據生成快照保存在磁盤中。
(2)方式
a.手動觸發
bgsave命令:Redis進程執行fork操做建立子進程,RDB的序列化由子進程完成,在fork階段會出現堵塞。
b.自動觸發
在某些狀況下自動觸發bgsave命令或是save命令。
(3)RDB的優缺點
a.優勢
緊湊壓縮的二進制文件,可以表明Redis在某個時間點的數據備份,可複製到不一樣的機器進行災難恢復。Redis加載RDB恢復數據的速度快於AOF。
b.缺點
沒法實現實時持久化,執行fork操做建立子進程是重量級操做,頻繁執行成本較高,且老版本的Redis服務沒法兼容新版本的RDB格式文件。
2.AOF
(1)概念:記錄每次的寫命令,重啓後執行AOF文件中的命令以達到恢復數據的目的。能夠用aof_enabled開啓aof功能。
(2)特色:
a.AOF命令以文本協議格式的形式寫入內容到aof_buf中,再由aof_buf同步到硬盤中。文本協議格式具備很好的兼容性以及避免了二次處理的開銷。而寫入到aof_buf中是爲了不直接寫入硬盤,以避免硬盤的容量決定了追加寫入的性能。
b.aof重寫將無效的命令如del去掉,將多個命令合併成一個命令,以達到壓縮文件體積,加快Redis加載aof文件的速度。
六.複製
1.從節點和主節點之間創建關係有如下的方式:
(1)在配置文件(redis.conf)中加入slaveof {masterofhost} {masterofport}
(2)啓動redis-server時執行:redis-server -slaveof {masterofhost} {masterofport}
2.主節點和從節點斷開和切換:
(1)斷開:slaveof no one
(2)切換:執行命令slaveof {masterofhost} {masterofport}
3.複製的特色
(1)只能將主節點的數據複製到從節點。
(2)slaveof是異步命令,從節點保存了主節點的信息後返回,而不須要等到徹底複製完畢才返回。
(3)能夠經過命令info replication查看複製信息。
(4)從節點斷開與主節點的複製關係後,會晉升爲主節點。
(5)從節點切換主節點以後,會刪除從節點當前的全部數據,對新節點數據進行復制。
4.Redis的複製關係
(1)一主一從:用於主節點宕機時,從節點提供故障轉移支持。
(2)一主多從:用於讀寫分離,主節點執行寫命令,從節點執行讀命令,當高併發寫時,將寫命令的數據複製到從節點就須要消耗比較多的網絡帶寬。
(3)樹狀主從:從節點不只能夠複製主節點的數據,還能夠做爲其餘從節點的主節點進行向下複製。能夠有效下降主節點的負載和傳輸給從節點的數據量。
5.全量複製和部分複製
全量複製:將主節點的數據一次性發生給從節點。通常用於初次複製場景。
部分複製:僅複製主節點的部分數據給從節點。通常用於處理主從複製中網絡閃斷等緣由形成的數據丟失場景。
從節點執行命令:psync {runId} {offse7dxzt}
runId是主節點的運行id,offset是從節點已複製的偏移量。主節點響應寫命令時,會把寫命令發送給從節點,還會將寫命令寫入複製積壓緩衝區。
七.Redis的阻塞
利用日誌對Redis的異常進行監控。
內部緣由:不合理使用API或數據結構(可能由此致使慢查詢等)、CPU飽和(Redis是單線程,只會使用單個CPU)、持久化阻塞(fork操做產生阻塞,AOF對硬盤的操做產生阻塞或HugePage寫操做阻塞)等。
外在緣由:CPU競爭、內存交換、網絡問題等。
八.Redis的內存
1.Redis進程內存消耗
能夠經過config set maxmemory value設置最大內存以達到伸縮內存的目的
2.Redis內存的回收
(1)刪除已過時的鍵對象。包括惰性刪除(查詢時判斷鍵對象是否過時,若是過時執行刪除操做並返回空)和定時刪除。
(2)內存達到maxmemory時執行內存溢出控制策略。內存溢出策略包括noeviction,volatile-lru,allkeys-lru,allkeys-random,volatile-random和volatile-ttl,能夠經過config set maxmemory-policy {policy}動態設置。
3.內存優化
(1)縮短鍵和值得長度,使用高效二進制序列化工具。
(2)使用對象共享池優化小整數對象。
(3)避免字符串的追加操做,由於字符串追加會致使內存的預分配,下降內存的分配次數。
(4)ziplist壓縮編碼的原則是追求時間和空間的平衡,hash,zset,list的內部編碼能夠是ziplist,能夠經過{type}-max-ziplist-value和{type}-max-ziplist-entries進行編碼的控制。
(5)intset是set的內部編碼,整數集合儘可能使用intset編碼,
(6)數據優先使用整數,比字符串類型更節省內存。
九.Redis Sentinel(哨兵)
1.Redis Sentinel是什麼?
一個分佈式架構,包括Sentinel節點,Redis數據節點和分佈在多個物理機的客戶端應用。完成主節點不可用時的故障轉移處理工做,提供了高可用的解決方案。
2.Sentinel節點發現故障轉移前的內容:
(1)每一個Sentinel節點會對全部的數據節點(包括主節點和從節點)和其餘的Sentinel節點進行監控。
(2)當半數以上的節點認爲主節點故障不可用,就會選擇其中一個Sentinel節點做爲領導者進行故障轉移處理。
3.故障轉移處理的步驟以下:
(1)對某一個從節點執行slaveof no one,晉升爲主節點。
(2)其餘的從節點複製新的主節點命令(slaveof new master)。
(3)舊的主節點恢復後也要複製新的主節點命令(slaveof new master)。
(4)通知應用方新的主節點。
4.爲何須要多個Rentinel節點?
由多個Rentinel節點對主節點不可達進行判斷,能夠防止誤判。若是有個別Rentinel節點失效,整個Rentinel集合依然可用。
5.Redis Sentinel的搭建
(1)創建配置文件,逐一開啓。(配置文件的寫法能夠去看《Redis開發與設計》第九章)
開啓主節點:redis-server redis-6379.conf
開啓從節點 redis-server redis-6380.conf
redis-server redis-6381.conf
開啓sentinel節點 redis-server redis-sentinel-26379.conf --sentinel
redis-server redis-sentinel-26380.conf --sentinel redis-server redis-sentinel-26381.conf --sentinel
查看主節點的從節點:redis-cli -h 127.0.0.1 -p 6379 info replication
查看從節點的主節點 redis-cli -h 127.0.0.1 -p 6380 info replication
查看sentinel節點監控的主節點 redis-cli -h 127.0.0.1 -p 26379 info sentinel
(2)sentinel配置文件的一些參數
參數 | 含義 |
---|---|
sentinel monitor <master-name> <ip> <port> <quorum> | sentinel節點要監控名字叫<master-name>,ip地址是<ip>,端口地址是<port>的主節點。<quorum>表示斷定主節點不可達須要的票數。 |
sentinel down-after-milliseconds <master-name> <times> | sentinel節點會向數據節點和其餘sentinel節點發送ping命令,若是節點在<times>毫秒時間內沒有回覆,則認爲節點不可達。 |
sentinel parallel-syncs <master-name> <nums> | 一次故障轉移後,每次向新節點發起復制操做的從節點個數。 |
sentinel failover-timeout <master-name> <times> | 故障轉移的超時時間。 |
sentinel authpass <master-name> <password> | 添加主節點的密碼。 |
sentinel notification-script <master-name> <script-path> | 在故障轉移期間,若是發生了一些警告級別的事件(如客觀下線,主觀下線等),就會觸發對應路徑的腳本,並向腳本發送相應的事件參數。 |
sentinel client-reconfig-script <master-name> <script-path> | 在故障轉移結束後,會觸發相應路徑下的腳本,並把故障轉移後的結果參數發送給腳本。 |
6.Redis Sentinel部署的特色
(1)將Sentinel節點部署在不一樣的物理機上,由於若是一旦物理機出現故障,那這臺物理機上的Sentinel節點都會受到影響。
(2) 部署三個以上且奇數個Sentinel節點,由於領導者選舉須要半數加上1個,部署奇數個節點能夠節省一個節點。
(3)若是Sentinel節點須要監控同一個業務的全部主節點集合,就使用同一套Sentinel節點監控,若是不是,就用不一樣的Sentinel節點集合監控不一樣的業務的主節點。使用同一套Sentinel節點監控能夠節約資源,可是一旦出現異常,就會對監控的數據節點形成影響。
7.Sentinel節點的操做(進入某個Sentinel節點客戶端輸入如下操做)
操做 | 含義 |
---|---|
sentinel master | 查看全部的監控的主節點的信息。 |
sentinel master <master-name> | 查看指定的監控的主節點的信息。 |
sentinel get-master-addr-by-name <master-name> | 根據主節點名稱查看主節點的IP地址和端口 |
sentinel slaves <master-name> | 查看主節點的從節點信息 |
sentinel sentinels <master-name> | 查看主節點的Sentinel節點信息(不包括當前節點) |
sentinel remove <master-name> | 取消當前節點對指定主節點的監控。 |
8.根據Sentinel節點鏈接主節點
遍歷Sentinel節點集合得到一個可用的Sentinel節點,再利用sentinel get-master-addr-by-name得到主節點的IP地址和端口號。
/** * 使用Sentinel節點鏈接主節點 * @author liuffei * @date 2018年7月21日 * @description */ public class SentinelTest { public static void main(String[] args) { org.slf4j.Logger logger = LoggerFactory.getLogger(SentinelTest.class); Set<String> sentinels = new HashSet<String>(); sentinels.add("127.0.0.1:26379"); sentinels.add("127.0.0.1:26380"); sentinels.add("127.0.0.1:26381"); JedisSentinelPool pool = new JedisSentinelPool("mymaster",sentinels); Jedis jedis = null; try { jedis = pool.getResource(); String result = jedis.get("hello"); System.out.println(result); }catch(Exception e) { logger.error(e.getMessage()); }finally { if(null != jedis) { jedis.close(); } } } }
9.Sentinel的內部原理
(1)Sentinel須要三個定時任務來保證對節點不可達的判斷:
(2)主觀下線和客觀下線
(3)領導者的選舉
只須要一個Sentinel節點就能完成故障轉移。當一個Sentinel節點完成客觀下線以後,會詢問其餘節點是否贊成本身成爲領導者,若是得到票數大於等於max{quorum,num(sentinels/2+1)},就會成爲領導者,
十.集羣
集羣和哨兵均可以保障高可用,不一樣的是哨兵是每臺Redis服務器存儲相同的數據,而集羣是將數據分區後,每一個節點操做一個分區的數據。
1.數據分區
分佈式數據庫須要把數據集劃分到多個節點上,經常使用的分區規則有:順序分區和哈希分區。Redis採用哈希分區,哈希分區有節點取餘分區,一致性哈希分區和虛擬槽分區等等。Redis Cluster採用虛擬槽分區。
虛擬槽分區:使用分散度良好的哈希函數把全部數據映射到一個固定範圍的整數集合中,整數定義爲槽。槽是集羣內數據管理和遷移的基本單位。採用大範圍槽的主要目的是爲了方便拆分和集羣拓展。Redis Cluster採用虛擬槽分區,全部的鍵根據哈希函數映射到0-16383整數槽內,計算公式:slot=CRC16(key)&16383。每一個節點負責維護一部分槽以及槽所映射的鍵值數據。
2.集羣的搭建
(1)準備節點
須要準備6臺及以上的Redis服務器才能保證完整的高可用。須要設置cluster-enabled yes。
(2)節點握手
概念:指一批運行在集羣模式下的節點經過Gossip協議通訊,達到感知對方的過程。由客戶端發起命令:cluster meet {ip} {port}
(3)分配槽
只有當節點分配了槽,才能響應和這些槽關聯的鍵命令。
客戶端執行cluster replicate {nodeId}可讓一個節點變成子節點。
3.Gossip協議
工做原理:節點彼此不斷通訊交換消息,一段時間後全部節點都會知道集羣完整的信息,這種方式相似留言傳播。
Gossip的消息包括如下:
(1)meet消息:向集羣中加入新的節點 cluster meet {ip} {port}
(2)ping消息:用於集羣內交換消息。
(3)pong消息: 響應消息。
(4)fail消息:用於在集羣內廣播下線消息。
4.集羣的伸縮和擴容
(1)擴容:準備新節點->加入集羣->分配槽和數據
(2)收縮:下線遷移槽->遺忘節點
十一.緩存
1.使用緩存的好處以及帶來的問題
(1)好處:Redis將數據存儲在內存中,能夠加快寫入和讀取的速度,同時還能在緩存層作一些複雜的操做和計算。減小了向後端的訪問,下降了對後端(存儲層)的負載。
(2)問題:緩存層和存儲層的數據存在一致性問題。增長了代碼維護和運維成本。
2.緩存的更新策略
(1)算法剔除:當緩存的使用量超過最大值時,利用一些算法策略,刪除一部分緩存鍵值對象。
(2)過時刪除:給緩存對象設置過時時間,這會致使存儲層和緩存層的數據存在不一致,可用於實時性不高的場景中。
(3)主動更新:真實數據更新後就立馬更新存儲層的數據。可用於實時性要求高的場景。
3.緩存所有數據和部分數據的對比:
(1)緩存所有數據可使用在比較多的場景下,可是對內存的壓力也比較大,代碼維護壓力小。
(2)緩存部分數據的適用場景比較少,對內存壓力小,可是一旦須要在緩存中新加字段,就須要修改代碼。
4.緩存穿透
指查詢了存儲層和緩存層都不存在的數據,存儲層和緩存層都不會命中。
問題:若是不把空值存儲在緩存層就會致使頻繁訪問存儲層,增長了數據庫的訪問壓力。若是把空值存儲在內存中,就會在緩存層維護一些值爲空的鍵。增大了內存的存儲壓力。
5.緩存「無底洞」
指添加新的節點機器沒有提升性能,反而致使性能降低。由於將數據分散存儲在更多的機器節點上了,批量操做須要從不一樣的節點上獲取。
6.緩存雪崩
指緩存層不能提供服務以後,會有大量的請求涌入存儲層,可能會致使存儲層宕機。
7.熱點Key失效熱點Key會有大量的請求,短期內不能恢復。