Redis基本介紹
Remote Dictionary Server 高性能key-value數(shù)據(jù)庫(kù),支持BSD協(xié)議
Redis基本使用
數(shù)據(jù)類(lèi)型
String
Redis使用SDS(Simple Dynamic String)動(dòng)態(tài)字符串保存痛单,可以根據(jù)不同的字符串長(zhǎng)度使用不同的結(jié)構(gòu)體
使用場(chǎng)景:
- 保存
Session
實(shí)現(xiàn)單點(diǎn)登錄 - 計(jì)數(shù)器,記錄網(wǎng)站的瀏覽量或者點(diǎn)贊數(shù)等信息肝集,然后按照一定的規(guī)則持久化到數(shù)據(jù)庫(kù)中
- 緩存數(shù)據(jù)导俘,常用的是把緩存對(duì)象轉(zhuǎn)為
Json
格式的字符串保存,讀取的時(shí)候再反序列化
List 有序列表
Redis底層是使用QuickList
保存夭委,相當(dāng)于Java
中的LinkedList
,每個(gè)節(jié)點(diǎn)都是ZipList
的雙向鏈表保存若河,所以從列表的兩端取數(shù)據(jù)效率很高能岩,查詢(xún)數(shù)據(jù)的時(shí)間復(fù)雜度為O(n)
使用場(chǎng)景:
- 粉絲列表
- 文章評(píng)論列表等,可以使用lrange命令萧福,進(jìn)行分頁(yè)查詢(xún)拉鹃,提高應(yīng)用分頁(yè)查詢(xún)的速度
- 消息隊(duì)列,使用LPush和BRPop命令可以實(shí)現(xiàn)簡(jiǎn)單的消息隊(duì)列功能
常用命令
命令 | 作用 |
---|---|
LPUSH | 從列表頭部插入一條數(shù)據(jù) |
BRPOP | 從列表尾部移除一條數(shù)據(jù)鲫忍,如果沒(méi)有數(shù)據(jù)膏燕,則會(huì)一直阻塞等待到超時(shí)或者有元素為止 |
BRPOPLPUSH | 從列表中彈出一個(gè)值,并且將他插入到另外一個(gè)列表的頭部悟民,如果列表中沒(méi)有元素坝辫,則會(huì)一直阻塞等待到超時(shí)或者有元素為止 |
RPOP | 從列表中取出指定下標(biāo)的元素 |
Set 集合
內(nèi)部使用value為空的Hashtable實(shí)現(xiàn),查詢(xún)的時(shí)間復(fù)雜度為O(1)
使用場(chǎng)景:
- 去重
SortedSet 有序集合
基于跳躍表實(shí)現(xiàn)射亏,具體查看此文章近忙,他給每一個(gè)元素設(shè)置一個(gè)score分?jǐn)?shù),然后根據(jù)分?jǐn)?shù)進(jìn)行排序智润。
使用場(chǎng)景:
- 各種排行榜
- 帶權(quán)重的隊(duì)列及舍,可以讓線(xiàn)程根據(jù)權(quán)重優(yōu)先執(zhí)行某些任務(wù)。
Hash
內(nèi)部使用ziplist
或者Hashtable
實(shí)現(xiàn)窟绷,相當(dāng)于Java
中的HashMap
击纬,使用數(shù)據(jù)+鏈表的方式解決Hash沖突的問(wèn)題
使用場(chǎng)景:
- 一般可以把
java
對(duì)象緩存到hash里面,然后通過(guò)key-value
的方式取值钾麸,但是實(shí)際開(kāi)發(fā)中的對(duì)象一般比較復(fù)雜,嵌套類(lèi)型炕桨,所以使用hash
較少
過(guò)期時(shí)間
Expire key seconds
給key
設(shè)置過(guò)期時(shí)間
刪除策略
- 消極方法
- 當(dāng)用戶(hù)get獲取值的時(shí)候饭尝,判斷當(dāng)前key是否過(guò)期,如果過(guò)期就刪除献宫,不返回給用戶(hù)
- 積極方法
- 周期性的從設(shè)置了過(guò)期時(shí)間的key中隨機(jī)的選擇20個(gè)進(jìn)行檢查
- 刪除已經(jīng)過(guò)期的鍵
- 如果有25%的key過(guò)期钥平,則重復(fù)一次該操作
pub/sub
publish channel message
發(fā)布一條消息到channel通道
subscribe channel[channel...]
訂閱一個(gè)或者多個(gè)通道的消息
發(fā)布消息后就刪除了,不能實(shí)現(xiàn)消息的持久化以及重發(fā)等功能,需要專(zhuān)門(mén)的消息隊(duì)列中間件來(lái)實(shí)現(xiàn)(Kafka
涉瘾、RocketMQ
知态、RabbitMQ
)
自增
使用incr
命令可以進(jìn)行原子遞增
getset
設(shè)置一個(gè)key的value并獲取設(shè)置前的值,
Redis內(nèi)存回收策略
- noeviction 不淘汰任何鍵值對(duì)立叛,如果進(jìn)行讀操作則正常工作负敏,進(jìn)行寫(xiě)操作返回錯(cuò)誤。Redis默認(rèn)策略
- allkeys-lru 淘汰最近最少使用的鍵值對(duì)
- allkeys-random 對(duì)所有的鍵采用隨機(jī)刪除策略
- volatile-lru 在設(shè)置了過(guò)期時(shí)間的鍵中采用最近最少使用策略刪除鍵
- volatile-random 在設(shè)置了過(guò)期時(shí)間的鍵中采用隨機(jī)刪除的策略刪除鍵值對(duì)
- volatile-ttl 在設(shè)置了過(guò)期時(shí)間的鍵中秘蛇,具有更早過(guò)期時(shí)間的key優(yōu)先移除
JoinGroup過(guò)程
RDB方式:當(dāng)一定的條件觸發(fā)后其做,Redis會(huì)fork一個(gè)子進(jìn)程來(lái)進(jìn)行持久化操作,會(huì)把內(nèi)存中的數(shù)據(jù)集以快照形式寫(xiě)入磁盤(pán)赁还,采用二進(jìn)制壓縮存儲(chǔ)妖泄,將所有的數(shù)據(jù)寫(xiě)入到一個(gè)臨時(shí)文件中,等寫(xiě)入完成后會(huì)替換上次持久化的文件艘策。
觸發(fā)條件
- 用戶(hù)配置(默認(rèn)下面save seconds 操作次數(shù))
- save 900 1
- save 300 10
- save 60 10000
-
bgsave
蹈胡、save
調(diào)用save
方法或者bgsave
方法 -
flushall
清空數(shù)據(jù) -
replication
主從同步數(shù)據(jù)
AOF: 每隔一秒或者每次更改redis
數(shù)據(jù)就將命令追加到AOF文件中
- 默認(rèn)不開(kāi)啟,使用配置中
appendonly yes
打開(kāi)AOF
-
AOF
文件體積過(guò)大時(shí)朋蔫,會(huì)自動(dòng)的在后臺(tái)對(duì)AOF
進(jìn)行重寫(xiě)罚渐,重寫(xiě)后新的AOF
文件包含了恢復(fù)當(dāng)前數(shù)據(jù)集所需要的最小命令集;主進(jìn)程會(huì)fork
一個(gè)子進(jìn)程進(jìn)行重寫(xiě)斑举,類(lèi)似于RDB
快照的方式搅轿。 -
auto-aof-rewrite-percentage
表示表示當(dāng)前的AOF
文件大小 超過(guò)上一次重寫(xiě)時(shí)的AOF
文件大小的百分之多少時(shí)會(huì)再次進(jìn)行重寫(xiě),如果之前沒(méi)有重寫(xiě)過(guò)富玷,則以啟動(dòng)時(shí)AOF
文件大小為依據(jù)璧坟。 -
Auto-aof-rewrite-min-size
表示限制了允許重寫(xiě)的最小AOF
文件大小
RDB和AOF的優(yōu)缺點(diǎn):
- 當(dāng)服務(wù)發(fā)生故障,
RDB
方式會(huì)丟失上次備份之后的所有數(shù)據(jù)赎懦,AOF
最多丟失1秒內(nèi)的數(shù)據(jù) -
Redis
重啟時(shí)雀鹃,首先通過(guò)RDB
加載數(shù)據(jù)到內(nèi)存中,速度比較快励两,然后通過(guò)AOF
文件中的近期操作指令黎茎,將數(shù)據(jù)恢復(fù)到重啟之前的狀態(tài) -
AOF
文件可讀性比較好,但是相同內(nèi)容的數(shù)據(jù)当悔,會(huì)比RDB
大很多
Redis 單線(xiàn)程
Redis為什么這么塊
- Redis是在內(nèi)存中操作數(shù)據(jù)傅瞻,而且存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)類(lèi)似于
Java
中的HashMap
,查詢(xún)的時(shí)間復(fù)雜度為O(1)
盲憎; - 單線(xiàn)程嗅骄,不需要在線(xiàn)程間切換,減少了上下文切換的資源消耗饼疙,單線(xiàn)程也不需要考慮鎖的使用溺森,減少了獲取鎖和釋放鎖的資源消耗
- 使用I/O多路復(fù)用,同步非阻塞IO
Lua腳本
Redis
是單線(xiàn)程的,在內(nèi)部不會(huì)存在線(xiàn)程安全的問(wèn)題屏积,但是如果有多個(gè)客戶(hù)端同時(shí)訪(fǎng)問(wèn)医窿,就相當(dāng)于多線(xiàn)程,多個(gè)客戶(hù)端之間沒(méi)有請(qǐng)求的同步炊林,實(shí)際順序不一樣就可能產(chǎn)生線(xiàn)程安全問(wèn)題姥卢。使用Lua
腳本可以滿(mǎn)足原子性。
基本使用
eval "redis.call(’set’,’hello’,’world')" 0
不帶參數(shù)
eval “redis.call(’set’,KEYS[1],ARGV[1])” 1 hello world
帶參數(shù)
Lua腳本的好處
- 減少網(wǎng)絡(luò)開(kāi)銷(xiāo)铛铁,在Lua腳本中可以把多個(gè)命令放在同一個(gè)腳本中運(yùn)行
- 原子操作隔显,Redis會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行,中間不會(huì)被其他命令插入
- 復(fù)用性饵逐,客戶(hù)端發(fā)送的腳本會(huì)存儲(chǔ)在Redis中括眠,其他客戶(hù)端可以復(fù)用這一腳本完成同樣的邏輯。
Pinelining 管道
Redis
是一種基于客戶(hù)端-服務(wù)端模型以及請(qǐng)求/響應(yīng)協(xié)議的TCP
服務(wù)倍权,通常會(huì)遵循以下步驟
- 客戶(hù)端發(fā)送一個(gè)查詢(xún)請(qǐng)求掷豺,并監(jiān)聽(tīng)
socket
返回,通常是阻塞模式薄声,等待服務(wù)端響應(yīng) - 服務(wù)端處理命令当船,然后將結(jié)果返回給客戶(hù)端
如果客戶(hù)端需要發(fā)送批量的命令的時(shí)候,往返時(shí)間就會(huì)變的很長(zhǎng)(RTT Round Trip Time
)默辨,使用pipeline
可以減少RTT
的時(shí)間德频,服務(wù)端也可以見(jiàn)減少I(mǎi)/O的調(diào)用次數(shù)(用戶(hù)態(tài)->內(nèi)核態(tài))
分布式鎖的實(shí)現(xiàn)
setnx
命令可以設(shè)置一個(gè)key-value
鍵值對(duì),如果當(dāng)前Redis
中已經(jīng)有該key
缩幸,會(huì)返回失敗壹置。多個(gè)進(jìn)程同時(shí)進(jìn)行setnx
操作的時(shí)候,只會(huì)有一個(gè)可以設(shè)置成功表谊。
-
setnx
需要設(shè)置一個(gè)超時(shí)時(shí)間钞护,防止獲取鎖的進(jìn)程掛掉后導(dǎo)致死鎖 - 存在一種情況,當(dāng)一個(gè)客戶(hù)端A獲取鎖成功后爆办,由于某種原因阻塞了难咕,然后超時(shí)時(shí)間到了,自動(dòng)釋放鎖了距辆,然后另一個(gè)客戶(hù)端B獲取了鎖余佃,此時(shí)客戶(hù)端A阻塞結(jié)束并且運(yùn)行結(jié)束后,會(huì)嘗試釋放鎖跨算,這時(shí)候可能會(huì)把客戶(hù)端A的鎖釋放了咙冗。解決辦法:
setnx key randomValue
設(shè)置一個(gè)隨機(jī)值,每個(gè)客戶(hù)端不同漂彤,釋放鎖的時(shí)候,首先判斷一下當(dāng)前value
是否與自己客戶(hù)端相同,如果相同才能釋放鎖挫望。
Redis集群
1.如何配置
master
節(jié)點(diǎn)不用做任何修改立润,只需要在slave
節(jié)點(diǎn)中,修改redis.conf
文件中添加slaveof master-ip master-port
2.數(shù)據(jù)如何同步
-
slave
初始化階段媳板,Redis
會(huì)觸發(fā)全量復(fù)制桑腮,slave
需要將master
節(jié)點(diǎn)上的所有數(shù)據(jù) - Master服務(wù)器執(zhí)行
bgsave
命令(子線(xiàn)程),生成快照蛉幸,同時(shí)記錄在此期間的寫(xiě)命令破讨,快照發(fā)送到Slave
節(jié)點(diǎn)并載入后,再把緩存的寫(xiě)命令發(fā)送過(guò)來(lái)執(zhí)行命令 -
min-slaves-to-write 3
表示只有當(dāng)3個(gè)slave同步完成奕纫,master才是可寫(xiě)的 -
min-slaves-max-lag 10
表示允許slave最長(zhǎng)失去連接的時(shí)間是10秒提陶,10秒還沒(méi)收到slave
響應(yīng),master
就認(rèn)為slave
已經(jīng)斷開(kāi) -
master node
會(huì)在內(nèi)存中創(chuàng)建一個(gè)backlog
匹层,master
和slave
都會(huì)保存要給replica offset
還有一個(gè)master id
隙笆,如果slave
斷開(kāi)連接,重連后slave會(huì)讓master從上次的replica offset
開(kāi)始繼續(xù)復(fù)制數(shù)據(jù)升筏,如果沒(méi)有對(duì)應(yīng)的offset
撑柔,則會(huì)進(jìn)行一次全量同步
Redis哨兵(Sentinel)
Redis
集群之后,如果master
節(jié)點(diǎn)掛了您访,需要從slave
節(jié)點(diǎn)中選舉master
铅忿,Redis
沒(méi)有提供相關(guān)的功能,需要哨兵來(lái)進(jìn)行監(jiān)控灵汪。
哨兵是一個(gè)單獨(dú)的進(jìn)程檀训,一般使用三個(gè)哨兵集群,保證哨兵的高可用识虚。此時(shí)哨兵不僅會(huì)監(jiān)控master
和slave
肢扯,還會(huì)互相監(jiān)控。
配置:在redis-sentinel.conf文件中配置 sentinel monitor name ip port quorum担锤,只需要配置master節(jié)點(diǎn)即可
哨兵之間相互感知
- 所有的
sentinel
向他們的監(jiān)視的master
節(jié)點(diǎn)訂閱channel
sentinel
- 新加入的
sentinel
節(jié)點(diǎn)向master
的這個(gè)節(jié)點(diǎn)發(fā)布一條消息蔚晨,其他訂閱了這個(gè)channel
的sentinel
會(huì)發(fā)現(xiàn)這個(gè)新的sentinel
- 新加入的
sentinel
和其他sentinel
節(jié)點(diǎn)建立長(zhǎng)連接
故障發(fā)現(xiàn)
sentinel
節(jié)點(diǎn)定期向master
節(jié)點(diǎn)發(fā)送心跳包判斷是否存活,一旦發(fā)現(xiàn)master
沒(méi)有正確響應(yīng)肛循,sentinel
就會(huì)把master
設(shè)為主觀(guān)不可用狀態(tài)铭腕,然后把狀態(tài)發(fā)送給其他sentinel
確認(rèn),當(dāng)確認(rèn)的sentinel
超過(guò)quorum
時(shí)多糠,就認(rèn)為master
節(jié)點(diǎn)客觀(guān)不可用累舷,接著就進(jìn)入選舉新的master
的流程,這里使用到了Raft
算法夹孔,基于投票的算法被盈,只要保證過(guò)半數(shù)節(jié)點(diǎn)通過(guò)提議即可析孽。
哨兵的主要功能
- 集群監(jiān)控 哨兵可以監(jiān)控master節(jié)點(diǎn)和slave節(jié)點(diǎn)的運(yùn)行情況
- 消息通知 當(dāng)集群中有某一個(gè)節(jié)點(diǎn)掛了之后,可以通知管理員
- 故障轉(zhuǎn)移 當(dāng)master節(jié)點(diǎn)掛了之后只怎,哨兵會(huì)從slave節(jié)點(diǎn)中重新選舉一個(gè)做為master節(jié)點(diǎn)
- 配置中心 如果發(fā)生故障轉(zhuǎn)移袜瞬,通知客戶(hù)端新的master節(jié)點(diǎn)地址
Redis分片(Cluster)
主從同步的集群中,每個(gè)節(jié)點(diǎn)都存有集群中的所有數(shù)據(jù)身堡,存在著單機(jī)存儲(chǔ)量的瓶頸問(wèn)題邓尤,形成了木桶效應(yīng)。對(duì)Redis進(jìn)行分片集群贴谎,可以提高Redis的性能和存儲(chǔ)能力汞扎。
集群結(jié)構(gòu)如上圖,一個(gè)Redis Cluster由多個(gè)Redis節(jié)點(diǎn)構(gòu)成擅这,不同節(jié)點(diǎn)組服務(wù)沒(méi)有交集澈魄,也就是每一個(gè)節(jié)點(diǎn)組對(duì)應(yīng)數(shù)據(jù)sharding的一個(gè)分片。節(jié)點(diǎn)組內(nèi)部分為主備兩類(lèi)節(jié)點(diǎn)蕾哟,對(duì)應(yīng)master和slave節(jié)點(diǎn)一忱。兩者數(shù)據(jù)準(zhǔn)實(shí)時(shí)一直,通過(guò)異步化的主備復(fù)制機(jī)制來(lái)保證谭确。一個(gè)節(jié)點(diǎn)組有且只有一個(gè)master節(jié)點(diǎn)帘营,同時(shí)可以有0到n個(gè)slave節(jié)點(diǎn),在這個(gè)節(jié)點(diǎn)組中逐哈,只有master節(jié)點(diǎn)可以提供讀寫(xiě)服務(wù)芬迄,slave只能提供讀服務(wù)。
集群的數(shù)據(jù)分片
Redis 集群沒(méi)有使用一致性hash, 而是引入了 哈希槽的概念.
Redis 集群有16384個(gè)哈希槽,每個(gè)key通過(guò)CRC16校驗(yàn)后對(duì)16384取模來(lái)決定放置哪個(gè)槽.集群的每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分hash槽,舉個(gè)例子,比如當(dāng)前集群有3個(gè)節(jié)點(diǎn),那么:
- 節(jié)點(diǎn) A 包含 0 到 5500號(hào)哈希槽.
- 節(jié)點(diǎn) B 包含5501 到 11000 號(hào)哈希槽.
- 節(jié)點(diǎn) C 包含11001 到 16384號(hào)哈希槽.
這種結(jié)構(gòu)很容易添加或者刪除節(jié)點(diǎn). 比如如果我想新添加個(gè)節(jié)點(diǎn)D, 我需要從節(jié)點(diǎn) A, B, C中得部分槽到D上. 如果我想移除節(jié)點(diǎn)A,需要將A中的槽移到B和C節(jié)點(diǎn)上,然后將沒(méi)有任何槽的A節(jié)點(diǎn)從集群中移除即可. 由于從一個(gè)節(jié)點(diǎn)將哈希槽移動(dòng)到另一個(gè)節(jié)點(diǎn)并不會(huì)停止服務(wù),所以無(wú)論添加刪除或者改變某個(gè)節(jié)點(diǎn)的哈希槽的數(shù)量都不會(huì)造成集群不可用的狀態(tài).
如何把一次操作的所有值保存到一個(gè)節(jié)點(diǎn)中
Redis中引入了HashTag的概念昂秃,可以是得數(shù)據(jù)分布算法可以根據(jù)key的某一個(gè)部分進(jìn)行計(jì)算禀梳,
舉個(gè)簡(jiǎn)單的例子,加入對(duì)于用戶(hù)的信息進(jìn)行存儲(chǔ)肠骆, user:user1:id算途、user:user1:name/ 那么通過(guò)hashtag的方式, user:{user1}:id蚀腿、user:{user1}.name; 表示
當(dāng)一個(gè)key包含 {} 的時(shí)候嘴瓤,就不對(duì)整個(gè)key做hash,而僅對(duì) {} 包括的字符串做hash莉钙。
擴(kuò)容
- 槽位遷移
- 數(shù)據(jù)遷移
Redis緩存問(wèn)題(緩存擊穿廓脆、緩存穿透、緩存雪崩磁玉、緩存不一致)
緩存擊穿
當(dāng)Redis緩存中的某個(gè)熱點(diǎn)key失效停忿,導(dǎo)致大量的請(qǐng)求穿過(guò)緩存,到達(dá)DB
緩存穿透
大量的無(wú)效請(qǐng)求到達(dá)數(shù)據(jù)庫(kù)蚊伞,比如請(qǐng)求參數(shù)id = -1席赂,redis和數(shù)據(jù)庫(kù)中都沒(méi)有數(shù)據(jù)吮铭,但是會(huì)一直查詢(xún)數(shù)據(jù)庫(kù)。
解決辦法
- 熱點(diǎn)數(shù)據(jù)設(shè)置永不失效
- 多級(jí)緩存
- 熔斷降級(jí)
- nginx拉黑多次請(qǐng)求的同一ip
- 參數(shù)校驗(yàn)氧枣,永遠(yuǎn)不要相信用戶(hù)
- 當(dāng)查詢(xún)到數(shù)據(jù)庫(kù)中沒(méi)有的值沐兵,可以設(shè)置一個(gè)為null或其他提示的數(shù)據(jù)到緩存中,下次請(qǐng)求就不會(huì)到數(shù)據(jù)庫(kù)中了便监,緩存的失效時(shí)間設(shè)置短一點(diǎn)如30秒
- 使用互斥鎖
- 布隆過(guò)濾器
緩存雪崩
同一時(shí)間Redis緩存的key大面積失效,導(dǎo)致所有的請(qǐng)求都到達(dá)了數(shù)據(jù)庫(kù)
- 一般這種情況是redis的過(guò)期時(shí)間到了碳想,可以設(shè)置一個(gè)隨機(jī)值烧董,讓key在一定范圍內(nèi)失效
- Redis分片,將key保存到不同的節(jié)點(diǎn)上胧奔,防止出現(xiàn)大面積失效的情況
緩存更新方式
這是決定在使用緩存時(shí)就該考慮的問(wèn)題逊移。
緩存的數(shù)據(jù)在數(shù)據(jù)源發(fā)生變更時(shí)需要對(duì)緩存進(jìn)行更新,數(shù)據(jù)源可能是 DB龙填,也可能是遠(yuǎn)程服務(wù)胳泉。更新的方式可以是主動(dòng)更新。數(shù)據(jù)源是 DB 時(shí)岩遗,可以在更新完 DB 后就直接更新緩存扇商。
當(dāng)數(shù)據(jù)源不是 DB 而是其他遠(yuǎn)程服務(wù),可能無(wú)法及時(shí)主動(dòng)感知數(shù)據(jù)變更宿礁,這種情況下一般會(huì)選擇對(duì)緩存數(shù)據(jù)設(shè)置失效期案铺,也就是數(shù)據(jù)不一致的最大容忍時(shí)間。
這種場(chǎng)景下梆靖,可以選擇失效更新控汉,key 不存在或失效時(shí)先請(qǐng)求數(shù)據(jù)源獲取最新數(shù)據(jù),然后再次緩存返吻,并更新失效期姑子。
但這樣做有個(gè)問(wèn)題,如果依賴(lài)的遠(yuǎn)程服務(wù)在更新時(shí)出現(xiàn)異常测僵,則會(huì)導(dǎo)致數(shù)據(jù)不可用街佑。改進(jìn)的辦法是異步更新,就是當(dāng)失效時(shí)先不清除數(shù)據(jù)恨课,繼續(xù)使用舊的數(shù)據(jù)舆乔,然后由異步線(xiàn)程去執(zhí)行更新任務(wù)。這樣就避免了失效瞬間的空窗期剂公。另外還有一種純異步更新方式希俩,定時(shí)對(duì)數(shù)據(jù)進(jìn)行分批更新。實(shí)際使用時(shí)可以根據(jù)業(yè)務(wù)場(chǎng)景選擇更新方式纲辽。
數(shù)據(jù)不一致
第二個(gè)問(wèn)題是數(shù)據(jù)不一致的問(wèn)題颜武,可以說(shuō)只要使用緩存璃搜,就要考慮如何面對(duì)這個(gè)問(wèn)題。緩存不一致產(chǎn)生的原因一般是主動(dòng)更新失敗鳞上,例如更新 DB 后这吻,更新 Redis 因?yàn)榫W(wǎng)絡(luò)原因請(qǐng)求超時(shí);或者是異步更新失敗導(dǎo)致篙议。
解決的辦法是唾糯,如果服務(wù)對(duì)耗時(shí)不是特別敏感可以增加重試;如果服務(wù)對(duì)耗時(shí)敏感可以通過(guò)異步補(bǔ)償任務(wù)來(lái)處理失敗的更新鬼贱,或者短期的數(shù)據(jù)不一致不會(huì)影響業(yè)務(wù)移怯,那么只要下次更新時(shí)可以成功,能保證最終一致性就可以这难。