Redis架構(gòu)原理及應(yīng)用實(shí)踐

一.Redis簡(jiǎn)介

Redis 是完全開源免費(fèi)的扛禽,是一個(gè)高性能的key-value類型的內(nèi)存數(shù)據(jù)庫(kù)萍程。整個(gè)數(shù)據(jù)庫(kù)統(tǒng)統(tǒng)加載在內(nèi)存當(dāng)中進(jìn)行操作,定期通過異步操作把數(shù)據(jù)庫(kù)數(shù)據(jù)flush到硬盤上進(jìn)行保存。因?yàn)槭羌儍?nèi)存操作,Redis的性能非常出色奴烙,每秒可以處理超過 10萬(wàn)次讀寫操作,是已知性能最快的Key-Value DB。

Redis的出色之處不僅僅是性能切诀,Redis最大的魅力是支持保存多種數(shù)據(jù)結(jié)構(gòu)揩环,此外單個(gè)value的最大限制是1GB,因此Redis可以用來實(shí)現(xiàn)很多有用的功能幅虑,比方說用List來做FIFO雙向鏈表丰滑,實(shí)現(xiàn)一個(gè)輕量級(jí)的高性 能消息隊(duì)列服務(wù),用他的Set可以做高性能的tag系統(tǒng)等等倒庵。另外Redis也可以對(duì)存入的Key-Value設(shè)置expire時(shí)間褒墨。總結(jié)來說擎宝,使用Redis的好處如下:

1.速度快郁妈,因?yàn)閿?shù)據(jù)存在內(nèi)存中,讀的速度是 110000 次 /s, 寫的速度是 81000 次 /s绍申;

2.支持豐富數(shù)據(jù)類型噩咪,支持string,list失晴,set剧腻,sorted set,hash涂屁;

3.支持事務(wù)书在,操作都是原子性,對(duì)數(shù)據(jù)的更改要么全部執(zhí)行拆又,要么全部不執(zhí)行儒旬,事務(wù)中任意命令執(zhí)行失敗,其余命令依然被執(zhí)行帖族。也就是說 Redis 事務(wù)不保證原子性栈源,也不支持回滾;事務(wù)中的多條命令被一次性發(fā)送給服務(wù)器竖般,服務(wù)器在執(zhí)行命令期間甚垦,不會(huì)去執(zhí)行其他客戶端的命令請(qǐng)求。

4.豐富的特性:可用于緩存涣雕,消息(支持 publish/subscribe 通知)艰亮,按key設(shè)置過期時(shí)間,過期后將會(huì)自動(dòng)刪除挣郭,具體淘汰策略有:

  4.1.volatile-lru:從已經(jīng)設(shè)置過期時(shí)間的數(shù)據(jù)集中迄埃,挑選最近最少使用的數(shù)據(jù)淘汰

  4.2.volatile-ttl:從已經(jīng)設(shè)置過期時(shí)間的數(shù)據(jù)集中,挑選即將要過期的數(shù)據(jù)淘汰

  4.3.volatile-random:從已經(jīng)設(shè)置過期時(shí)間的數(shù)據(jù)集中兑障,隨機(jī)挑選數(shù)據(jù)淘汰

  4.4.allkeys-lru:從所有的數(shù)據(jù)集中侄非,挑選最近最少使用的數(shù)據(jù)淘汰

  4.5.allkeys-random:從所有的數(shù)據(jù)集中蕉汪,隨機(jī)挑選數(shù)據(jù)淘汰

  4.6.no-enviction:禁止淘汰數(shù)據(jù)

具體過期鍵的策略有:定時(shí)刪除(緩存過期時(shí)間到就刪除,創(chuàng)建timer耗CPU)逞怨,惰性刪除(獲取的時(shí)候檢查者疤,不獲取一直留在內(nèi)存,對(duì)內(nèi)存不友好)骇钦,定期刪除(CPU和內(nèi)存的折中方案)

5.支持?jǐn)?shù)據(jù)持久化宛渐,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時(shí)候可以再次加載進(jìn)行使用眯搭;

6.支持?jǐn)?shù)據(jù)的備份,即 master - slave 模式的數(shù)據(jù)備份业岁。

Redis的主要缺點(diǎn)是數(shù)據(jù)庫(kù)容量受到物理內(nèi)存的限制鳞仙,不能用作海量數(shù)據(jù)的高性能讀寫,因此Redis適合的場(chǎng)景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上笔时。


二.Redis的數(shù)據(jù)類型

Redis 支持 5 中數(shù)據(jù)類型:string(字符串)棍好,hash(哈希),list(列表)允耿,set(集合)借笙,zset(sorted set:有序集合)。每種數(shù)據(jù)類型的具體命令請(qǐng)參考Redis 命令參考

string

string 是 redis 最基本的數(shù)據(jù)類型较锡。一個(gè) key 對(duì)應(yīng)一個(gè) value业稼。string 是二進(jìn)制安全的。也就是說 redis 的 string 可以包含任何數(shù)據(jù)蚂蕴。比如 jpg 圖片或者序列化的對(duì)象低散。string 類型是 redis 最基本的數(shù)據(jù)類型,string 類型的值最大能存儲(chǔ) 512 MB骡楼。

hash

Redis hash 是一個(gè)鍵值對(duì)(key - value)集合熔号。Redis hash 是一個(gè) string 類型的 key 和 value 的映射表,hash 特別適合用于存儲(chǔ)對(duì)象鸟整。并且可以像數(shù)據(jù)庫(kù)中一樣只對(duì)某一項(xiàng)屬性值進(jìn)行存儲(chǔ)引镊、讀取、修改等操作篮条。

list

Redis 列表是簡(jiǎn)單的字符串列表弟头,按照插入順序排序。我們可以網(wǎng)列表的左邊或者右邊添加元素兑燥。?list 就是一個(gè)簡(jiǎn)單的字符串集合亮瓷,和 Java 中的 list 相差不大,區(qū)別就是這里的 list 存放的是字符串降瞳。list 內(nèi)的元素是可重復(fù)的嘱支◎拘兀可以做消息隊(duì)列或最新消息排行等功能。

set

redis 的 set 是字符串類型的無(wú)序集合除师。集合是通過哈希表實(shí)現(xiàn)的沛膳,因此添加、刪除汛聚、查找的復(fù)雜度都是 O(1)锹安。redis 的 set 是一個(gè) key 對(duì)應(yīng)著多個(gè)字符串類型的 value,也是一個(gè)字符串類型的集合倚舀,和 redis 的 list 不同的是 set 中的字符串集合元素不能重復(fù)叹哭,但是 list 可以。利用唯一性痕貌,可以統(tǒng)計(jì)訪問網(wǎng)站的所有獨(dú)立 ip风罩。

Zset

redis zset 和 set 一樣都是字符串類型元素的集合,并且集合內(nèi)的元素不能重復(fù)舵稠。不同的是 zset 每個(gè)元素都會(huì)關(guān)聯(lián)一個(gè) double 類型的分?jǐn)?shù)超升。redis 通過分?jǐn)?shù)來為集合中的成員進(jìn)行從小到大的排序。zset 的元素是唯一的哺徊,但是分?jǐn)?shù)(score)卻可以重復(fù)室琢。可用作排行榜等場(chǎng)景落追。

三.redis適用場(chǎng)景

1.會(huì)話緩存(Session Cache)

最常用的一種使用Redis的情景是會(huì)話緩存(session cache)盈滴。用Redis緩存會(huì)話比其他存儲(chǔ)(如Memcached)的優(yōu)勢(shì)在于:Redis提供持久化。當(dāng)維護(hù)一個(gè)不是嚴(yán)格要求一致性的緩存時(shí)淋硝,如果用戶的購(gòu)物車信息全部丟失雹熬,大部分人都會(huì)不高興的。

2.隊(duì)列

Reids在內(nèi)存存儲(chǔ)引擎領(lǐng)域的一大優(yōu)點(diǎn)是提供 list 和 set 操作谣膳,這使得Redis能作為一個(gè)很好的消息隊(duì)列平臺(tái)來使用竿报。Redis作為隊(duì)列使用的操作,就類似于本地程序語(yǔ)言(如Python)對(duì) list 的 push/pop 操作继谚。

3.全頁(yè)緩存

大型互聯(lián)網(wǎng)公司都會(huì)使用Redis作為緩存存儲(chǔ)數(shù)據(jù)烈菌,提升頁(yè)面相應(yīng)速度。即使重啟了Redis實(shí)例花履,因?yàn)橛写疟P的持久化芽世,用戶也不會(huì)看到頁(yè)面加載速度的下降祭犯。

4.排行榜/計(jì)數(shù)器

Redis在內(nèi)存中對(duì)數(shù)字進(jìn)行遞增或遞減的操作實(shí)現(xiàn)的非常好喜命。集合(Set)和有序集合(Sorted Set)也使得我們?cè)趫?zhí)行這些操作的時(shí)候變的非常簡(jiǎn)單沟娱。

四.Redis高可用架構(gòu)

1.持久化

Redis 是內(nèi)存型數(shù)據(jù)庫(kù)纤控,為了保證數(shù)據(jù)在斷電后不會(huì)丟失,需要將內(nèi)存中的數(shù)據(jù)持久化到硬盤上厦滤。Redis提供了兩種持久化的方式片任,分別是RDB(Redis DataBase)和AOF(Append Only File)逗概。

RDB

簡(jiǎn)而言之,就是在不同的時(shí)間點(diǎn)箕宙,將redis存儲(chǔ)的數(shù)據(jù)生成快照并存儲(chǔ)到磁盤等介質(zhì)上嚎朽,可以將快照復(fù)制到其他服務(wù)器從而創(chuàng)建具有相同數(shù)據(jù)的服務(wù)器副本。如果系統(tǒng)發(fā)生故障柬帕,將會(huì)丟失最后一次創(chuàng)建快照之后的數(shù)據(jù)哟忍。如果數(shù)據(jù)量大,保存快照的時(shí)間會(huì)很長(zhǎng)陷寝。

AOF

換了一個(gè)角度來實(shí)現(xiàn)持久化锅很,那就是將redis執(zhí)行過的所有寫指令記錄下來,在下次redis重新啟動(dòng)時(shí)凤跑,只要把這些寫指令從前到后再重復(fù)執(zhí)行一遍粗蔚,就可以實(shí)現(xiàn)數(shù)據(jù)恢復(fù)了。將寫命令添加到 AOF 文件(append only file)末尾饶火。

使用 AOF 持久化需要設(shè)置同步選項(xiàng),從而確保寫命令同步到磁盤文件上的時(shí)機(jī)致扯。這是因?yàn)閷?duì)文件進(jìn)行寫入并不會(huì)馬上將內(nèi)容同步到磁盤上肤寝,而是先存儲(chǔ)到緩沖區(qū),然后由操作系統(tǒng)決定什么時(shí)候同步到磁盤抖僵。選項(xiàng)同步頻率always每個(gè)寫命令都同步鲤看,eyerysec每秒同步一次,no讓操作系統(tǒng)來決定何時(shí)同步耍群,always 選項(xiàng)會(huì)嚴(yán)重減低服務(wù)器的性能义桂,everysec 選項(xiàng)比較合適,可以保證系統(tǒng)崩潰時(shí)只會(huì)丟失一秒左右的數(shù)據(jù)蹈垢,并且 Redis 每秒執(zhí)行一次同步對(duì)服務(wù)器幾乎沒有任何影響慷吊。no 選項(xiàng)并不能給服務(wù)器性能帶來多大的提升,而且會(huì)增加系統(tǒng)崩潰時(shí)數(shù)據(jù)丟失的數(shù)量曹抬。隨著服務(wù)器寫請(qǐng)求的增多溉瓶,AOF 文件會(huì)越來越大。Redis 提供了一種將 AOF 重寫的特性谤民,能夠去除 AOF 文件中的冗余寫命令堰酿。

其實(shí)RDB和AOF兩種方式也可以同時(shí)使用,在這種情況下张足,如果redis重啟的話触创,則會(huì)優(yōu)先采用AOF方式來進(jìn)行數(shù)據(jù)恢復(fù),這是因?yàn)锳OF方式的數(shù)據(jù)恢復(fù)完整度更高为牍。如果你沒有數(shù)據(jù)持久化的需求哼绑,也完全可以關(guān)閉RDB和AOF方式岩馍,這樣的話,redis將變成一個(gè)純內(nèi)存數(shù)據(jù)庫(kù)凌那。

2.復(fù)制

Redis為了解決單點(diǎn)數(shù)據(jù)庫(kù)問題兼雄,會(huì)把數(shù)據(jù)復(fù)制多個(gè)副本部署到其他節(jié)點(diǎn)上,通過復(fù)制帽蝶,實(shí)現(xiàn)Redis的高可用性赦肋,實(shí)現(xiàn)對(duì)數(shù)據(jù)的冗余備份,保證數(shù)據(jù)和服務(wù)的高度可靠性励稳。Redis有主從和主備兩種方式解決單點(diǎn)問題佃乘,主備(keepalived)模式下主機(jī)備機(jī)對(duì)外提供同一個(gè)虛擬IP,客戶端通過虛擬IP進(jìn)行數(shù)據(jù)操作驹尼,正常期間主機(jī)一直對(duì)外提供服務(wù)趣避,宕機(jī)后VIP自動(dòng)漂移到備機(jī)上。 主從模式下當(dāng)Master宕機(jī)后新翎,通過選舉算法(Paxos程帕、Raft)從slave中選舉出新Master繼續(xù)對(duì)外提供服務(wù),主機(jī)恢復(fù)后以slave的身份重新加入地啰,此模式下可以使用讀寫分離愁拭,如果數(shù)據(jù)量比較大,不希望過多浪費(fèi)機(jī)器亏吝,還希望在宕機(jī)后岭埠,做一些自定義的措施,比如報(bào)警蔚鸥、記日志惜论、數(shù)據(jù)遷移等操作,推薦使用主從方式止喷,因?yàn)楹椭鲝拇钆涞囊话氵€有個(gè)管理監(jiān)控中心(哨兵)馆类。

①?gòu)臄?shù)據(jù)庫(kù)向主數(shù)據(jù)庫(kù)發(fā)送sync(數(shù)據(jù)同步)命令。

②主數(shù)據(jù)庫(kù)接收同步命令后启盛,會(huì)保存快照蹦掐,創(chuàng)建一個(gè)RDB文件。

③當(dāng)主數(shù)據(jù)庫(kù)執(zhí)行完保持快照后僵闯,會(huì)向從數(shù)據(jù)庫(kù)發(fā)送RDB文件卧抗,而從數(shù)據(jù)庫(kù)會(huì)接收并載入該文件。

④主數(shù)據(jù)庫(kù)將緩沖區(qū)的所有寫命令發(fā)給從服務(wù)器執(zhí)行鳖粟。

⑤以上處理完之后社裆,之后主數(shù)據(jù)庫(kù)每執(zhí)行一個(gè)寫命令,都會(huì)將被執(zhí)行的寫命令發(fā)送給從數(shù)據(jù)庫(kù)向图∮拘悖可以同步發(fā)送也可以異步發(fā)送标沪,同步發(fā)送可以不用每臺(tái)都同步,可以配置一臺(tái)master嗜傅,一臺(tái)slave金句,同時(shí)這臺(tái)salve又作為其他slave的master。異步方式無(wú)法保證數(shù)據(jù)的完整性吕嘀,比如在異步同步過程中主機(jī)突然宕機(jī)了违寞,也稱這種方式為數(shù)據(jù)弱一致性。

注意:在Redis2.8之后偶房,主從斷開重連后會(huì)根據(jù)斷開之前最新的命令偏移量進(jìn)行增量復(fù)制趁曼。

3.哨兵

哨兵是Redis集群架構(gòu)中非常重要的一個(gè)組件,哨兵的出現(xiàn)主要是解決了主從復(fù)制出現(xiàn)故障時(shí)需要人為干預(yù)的問題棕洋。

1.Redis哨兵主要功能

(1)集群監(jiān)控:負(fù)責(zé)監(jiān)控Redis master和slave進(jìn)程是否正常工作

(2)消息通知:如果某個(gè)Redis實(shí)例有故障挡闰,那么哨兵負(fù)責(zé)發(fā)送消息作為報(bào)警通知給管理員

(3)故障轉(zhuǎn)移:如果master node掛掉了,會(huì)自動(dòng)轉(zhuǎn)移到slave node上

(4)配置中心:如果故障轉(zhuǎn)移發(fā)生了掰盘,通知client客戶端新的master地址

2.Redis哨兵的高可用


原理:當(dāng)主節(jié)點(diǎn)出現(xiàn)故障時(shí)摄悯,由Redis Sentinel自動(dòng)完成故障發(fā)現(xiàn)和轉(zhuǎn)移,并通知應(yīng)用方愧捕,實(shí)現(xiàn)高可用性射众。哨兵機(jī)制建立了多個(gè)哨兵節(jié)點(diǎn)(進(jìn)程),共同監(jiān)控?cái)?shù)據(jù)節(jié)點(diǎn)的運(yùn)行狀況晃财。同時(shí)哨兵節(jié)點(diǎn)之間也互相通信,交換對(duì)主從節(jié)點(diǎn)的監(jiān)控狀況典蜕。每隔1秒每個(gè)哨兵會(huì)向整個(gè)集群:Master主服務(wù)器+Slave從服務(wù)器+其他Sentinel(哨兵)進(jìn)程断盛,發(fā)送一次ping命令做一次心跳檢測(cè)。這個(gè)就是哨兵用來判斷節(jié)點(diǎn)是否正常的重要依據(jù)愉舔,涉及兩個(gè)新的概念:主觀下線和客觀下線钢猛。一個(gè)哨兵節(jié)點(diǎn)判定主節(jié)點(diǎn)down掉是主觀下線,只有半數(shù)哨兵節(jié)點(diǎn)都主觀判定主節(jié)點(diǎn)down掉轩缤,此時(shí)多個(gè)哨兵節(jié)點(diǎn)交換主觀判定結(jié)果命迈,才會(huì)判定主節(jié)點(diǎn)客觀下線』鸬模基本上哪個(gè)哨兵節(jié)點(diǎn)最先判斷出這個(gè)主節(jié)點(diǎn)客觀下線壶愤,就會(huì)在各個(gè)哨兵節(jié)點(diǎn)中發(fā)起投票機(jī)制Raft算法(選舉算法),最終被投為領(lǐng)導(dǎo)者的哨兵節(jié)點(diǎn)完成主從自動(dòng)化切換的過程馏鹤。


4.集群

至少部署兩臺(tái)Redis服務(wù)器構(gòu)成一個(gè)小的集群征椒,主要有2個(gè)目的:

高可用性:在主機(jī)掛掉后,自動(dòng)故障轉(zhuǎn)移湃累,使前端服務(wù)對(duì)用戶無(wú)影響勃救。

讀寫分離:將主機(jī)讀壓力分流到從機(jī)上碍讨。

可在客戶端組件上實(shí)現(xiàn)負(fù)載均衡,根據(jù)不同服務(wù)器的運(yùn)行情況蒙秒,分擔(dān)不同比例的讀請(qǐng)求壓力勃黍。


緩存數(shù)據(jù)量不斷增加時(shí)晕讲,單機(jī)內(nèi)存不夠使用覆获,需要把數(shù)據(jù)切分不同部分,分布到多臺(tái)服務(wù)器上益兄。 可在客戶端對(duì)數(shù)據(jù)進(jìn)行分片锻梳,數(shù)據(jù)分片算法詳見一致性Hash詳解、虛擬桶分片净捅。


當(dāng)數(shù)據(jù)量持續(xù)增加時(shí)疑枯,應(yīng)用可根據(jù)不同場(chǎng)景下的業(yè)務(wù)申請(qǐng)對(duì)應(yīng)的分布式集群。 這塊最關(guān)鍵的是緩存治理這塊蛔六,其中最重要的部分是加入了代理服務(wù)(Codis和Twemproxy)荆永。 應(yīng)用通過代理訪問真實(shí)的Redis服務(wù)器進(jìn)行讀寫,這樣做的好處是避免越來越多的客戶端直接訪問Redis服務(wù)器難以管理国章,而造成風(fēng)險(xiǎn)具钥,在代理這一層可以做對(duì)應(yīng)的安全措施,比如限流液兽、授權(quán)骂删、分片,避免客戶端越來越多的邏輯代碼四啰,不但臃腫升級(jí)還比較麻煩宁玫。代理這層無(wú)狀態(tài)的,可任意擴(kuò)展節(jié)點(diǎn)柑晒,對(duì)于客戶端來說欧瘪,訪問代理跟訪問單機(jī)Redis一樣。



Redis Cluster是Redis官網(wǎng)給出的集群架構(gòu)


客戶端與Redis節(jié)點(diǎn)直連,不需要中間Proxy層匙赞,直接連接任意一個(gè)Master節(jié)點(diǎn)佛掖,根據(jù)公式HASH_SLOT=CRC16(key) mod 16384,計(jì)算出映射到哪個(gè)分片上涌庭,然后Redis會(huì)去相應(yīng)的節(jié)點(diǎn)進(jìn)行操作

具有如下優(yōu)點(diǎn):

(1)無(wú)需Sentinel哨兵監(jiān)控芥被,如果Master掛了,Redis Cluster內(nèi)部自動(dòng)將Slave切換Master

(2)可以進(jìn)行水平擴(kuò)容

(3)支持自動(dòng)化遷移坐榆,當(dāng)出現(xiàn)某個(gè)Slave宕機(jī)了撕彤,那么就只有Master了,這時(shí)候的高可用性就無(wú)法很好的保證了,萬(wàn)一Master也宕機(jī)了羹铅,咋辦呢蚀狰? 針對(duì)這種情況,如果說其他Master有多余的Slave 职员,集群自動(dòng)把多余的Slave遷移到?jīng)]有Slave的Master 中麻蹋。

缺點(diǎn):

(1)批量操作是個(gè)坑,不同的key會(huì)劃分到不同的slot中焊切,因此直接使用mset或者mget等操作是行不通的扮授。如果執(zhí)行的key數(shù)量比較少,就不用mget了专肪,就用串行g(shù)et操作刹勃。如果真的需要執(zhí)行的key很多,就使用Hashtag保證這些key映射到同一臺(tái)Redis節(jié)點(diǎn)上嚎尤。

(2)資源隔離性較差荔仁,容易出現(xiàn)相互影響的情況。

五.Redis高并發(fā)及熱key解決之道

1.并發(fā)設(shè)置key及分布式鎖

Redis是一種單線程機(jī)制的nosql數(shù)據(jù)庫(kù)芽死,基于key-value乏梁,數(shù)據(jù)可持久化落盤。由于單線程所以Redis本身并沒有鎖的概念关贵,多個(gè)客戶端連接并不存在競(jìng)爭(zhēng)關(guān)系遇骑,但是利用jedis等客戶端對(duì)Redis進(jìn)行并發(fā)訪問時(shí)會(huì)出現(xiàn)問題。比如多客戶端同時(shí)并發(fā)寫一個(gè)key揖曾,一個(gè)key的值是1落萎,本來按順序修改為2,3,4,最后是4炭剪,但是順序變成了4,3,2模暗,最后變成了2。使用分布式鎖防止并發(fā)設(shè)置Key的原理及代碼見:使用Redis實(shí)現(xiàn)分布式鎖及其優(yōu)化念祭,另外一種方式是使用消息隊(duì)列,把并行讀寫進(jìn)行串行化。

2.熱key問題

熱key問題說來也很簡(jiǎn)單碍侦,就是瞬間有幾十萬(wàn)的請(qǐng)求去訪問redis上某個(gè)固定的key粱坤,從而壓垮緩存服務(wù)的情情況。其實(shí)生活中也是有不少這樣的例子瓷产。比如XX明星結(jié)婚站玄。那么關(guān)于XX明星的Key就會(huì)瞬間增大,就會(huì)出現(xiàn)熱數(shù)據(jù)問題濒旦。那么如何發(fā)現(xiàn)熱KEY呢:

1.憑借業(yè)務(wù)經(jīng)驗(yàn)株旷,進(jìn)行預(yù)估哪些是熱key

2.在客戶端進(jìn)行收集

3.在Proxy層做收集

4.用redis自帶命令(monitor命令、hotkeys參數(shù))

5.自己抓包評(píng)估

解決方案:

1.利用二級(jí)緩存,比如利用ehcache晾剖,或者一個(gè)HashMap都可以锉矢。在你發(fā)現(xiàn)熱key以后,把熱key加載到系統(tǒng)的JVM中齿尽。

2.備份熱key沽损,不要讓key走到同一臺(tái)redis上。我們把這個(gè)key循头,在多個(gè)redis上都存一份绵估。可以用HOTKEY加上一個(gè)隨機(jī)數(shù)(N卡骂,集群分片數(shù))組成一個(gè)新key国裳。

3.熱點(diǎn)數(shù)據(jù)盡量不要設(shè)置過期時(shí)間,在數(shù)據(jù)變更時(shí)同步寫緩存全跨,防止高并發(fā)下重建緩存的資源損耗缝左。可以用setnx做分布式鎖保證只有一個(gè)線程在重建緩存螟蒸,其他線程等待重建緩存的線程執(zhí)行完盒使,重新從緩存獲取數(shù)據(jù)即可。

3.緩存穿透

緩存穿透是指查詢一個(gè)根本不存在的數(shù)據(jù)七嫌,緩存層和存儲(chǔ)層都不會(huì)命中少办,但是出于容錯(cuò)的考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫入緩存層诵原。緩存穿透將導(dǎo)致不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢英妓,失去了緩存保護(hù)后端存儲(chǔ)的意義。造成緩存穿透的基本有兩個(gè)绍赛。第一蔓纠,業(yè)務(wù)自身代碼或者數(shù)據(jù)出現(xiàn)問題,第二吗蚌,一些惡意攻擊腿倚、爬蟲等造成大量空命中,下面我們來看一下如何解決緩存穿透問題蚯妇。解決緩存穿透的兩種方案:

1)緩存空對(duì)象

緩存空對(duì)象會(huì)有兩個(gè)問題:

第一敷燎,空值做了緩存,意味著緩存層中存了更多的鍵箩言,需要更多的內(nèi)存空間 ( 如果是攻擊硬贯,問題更嚴(yán)重 ),比較有效的方法是針對(duì)這類數(shù)據(jù)設(shè)置一個(gè)較短的過期時(shí)間陨收,讓其自動(dòng)剔除饭豹。

第二,緩存層和存儲(chǔ)層的數(shù)據(jù)會(huì)有一段時(shí)間窗口的不一致,可能會(huì)對(duì)業(yè)務(wù)有一定影響拄衰。例如過期時(shí)間設(shè)置為 5 分鐘它褪,如果此時(shí)存儲(chǔ)層添加了這個(gè)數(shù)據(jù),那此段時(shí)間就會(huì)出現(xiàn)緩存層和存儲(chǔ)層數(shù)據(jù)的不一致肾砂,此時(shí)可以利用消息系統(tǒng)或者其他方式清除掉緩存層中的空對(duì)象列赎。

2)布隆過濾器攔截

如下圖所示,在訪問緩存層和存儲(chǔ)層之前镐确,將存在的 key 用布隆過濾器提前保存起來包吝,做第一層攔截。如果布隆過濾器認(rèn)為該用戶 ID 不存在源葫,那么就不會(huì)訪問存儲(chǔ)層诗越,在一定程度保護(hù)了存儲(chǔ)層。有關(guān)布隆過濾器的相關(guān)知識(shí)息堂,可以參考:?布隆過濾器嚷狞,可以利用 Redis 的 Bitmaps 實(shí)現(xiàn)布隆過濾器,GitHub 上已經(jīng)開源了類似的方案荣堰,讀者可以進(jìn)行參考:redis bitmaps實(shí)現(xiàn)布隆過濾器


緩存空對(duì)象和布隆過濾器方案對(duì)比

4.緩存雪崩

數(shù)據(jù)未加載到緩存中床未,或者緩存同一時(shí)間大面積的失效,從而導(dǎo)致所有請(qǐng)求都去查數(shù)據(jù)庫(kù)振坚,導(dǎo)致數(shù)據(jù)庫(kù)CPU和內(nèi)存負(fù)載過高薇搁,甚至宕機(jī)。


可以從以下幾個(gè)方面防止緩存雪崩:

1)保證緩存層服務(wù)高可用性

和飛機(jī)都有多個(gè)引擎一樣渡八,如果緩存層設(shè)計(jì)成高可用的啃洋,即使個(gè)別節(jié)點(diǎn)、個(gè)別機(jī)器屎鳍、甚至是機(jī)房宕掉宏娄,依然可以提供服務(wù),例如前面介紹過的 Redis Sentinel 和 Redis Cluster 都實(shí)現(xiàn)了高可用逮壁。

2)Redis備份和快速預(yù)熱

Redis備份保證master出問題切換為slave迅速能夠承擔(dān)線上實(shí)際流量孵坚,快速預(yù)熱保證緩存及時(shí)被寫入緩存,防止穿透到庫(kù)窥淆。

3)依賴隔離組件為后端限流并降級(jí)

無(wú)論是緩存層還是存儲(chǔ)層都會(huì)有出錯(cuò)的概率卖宠,可以將它們視同為資源。作為并發(fā)量較大的系統(tǒng)祖乳,假如有一個(gè)資源不可用,可能會(huì)造成線程全部 hang 在這個(gè)資源上秉氧,造成整個(gè)系統(tǒng)不可用眷昆。降級(jí)在高并發(fā)系統(tǒng)中是非常正常的:比如推薦服務(wù)中,如果個(gè)性化推薦服務(wù)不可用,可以降級(jí)補(bǔ)充熱點(diǎn)數(shù)據(jù)亚斋,不至于造成前端頁(yè)面是開天窗作媚。

在實(shí)際項(xiàng)目中,我們需要對(duì)重要的資源 ( 例如 Redis帅刊、 MySQL纸泡、 Hbase、外部接口 ) 都進(jìn)行隔離赖瞒,讓每種資源都單獨(dú)運(yùn)行在自己的線程池中女揭,即使個(gè)別資源出現(xiàn)了問題,對(duì)其他服務(wù)沒有影響栏饮。但是線程池如何管理吧兔,比如如何關(guān)閉資源池,開啟資源池袍嬉,資源池閥值管理境蔼,這些做起來還是相當(dāng)復(fù)雜的,這里推薦一個(gè) Java 依賴隔離工具Hystrix(https://github.com/Netflix/Hystrix)伺通,如下圖所示箍土。

4)提前演練

在項(xiàng)目上線前,演練緩存層宕掉后罐监,應(yīng)用以及后端的負(fù)載情況以及可能出現(xiàn)的問題吴藻,在此基礎(chǔ)上做一些預(yù)案設(shè)定。

5.緩存預(yù)熱

緩存預(yù)熱就是系統(tǒng)上線前笑诅,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)调缨。這樣就可以避免上線后在用戶請(qǐng)求的時(shí)候,先查詢數(shù)據(jù)庫(kù)吆你,然后再將數(shù)據(jù)緩存的問題弦叶!用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)!

六.Redis內(nèi)存模型

Redis為什么這么快妇多?一文深入了解Redis內(nèi)存模型伤哺!

一文揭秘單線程的Redis為什么這么快?


參考文章:

學(xué)Redis這篇就夠了

Redis緩存的設(shè)計(jì)、性能者祖、應(yīng)用與數(shù)據(jù)集群同步

Redis哨兵立莉、復(fù)制、集群的設(shè)計(jì)原理七问,以及區(qū)別

圖示Redis集群架構(gòu)詳解

談?wù)剅edis的熱key問題如何解決

如何解決Redis雪崩蜓耻、穿透、并發(fā)等5大難題

Redis架構(gòu)之防雪崩設(shè)計(jì):網(wǎng)站不宕機(jī)背后的兵法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末械巡,一起剝皮案震驚了整個(gè)濱河市刹淌,隨后出現(xiàn)的幾起案子姆涩,更是在濱河造成了極大的恐慌矫废,老刑警劉巖蚪缀,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件林说,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蔼卡,警方通過查閱死者的電腦和手機(jī)喊崖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雇逞,“玉大人荤懂,你說我怎么就攤上這事『嚷停” “怎么了势誊?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)谣蠢。 經(jīng)常有香客問我粟耻,道長(zhǎng),這世上最難降的妖魔是什么眉踱? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任挤忙,我火速辦了婚禮,結(jié)果婚禮上谈喳,老公的妹妹穿的比我還像新娘册烈。我一直安慰自己,他們只是感情好婿禽,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布赏僧。 她就那樣靜靜地躺著,像睡著了一般扭倾。 火紅的嫁衣襯著肌膚如雪淀零。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天膛壹,我揣著相機(jī)與錄音驾中,去河邊找鬼。 笑死模聋,一個(gè)胖子當(dāng)著我的面吹牛肩民,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播链方,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼持痰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了祟蚀?” 一聲冷哼從身側(cè)響起工窍,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤占调,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后移剪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薪者,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年纵苛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片言津。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡攻人,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悬槽,到底是詐尸還是另有隱情怀吻,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布初婆,位于F島的核電站蓬坡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏磅叛。R本人自食惡果不足惜屑咳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弊琴。 院中可真熱鬧兆龙,春花似錦、人聲如沸敲董。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腋寨。三九已至聪铺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間精置,已是汗流浹背计寇。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脂倦,地道東北人番宁。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赖阻,于是被迫代替她去往敵國(guó)和親蝶押。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容