最近在看《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作為字首開頭
命令 | 含義 |
---|---|
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
使用場景:
- setnx和setex可用於分散式鎖
- incr等可以用於計數
-
統一管理使用者的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
使用場景:
- lpush+brpop=阻塞佇列(訊息佇列)。
- lpush+lpop=Stack(棧)
- lpush+rpop=Queue(佇列)
- lpush+ltrim=Capped Collection(有限集合)
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=Tagging(標籤)
- spop/srandmember=Random item(隨機數抽獎)
-
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需要三個定時任務來保證對節點不可達的判斷:
- 每隔10秒,每個Sentinel節點向資料節點(主節點和從節點)傳送info replication命令獲取最新的主從關係。
- 每隔2秒,每個Sentinel節點需要向某個頻道傳送自己對主節點是否可達的判斷和自身節點的資訊,以發現新的Sentinel節點和Sentinel節點之間可以交換主節點的狀態。
- 每隔1秒,每個Sentinel節點需要向其它節點(包括主節點,從節點,Sentinel節點)傳送ping命令來確認這些節點是否可達。
(2)主觀下線和客觀下線
- 主觀下線:Sentinel節點向某個節點發出ping命令後,該節點在down-after-milliseconds之後沒有進行回覆,Sentinel會對該節點做失敗判定,這個行為成為主觀下線。
- 客觀下線:如果主觀下線的是主節點,那Sentinel節點就會通過is-master-down-by-addr向其他Sentinel節點詢問主節點的狀態,當Sentinel認為主節點失敗的個數超過<quorum>的數量,就認為客觀下線,需要進行故障轉移。
(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會有大量的請求,短時間內不能恢復。