1.Redis應(yīng)用場(chǎng)景
解決CPU及內(nèi)存壓力

解決IO壓力

案例1:配合關(guān)系型數(shù)據(jù)庫(kù)做高速緩存:
高頻次,熱門訪問的數(shù)據(jù),降低數(shù)據(jù)庫(kù)IO
分布式架構(gòu),做session共享

案例2:多樣的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)持久化數(shù)據(jù)

2.幾種特殊的數(shù)據(jù)結(jié)構(gòu)
2.1 跳躍表
有序鏈表和跳躍表查找效率對(duì)比:

2.2 Bitmaps
現(xiàn)代計(jì)算機(jī)用二進(jìn)制(位) 作為信息的基礎(chǔ)單位, 1個(gè)字節(jié)等于8位, 例如“abc”字符串是由3個(gè)字節(jié)組成, 但實(shí)際在計(jì)算機(jī)存儲(chǔ)時(shí)將其用二進(jìn)制表示, “abc”分別對(duì)應(yīng)的ASCII碼分別是97、 98、 99, 對(duì)應(yīng)的二進(jìn)制分別是01100001、 01100010和01100011,如下圖

合理地使用操作位能夠有效地提高內(nèi)存使用率和開發(fā)效率。Redis提供了Bitmaps這個(gè)“數(shù)據(jù)類型”可以實(shí)現(xiàn)對(duì)位的操作:
(1)Bitmaps本身不是一種數(shù)據(jù)類型, 實(shí)際上它就是字符串(key-value) , 但是它可以對(duì)字符串的位進(jìn)行操作。
(2)Bitmaps單獨(dú)提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一個(gè)以位為單位的數(shù)組, 數(shù)組的每個(gè)單元只能存儲(chǔ)0和1, 數(shù)組的下標(biāo)在Bitmaps中叫做偏移量。

案例1:(setbit<key><offset><value>設(shè)置Bitmaps中某個(gè)偏移量的值(0或1))每個(gè)獨(dú)立用戶是否訪問過網(wǎng)站存放在Bitmaps中, 將訪問的用戶記做1, 沒有訪問的用戶記做0, 用偏移量作為用戶的id。設(shè)置鍵的第offset個(gè)位的值(從0算起),假設(shè)現(xiàn)在有20個(gè)用戶,userid=1,6,11,15,19的用戶對(duì)網(wǎng)站進(jìn)行了訪問,那么當(dāng)前Bitmaps初始化結(jié)果如圖:

備注:很多應(yīng)用的用戶id以一個(gè)指定數(shù)字(例如10000)開頭,直接將用戶id和Bitmaps的偏移量對(duì)應(yīng)勢(shì)必會(huì)造成一定的浪費(fèi),通常做法是每次做setbit操作時(shí)將用戶id減去這個(gè)指定數(shù)字。假如第一次初始化Bitmaps時(shí),假如偏移量非常大,那么整個(gè)初始化過程執(zhí)行會(huì)比較慢,可能會(huì)造成Redis的阻塞。
案例2:getbit<key><offset>獲取Bitmaps中某個(gè)偏移量的值
獲取id=8的用戶是否在2020-11-06這天訪問過,返回0說明沒有訪問過。

案例3:bitcount<key>[start end] 統(tǒng)計(jì)字符串從start字節(jié)到end字節(jié)比特值為1的數(shù)量
計(jì)算2022-11-06這天的獨(dú)立訪問用戶數(shù)量,

start和end代表起始和結(jié)束字節(jié)數(shù),下面操作計(jì)算用戶id在第一個(gè)字節(jié)到第三個(gè)字節(jié)之間的獨(dú)立訪問用戶數(shù),對(duì)應(yīng)的用戶id是11,15,19.

案例4:bitop and(or/not/xor) <destkey> [key…]bitop是一個(gè)復(fù)合操作, 它可以做多個(gè)Bitmaps的and(交集) 、 or(并集) 、 not(非) 、 xor(異或) 操作并將結(jié)果保存在destkey中。


案例5:Bitmaps和set對(duì)比


2.3 HyperLogLog
涉及統(tǒng)計(jì)相關(guān)的需求,比如統(tǒng)計(jì)網(wǎng)站PageView頁(yè)面訪問量,可以使用Redis的incr等實(shí)現(xiàn)。但如果UV獨(dú)立訪客、獨(dú)立IP數(shù)、搜索記錄數(shù)等需要去重和計(jì)數(shù)的問題如何解決。這種求集合中不重復(fù)元素個(gè)數(shù)的問題稱為基數(shù)問題。
HyperLogLog是用來做基數(shù)統(tǒng)計(jì)的算法,HyperLogLog的優(yōu)點(diǎn)是,在輸入元素的數(shù)量或者體積非常非常大時(shí),計(jì)算基數(shù)所需的空間總是固定的、并且很小的。

案例1:pfadd <key>< element>[element ...] 添加指定元素到 HyperLogLog 中

案例2:pfcount<key> [key ...] 計(jì)算HLL的近似基數(shù),可以計(jì)算多個(gè)HLL,比如用HLL存儲(chǔ)每天的UV,計(jì)算一周的UV可以使用7天的UV合并計(jì)算即可

案例3:pfmerge<destkey><sourcekey>[sourcekey ...] 將一個(gè)或多個(gè)HLL合并后的結(jié)果存儲(chǔ)在另一個(gè)HLL中,比如每月活躍用戶可以使用每天的活躍用戶來合并計(jì)算可得

3.發(fā)布與訂閱
Redis是一種發(fā)布訂閱消息通信模式:發(fā)送者發(fā)送消息,訂閱者接收消息。

4.事務(wù)、鎖機(jī)制
4.1事務(wù)定義
Redis事務(wù)是一個(gè)單獨(dú)的隔離操作:事務(wù)中的所有命令都會(huì)序列化、按順序地執(zhí)行。事務(wù)在執(zhí)行的過程中,不會(huì)被其他客戶端發(fā)送來的命令請(qǐng)求打斷。Redis事務(wù)的主要作用就是串聯(lián)多個(gè)命令防止別的命令插隊(duì)。
4.2 Muli、Exec、Discard

4.3 事物的錯(cuò)誤處理
如果是組隊(duì)階段出現(xiàn)了報(bào)告錯(cuò)誤,執(zhí)行時(shí)整個(gè)的所有隊(duì)列都會(huì)被取消。

如果執(zhí)行階段某個(gè)命令報(bào)了錯(cuò)誤,則只有報(bào)錯(cuò)的命令不會(huì)被執(zhí)行,而其他的命令都會(huì)執(zhí)行,不會(huì)回滾。

4.4 為什么需要事務(wù)?
案例:很多人有你的賬號(hào),同時(shí)去參加雙十一的搶購(gòu)。

悲觀鎖:每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到拿到鎖。傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖、表鎖等,讀鎖、寫鎖等,都是在做操作之前先上鎖。

樂觀鎖:就是很樂觀,每去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量。Redis就是利用這種check-and-set機(jī)制實(shí)現(xiàn)事務(wù)的。

Watch在執(zhí)行multi之前,先執(zhí)行watch key1 [key2],可以監(jiān)視一個(gè)(或多個(gè)) key ,如果在事務(wù)執(zhí)行之前這個(gè)(或這些) key 被其他命令所改動(dòng),那么事務(wù)將被打斷。

Redis事務(wù)的三特性:
單獨(dú)的隔離操作:事務(wù)中的所有命令都會(huì)被序列化、按順序執(zhí)行。事務(wù)在執(zhí)行的過程中,不會(huì)被其他客戶端發(fā)送來的命令請(qǐng)求打端。
沒有隔離級(jí)別的概念:隊(duì)列中的命令沒有提交之前都不會(huì)實(shí)際被執(zhí)行,因?yàn)槭聞?wù)提交前任何指令都不會(huì)被實(shí)際執(zhí)行。
不保證原子性:事務(wù)中如果有一條命令執(zhí)行失敗,其后的命令仍然會(huì)被執(zhí)行,沒有回滾 。
5.秒殺
5.1 超賣問題


解決方法1:樂觀鎖(出現(xiàn)庫(kù)存遺留問題和連接超時(shí)問題)

5.2 超賣問題
通過連接池
5.3 庫(kù)存遺留問題

6.持久化(RDB、AOF)
6.1 RDB
在指定的時(shí)間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤,也就是行話講的Snapshot快照,它恢復(fù)時(shí)是將快照文件直接讀到內(nèi)存里。
Redis會(huì)單獨(dú)創(chuàng)建(fork)一個(gè)子進(jìn)程來進(jìn)行持久化,會(huì)先將數(shù)據(jù)寫入到 一個(gè)臨時(shí)文件中,待持久化過程都結(jié)束了,再用這個(gè)臨時(shí)文件替換上次持久化好的文件。 整個(gè)過程中,主進(jìn)程是不進(jìn)行任何IO操作的,這就確保了極高的性能 如果需要進(jìn)行大規(guī)模數(shù)據(jù)的恢復(fù),且對(duì)于數(shù)據(jù)恢復(fù)的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點(diǎn)是最后一次持久化后的數(shù)據(jù)可能丟失。
Fork的作用是復(fù)制一個(gè)與當(dāng)前進(jìn)程一樣的進(jìn)程。新進(jìn)程的所有數(shù)據(jù)(變量、環(huán)境變量、程序計(jì)數(shù)器等) 數(shù)值都和原進(jìn)程一致,但是是一個(gè)全新的進(jìn)程,并作為原進(jìn)程的子進(jìn)程
在Linux程序中,fork()會(huì)產(chǎn)生一個(gè)和父進(jìn)程完全相同的子進(jìn)程,但子進(jìn)程在此后多會(huì)exec系統(tǒng)調(diào)用,出于效率考慮,Linux中引入了“寫時(shí)復(fù)制技術(shù)”
一般情況父進(jìn)程和子進(jìn)程會(huì)共用同一段物理內(nèi)存,只有進(jìn)程空間的各段的內(nèi)容要發(fā)生變化時(shí),才會(huì)將父進(jìn)程的內(nèi)容復(fù)制一份給子進(jìn)程。

save :save時(shí)只管保存,其它不管,全部阻塞。手動(dòng)保存。不建議。 bgsave:Redis會(huì)在后臺(tái)異步進(jìn)行快照操作, 快照同時(shí)還可以響應(yīng)客戶端請(qǐng)求。 可以通過lastsave 命令獲取最后一次成功執(zhí)行快照的時(shí)間
格式:save 秒鐘 寫操作次數(shù) RDB是整個(gè)內(nèi)存的壓縮過的Snapshot,RDB的數(shù)據(jù)結(jié)構(gòu),可以配置復(fù)合的快照觸發(fā)條件, 默認(rèn)是1分鐘內(nèi)改了1萬(wàn)次,或5分鐘內(nèi)改了10次,或15分鐘內(nèi)改了1次。 禁用 不設(shè)置save指令,或者給save傳入空字符串


6.2 AOF
以日志的形式來記錄每個(gè)寫操作(增量保存),將Redis執(zhí)行過程的所有寫指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis啟動(dòng)之初會(huì)讀取該文件重新構(gòu)建數(shù)據(jù),換言之,redis重啟的話就根據(jù)日志文件的內(nèi)容將寫指令從前到后執(zhí)行一次以完成數(shù)據(jù)的恢復(fù)工作。
持久化流程:
客戶端的請(qǐng)求寫命令會(huì)被append追加到AOF緩沖區(qū)
AOF緩沖區(qū)根據(jù)AOF持久化策略[always,everysec,no]將操作sync同步到磁盤的AOF文件中;
AOF文件大小超過重寫策略或手動(dòng)重寫時(shí),會(huì)對(duì)AOF文件rewrite重寫,壓縮AOF文件容量;
Redis服務(wù)重啟時(shí),會(huì)重新load加載AOF文件中的寫操作達(dá)到數(shù)據(jù)恢復(fù)的目的;

默認(rèn)不開啟,同時(shí)開啟默認(rèn)AOF,

Rewrite壓縮:


重寫流程:


優(yōu)勢(shì):

劣勢(shì):


官方推薦兩個(gè)都啟用。
如果對(duì)數(shù)據(jù)不敏感,可以選單獨(dú)用RDB。
不建議單獨(dú)用 AOF,因?yàn)榭赡軙?huì)出現(xiàn)Bug。
如果只是做純內(nèi)存緩存,可以都不用
因?yàn)镽DB文件只用作后備用途,建議只在Slave上持久化RDB文件,而且只要15分鐘備份一次就夠了,只保留save 900 1這條規(guī)則。
如果使用AOF,好處是在最惡劣情況下也只會(huì)丟失不超過兩秒數(shù)據(jù),啟動(dòng)腳本較簡(jiǎn)單只load自己的AOF文件就可以了。
代價(jià),一是帶來了持續(xù)的IO,二是AOF rewrite的最后將rewrite過程中產(chǎn)生的新數(shù)據(jù)寫到新文件造成的阻塞幾乎是不可避免的。
只要硬盤許可,應(yīng)該盡量減少AOF rewrite的頻率,AOF重寫的基礎(chǔ)大小默認(rèn)值64M太小了,可以設(shè)到5G以上。
默認(rèn)超過原大小
100%
大小時(shí)重寫可以改到適當(dāng)?shù)臄?shù)值。
7.主從復(fù)制
定義:主機(jī)數(shù)據(jù)更新后根據(jù)配置和策略,自動(dòng)同步到備機(jī)的master/slaver機(jī)制,master以寫為主,slave以讀為主。
作用:讀寫分離,性能擴(kuò)展;容災(zāi)快速恢復(fù)。

7.1搭建
復(fù)制redis6379,6380,6381多個(gè)redi是配置文件,模擬三臺(tái)redis服務(wù)器
配置一臺(tái)服務(wù)器為主另外兩臺(tái)為從。
一主二仆:
薪火相傳:上一個(gè)slave可以是下一個(gè)slave的master,slave同樣可以接收其他slaves的連接和同步請(qǐng)求,那么該slave作為了鏈條中下一個(gè)的master,可以有效減輕master的寫壓力,去中心化降低風(fēng)險(xiǎn)。slaveof <ip><port>
中途轉(zhuǎn)向變更:會(huì)清除之前的數(shù)據(jù),重新建立拷貝最新的。風(fēng)險(xiǎn)是一旦某個(gè)slave宕機(jī),后面的slave都沒辦法備份。主機(jī)掛了,從機(jī)還是從機(jī),無(wú)法寫數(shù)據(jù)。

反客為主:當(dāng)一個(gè)master宕機(jī)后,后面的slave可以立刻升為master,其后面的slave不用做任何修改。用slaveof no one將從機(jī)變?yōu)橹鳈C(jī)。
7.2 復(fù)制原理
slave啟動(dòng)成功連接到master后會(huì)發(fā)送一個(gè)sync命令。
Master接到命令啟動(dòng)后臺(tái)的存盤進(jìn)程,同時(shí)收集所有接收到的用于修改數(shù)據(jù)集命令,在后臺(tái)進(jìn)程執(zhí)行完畢之后,master將傳送整個(gè)數(shù)據(jù)文件到slave,以完成一次同步。
全量復(fù)制:而slave服務(wù)在接受到數(shù)據(jù)庫(kù)文件數(shù)據(jù)之后,將其存盤并加載到內(nèi)存中。
增量復(fù)制:Master繼續(xù)將新的所有收集到的修改命令依次傳給slave,完成同步。
但是只要是重新連接master,一次完全同步(全量復(fù)制)將被自動(dòng)執(zhí)行。

7.3 哨兵模式
反客為主的自動(dòng)版,能夠?qū)⒑笈_(tái)監(jiān)控主機(jī)是否故障,如果故障了根據(jù)投票數(shù)自動(dòng)將從庫(kù)轉(zhuǎn)換為主庫(kù)。

sentinel monitor mymaster 127.0.0.1 6379 1
mymaster為監(jiān)控對(duì)象起的服務(wù)器名稱,1為至少有多個(gè)哨兵同意遷移的數(shù)量。
選舉從機(jī)的優(yōu)先級(jí)別是slave-priority,原主機(jī)重啟后會(huì)變?yōu)閺臋C(jī)。

8.集群?jiǎn)栴}
容量不夠,redis如何進(jìn)行擴(kuò)容?
并發(fā)寫操作,redis如何分?jǐn)偅?/p>
另外,主從模式,薪火相傳模式,主機(jī)宕機(jī),導(dǎo)致ip地址發(fā)生變化,應(yīng)用程序中配置需要修改對(duì)應(yīng)的主機(jī)地址、端口等信息。 之前通過代理主機(jī)來解決,但是redis3.0中提供了解決方案。就是無(wú)中心化集群配置。
定義:Redis集群實(shí)現(xiàn)了對(duì)Redis的水平擴(kuò)容,即啟動(dòng)N個(gè)節(jié)點(diǎn),將數(shù)據(jù)庫(kù)分布存儲(chǔ)在這N個(gè)節(jié)點(diǎn)中,每個(gè)節(jié)點(diǎn)存儲(chǔ)總數(shù)居的1/N。Redis集群通過分區(qū)來提供一定程度的可用性:即使集群中有一部分節(jié)點(diǎn)失效或者無(wú)法進(jìn)行通訊,集群也可以繼續(xù)處理命令請(qǐng)求。
構(gòu)建六個(gè)實(shí)例:
8.1 redis cluster如何分配這六個(gè)節(jié)點(diǎn)。
一個(gè)集群至少要有三個(gè)主節(jié)點(diǎn)。 選項(xiàng) --cluster-replicas 1 表示我們希望為集群中的每個(gè)主節(jié)點(diǎn)創(chuàng)建一個(gè)從節(jié)點(diǎn)。 分配原則盡量保證每個(gè)主數(shù)據(jù)庫(kù)運(yùn)行在不同的IP地址,每個(gè)從庫(kù)和主庫(kù)不在一個(gè)IP地址上。
8.2 slots
一個(gè)Redis集群包含16384個(gè)插槽,數(shù)據(jù)庫(kù)中的每個(gè)鍵都屬于這16384個(gè)插槽的其中一個(gè)。集群使用公式CRC16(key)%16384來計(jì)算鍵key屬于哪個(gè)槽,其中CRC16(key)語(yǔ)句用于計(jì)算鍵key的CRC16校驗(yàn)和。
集群中的每個(gè)節(jié)點(diǎn)負(fù)責(zé)處理一部分插槽。舉個(gè)例子,如果一個(gè)集群可以有主節(jié)點(diǎn),其中:
節(jié)點(diǎn)A負(fù)責(zé)處理0號(hào)到5460號(hào)插槽。
節(jié)點(diǎn)B負(fù)責(zé)處理5461號(hào)至10922號(hào)插槽。
節(jié)點(diǎn)C負(fù)責(zé)處理10923號(hào)至16383號(hào)插槽。
注意:不在一個(gè)slot下的鍵值,是不能使用mget,mset等多建操作。
8.3 故障恢復(fù)
主節(jié)點(diǎn)下線,從節(jié)點(diǎn)能否自動(dòng)升為主節(jié)點(diǎn),注意15秒超時(shí)。
主節(jié)點(diǎn)恢復(fù)后,主節(jié)點(diǎn)變成從機(jī)。
如果某一段插槽的主從節(jié)點(diǎn)都宕機(jī)掉,而cluster-require-full-coverage 為yes,那么整個(gè)集群都掛掉。
如果某一段插槽的主從都掛掉,而cluster-require-full-coverage 為no ,那么,該插槽數(shù)據(jù)全都不能使用,也無(wú)法存儲(chǔ)。
8.4 Redis集群的優(yōu)點(diǎn)和不足
優(yōu)點(diǎn):實(shí)現(xiàn)擴(kuò)容、分?jǐn)倝毫?、無(wú)中心配置相對(duì)簡(jiǎn)單。
不足:多建操作不被支持,多建的Redis事務(wù)不被支持,lua腳本不被支持。
9.緩存穿透、擊穿、雪崩和分布式鎖
9.1 緩存穿透
key對(duì)應(yīng)的數(shù)據(jù)在數(shù)據(jù)源并不存在,每次針對(duì)key的請(qǐng)求從緩存獲取不到,請(qǐng)求都會(huì)被壓到數(shù)據(jù)源,從而可能壓垮數(shù)據(jù)源。比如用一個(gè)不存在的用戶id獲取用戶信息,不論緩存還是數(shù)據(jù)庫(kù)都沒有,若黑客利用此漏洞進(jìn)行攻擊可能壓垮數(shù)據(jù)庫(kù)。

解決方案:
對(duì)空值緩存:如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)是否不存在),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存,設(shè)置空結(jié)果的過期時(shí)間會(huì)很短,最長(zhǎng)不超過五分鐘。
設(shè)置可訪問的白名單:使用bitmaps類型定義一個(gè)可以訪問的名單,名單id作為bitmaps的偏移量,每次訪問和bitmaps里面的id進(jìn)行比較,如果訪問id不在bitmaps里面,進(jìn)行攔截,不允許訪問。
采用布隆過濾器:實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量(位圖)和一系列隨機(jī)映射函數(shù)(哈希函數(shù)),布隆過濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中,它的優(yōu)點(diǎn)是空間和查詢效率都遠(yuǎn)超過一般的算法,缺點(diǎn)是有一定的誤識(shí)別率和刪除困難。將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmaps中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmaps攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力。
進(jìn)行實(shí)時(shí)監(jiān)控:當(dāng)發(fā)現(xiàn)Redis的命中率開始急速降低,需要排查訪問對(duì)象和訪問數(shù)據(jù),和運(yùn)維人員配合,可以設(shè)置黑名單限制服務(wù)。
9.2 緩存擊穿
key對(duì)應(yīng)的數(shù)據(jù)存在,但在redis中過期,此時(shí)若有大量并發(fā)請(qǐng)求過來,這些請(qǐng)求發(fā)現(xiàn)緩存過期一般都會(huì)從后端DB加載數(shù)據(jù)并回設(shè)到緩存,這個(gè)時(shí)候大并發(fā)的請(qǐng)求可能會(huì)瞬間把后端DB壓垮。

key可能會(huì)在某些時(shí)間點(diǎn)被超高并發(fā)地訪問,是一種非常“熱點(diǎn)”的數(shù)據(jù)。這個(gè)時(shí)候,需要考慮一個(gè)問題:緩存被“擊穿”的問題。
解決方案:
預(yù)先設(shè)置熱門數(shù)據(jù):在redis高峰訪問之前,把一些熱門數(shù)據(jù)提前存入到redis里面,加大這些熱門數(shù)據(jù)key的時(shí)長(zhǎng)。
實(shí)時(shí)調(diào)整:現(xiàn)場(chǎng)監(jiān)控哪些數(shù)據(jù)熱門,實(shí)時(shí)調(diào)整key的過期時(shí)長(zhǎng)。
-
使用鎖:

9.3 緩存雪崩
緩存擊穿和緩存雪崩的區(qū)別在于,緩存雪崩這里針對(duì)很多key緩存過期,而緩存擊穿則是某一個(gè)key過期。


解決方案:
構(gòu)建多級(jí)緩存架構(gòu):nginx緩存+redis緩存+其他緩存
使用鎖或隊(duì)列:用加鎖或者隊(duì)列的方式保證來保證不會(huì)有大量的線程對(duì)數(shù)據(jù)庫(kù)一次性進(jìn)行讀寫,從而避免失效時(shí)大量的并發(fā)請(qǐng)求落到底層存儲(chǔ)系統(tǒng)上。不適用高并發(fā)情況
設(shè)置過期標(biāo)值更新緩存:記錄緩存數(shù)據(jù)是否過期(設(shè)置提前量),如果過期會(huì)觸發(fā)通知另外的線程在后臺(tái)去更新實(shí)際key的緩存。
將緩存失效時(shí)間分散開來:比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過期時(shí)間的重復(fù)率就會(huì)降低,就很難引發(fā)集體失效的事件。
9.4 分布式鎖
分布式集群后,分布式系統(tǒng)多線程、多進(jìn)程并且分布在不同機(jī)器上,單機(jī)的并發(fā)控制鎖策略就會(huì)失效,單純的Java API并不能提供分布式鎖的能力。為了解決這個(gè)問題就需要一種跨JVM的互斥機(jī)制來控制共享資源的訪問,這就是分布式鎖要解決的問題。

