目錄
一、Redis集群模型
1.1、主從模式
1.1.1 主從模式優(yōu)缺點(diǎn)
1.2、哨兵模式
1.2.1 哨兵模式的作用:
1.2.2 哨兵實(shí)現(xiàn)原理
1.2.3 主觀下線和客觀下線
1.2.4 哨兵模式優(yōu)缺點(diǎn)
1.3、各大廠的Redis集群方案
1.3.1 客戶端分片
1.3.2 代理分片
Twemproxy的優(yōu)點(diǎn):
Twemproxy的不足:
1.3.3 Codis
1.4、Redis Cluster
二.RDB持久化
2.1 RDB全量寫入
2.1.1 rdb原理
2.1.2?rdb模式
2.1.3?rdb觸發(fā)情況
2.1.4?rdb優(yōu)勢(shì)和劣勢(shì)
2.1.5?rdb文件配置
2.1.6?rdb命令配置
2.1.7?rdb數(shù)據(jù)恢復(fù)
2.2 AOF持久化:增量寫入
2.2.1aof原理
2.2.2 aof觸發(fā)情況
2.2.3 aof優(yōu)勢(shì)和劣勢(shì)
2.2.4 aof文件配置
2.2.5 aof命令配置
2.2.6 aof數(shù)據(jù)恢復(fù)
2.3.RDB&AOF對(duì)比
三、Redis高階
3.1 Redis高階之緩存擊穿
3.1.1 緩存擊穿定義
3.1.2?緩存擊穿產(chǎn)生原因
3.1.3?緩存擊穿解決方案
3.1.4?緩存擊穿解決方案之互斥鎖詳解
3.2 Redis高階之緩存穿透
3.2.1 緩存穿透定義
3.2.2?緩存穿透產(chǎn)生的原因
3.2.3?緩存穿透的三種解決方案
3.2.4?緩存穿透解決方案之布隆過濾器詳解
3.3 Redis高階之緩存雪崩
3.3.1?緩存雪奔定義
3.3.2?產(chǎn)生雪崩的原因
3.3.3 緩存雪崩的四種解決方案
3.3.4 緩存雪崩解決方案之加鎖限流詳解
Redis常見面試問題
Redis簡(jiǎn)介
Redis,英文全稱是Remote Dictionary Server(遠(yuǎn)程字典服務(wù)),是一個(gè)開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫(kù),并提供多種語言的API。
與memcached一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了master-slave(主從)同步。
與MySQL數(shù)據(jù)庫(kù)不同的是,Redis的數(shù)據(jù)是存在內(nèi)存中的。它的讀寫速度非常快,每秒可以處理超過10萬次讀寫操作。因此redis被廣泛應(yīng)用于緩存,另外,Redis也經(jīng)常用來做分布式鎖。除此之外,Redis支持事務(wù)、持久化、LUA 腳本、LRU 驅(qū)動(dòng)事件、多種集群方案。
Redis 是一個(gè)高性能的key-value數(shù)據(jù)庫(kù)。 redis的出現(xiàn),很大程度補(bǔ)償了memcached這類key/value存儲(chǔ)的不足,在部 分場(chǎng)合可以對(duì)關(guān)系數(shù)據(jù)庫(kù)起到很好的補(bǔ)充作用。
Redis支持主從同步。數(shù)據(jù)可以從主服務(wù)器向任意數(shù)量的從服務(wù)器上同步,從服務(wù)器可以是關(guān)聯(lián)其他從服務(wù)器的主服務(wù)器。
一、Redis集群模型
在服務(wù)開發(fā)中,單機(jī)都會(huì)存在單點(diǎn)故障的問題,及服務(wù)部署在一場(chǎng)臺(tái)服務(wù)器上,一旦服務(wù)器宕機(jī)服務(wù)就不可用,所以為了讓服務(wù)高可用,分布式服務(wù)就出現(xiàn)了,將同一服務(wù)部署到多臺(tái)機(jī)器上,即使其中幾臺(tái)服務(wù)器宕機(jī),只要有一臺(tái)服務(wù)器可用服務(wù)就可用。
redis也是一樣,為了解決單機(jī)故障引入了主從模式,但主從模式存在一個(gè)問題:master節(jié)點(diǎn)故障后服務(wù),需要人為的手動(dòng)將slave節(jié)點(diǎn)切換成為maser節(jié)點(diǎn)后服務(wù)才恢復(fù)。redis為解決這一問題又引入了哨兵模式,哨兵模式能在master節(jié)點(diǎn)故障后能自動(dòng)將salve節(jié)點(diǎn)提升成master節(jié)點(diǎn),不需要人工干預(yù)操作就能恢復(fù)服務(wù)可用。
但是主從模式、哨兵模式都沒有達(dá)到真正的數(shù)據(jù)sharding存儲(chǔ),每個(gè)redis實(shí)例中存儲(chǔ)的都是全量數(shù)據(jù),所以redis cluster就誕生了,實(shí)現(xiàn)了真正的數(shù)據(jù)分片存儲(chǔ)。但是由于redis cluster發(fā)布得比較晚(2015年才發(fā)布正式版 ),各大廠等不及了,陸陸續(xù)續(xù)開發(fā)了自己的redis數(shù)據(jù)分片集群模式,比如:Twemproxy、Codis等。
1.1、主從模式
redis單節(jié)點(diǎn)雖然有通過RDB和AOF持久化機(jī)制能將數(shù)據(jù)持久化到硬盤上,但數(shù)據(jù)是存儲(chǔ)在一臺(tái)服務(wù)器上的,如果服務(wù)器出現(xiàn)硬盤故障等問題,會(huì)導(dǎo)致數(shù)據(jù)不可用,而且讀寫無法分離,讀寫都在同一臺(tái)服務(wù)器上,請(qǐng)求量大時(shí)會(huì)出現(xiàn)I/O瓶頸。
為了避免單點(diǎn)故障 和 讀寫不分離,Redis 提供了復(fù)制(replication)功能實(shí)現(xiàn)master數(shù)據(jù)庫(kù)中的數(shù)據(jù)更新后,會(huì)自動(dòng)將更新的數(shù)據(jù)同步到其他slave數(shù)據(jù)庫(kù)上。
如上redis主從結(jié)構(gòu)特點(diǎn):一個(gè)master可以有多個(gè)salve節(jié)點(diǎn);salve節(jié)點(diǎn)可以有slave節(jié)點(diǎn),從節(jié)點(diǎn)是級(jí)聯(lián)結(jié)構(gòu)。
1.1.1 主從模式優(yōu)缺點(diǎn)
-
優(yōu)點(diǎn): 主從結(jié)構(gòu)具有讀寫分離,提高效率、數(shù)據(jù)備份,提供多個(gè)副本等優(yōu)點(diǎn)。
-
不足: 最大的不足就是主從模式不具備自動(dòng)容錯(cuò)和恢復(fù)功能,主節(jié)點(diǎn)故障,集群則無法進(jìn)行工作,可用性比較低,從節(jié)點(diǎn)升主節(jié)點(diǎn)需要人工手動(dòng)干預(yù)。
普通的主從模式,當(dāng)主數(shù)據(jù)庫(kù)崩潰時(shí),需要手動(dòng)切換從數(shù)據(jù)庫(kù)成為主數(shù)據(jù)庫(kù):
-
在從數(shù)據(jù)庫(kù)中使用
SLAVE NO ONE
命令將從數(shù)據(jù)庫(kù)提升成主數(shù)據(jù)繼續(xù)服務(wù)。 -
啟動(dòng)之前崩潰的主數(shù)據(jù)庫(kù),然后使用SLAVEOF命令將其設(shè)置成新的主數(shù)據(jù)庫(kù)的從數(shù)據(jù)庫(kù),即可同步數(shù)據(jù)。
1.2、哨兵模式
第一種主從同步/復(fù)制的模式,當(dāng)主服務(wù)器宕機(jī)后,需要手動(dòng)把一臺(tái)從服務(wù)器切換為主服務(wù)器,這就需要人工干預(yù),費(fèi)事費(fèi)力,還會(huì)造成一段時(shí)間內(nèi)服務(wù)不可用,這時(shí)候就需要哨兵模式登場(chǎng)了。
哨兵模式是從Redis的2.6版本開始提供的,但是當(dāng)時(shí)這個(gè)版本的模式是不穩(wěn)定的,直到Redis的2.8版本以后,這個(gè)哨兵模式才穩(wěn)定下來。
哨兵模式核心還是主從復(fù)制,只不過在相對(duì)于主從模式在主節(jié)點(diǎn)宕機(jī)導(dǎo)致不可寫的情況下,多了一個(gè)競(jìng)選機(jī)制:從所有的從節(jié)點(diǎn)競(jìng)選出新的主節(jié)點(diǎn)。競(jìng)選機(jī)制的實(shí)現(xiàn),是依賴于在系統(tǒng)中啟動(dòng)一個(gè)sentinel進(jìn)程。
如上圖,哨兵本身也有單點(diǎn)故障的問題,所以在一個(gè)一主多從的Redis系統(tǒng)中,可以使用多個(gè)哨兵進(jìn)行監(jiān)控,哨兵不僅會(huì)監(jiān)控主數(shù)據(jù)庫(kù)和從數(shù)據(jù)庫(kù),哨兵之間也會(huì)相互監(jiān)控。每一個(gè)哨兵都是一個(gè)獨(dú)立的進(jìn)程,作為進(jìn)程,它會(huì)獨(dú)立運(yùn)行。
1.2.1 哨兵模式的作用:
監(jiān)控所有服務(wù)器是否正常運(yùn)行:通過發(fā)送命令返回監(jiān)控服務(wù)器的運(yùn)行狀態(tài),處理監(jiān)控主服務(wù)器、從服務(wù)器外,哨兵之間也相互監(jiān)控。
故障切換:當(dāng)哨兵監(jiān)測(cè)到master宕機(jī),會(huì)自動(dòng)將slave切換成master,然后通過發(fā)布訂閱模式通知其他的從服務(wù)器,修改配置文件,讓它們切換master。同時(shí)那臺(tái)有問題的舊主也會(huì)變?yōu)樾轮鞯膹模簿褪钦f當(dāng)舊的主即使恢復(fù)時(shí),并不會(huì)恢復(fù)原來的主身份,而是作為新主的一個(gè)從。
1.2.2 哨兵實(shí)現(xiàn)原理
哨兵在啟動(dòng)進(jìn)程時(shí),會(huì)讀取配置文件的內(nèi)容,通過如下的配置找出需要監(jiān)控的主數(shù)據(jù)庫(kù):
sentinel?monitor?master-name?ip?port?quorum
#master-name是主數(shù)據(jù)庫(kù)的名字
#ip和port?是當(dāng)前主數(shù)據(jù)庫(kù)地址和端口號(hào)
#quorum表示在執(zhí)行故障切換操作前,需要多少哨兵節(jié)點(diǎn)同意。
這里之所以只需要連接主節(jié)點(diǎn),是因?yàn)橥ㄟ^主節(jié)點(diǎn)的info命令,獲取從節(jié)點(diǎn)信息,從而和從節(jié)點(diǎn)也建立連接,同時(shí)也能通過主節(jié)點(diǎn)的info信息知道新增從節(jié)點(diǎn)的信息。
一個(gè)哨兵節(jié)點(diǎn)可以監(jiān)控多個(gè)主節(jié)點(diǎn),但是并不提倡這么做,因?yàn)楫?dāng)哨兵節(jié)點(diǎn)崩潰時(shí),同時(shí)有多個(gè)集群切換會(huì)發(fā)生故障。哨兵啟動(dòng)后,會(huì)與主數(shù)據(jù)庫(kù)建立兩條連接。
-
訂閱主數(shù)據(jù)庫(kù)
_sentinel_:hello
頻道以獲取同樣監(jiān)控該數(shù)據(jù)庫(kù)的哨兵節(jié)點(diǎn)信息 -
定期向主數(shù)據(jù)庫(kù)發(fā)送info命令,獲取主數(shù)據(jù)庫(kù)本身的信息。
跟主數(shù)據(jù)庫(kù)建立連接后會(huì)定時(shí)執(zhí)行以下三個(gè)操作:
(1)每隔10s向master和 slave發(fā)送info命令。作用是獲取當(dāng)前數(shù)據(jù)庫(kù)信息,比如發(fā)現(xiàn)新增從節(jié)點(diǎn)時(shí),會(huì)建立連接,并加入到監(jiān)控列表中,當(dāng)主從數(shù)據(jù)庫(kù)的角色發(fā)生變化進(jìn)行信息更新。
(2)每隔2s向主數(shù)據(jù)里和從數(shù)據(jù)庫(kù)的_sentinel_:hello
頻道發(fā)送自己的信息。作用是將自己的監(jiān)控?cái)?shù)據(jù)和哨兵分享。每個(gè)哨兵會(huì)訂閱數(shù)據(jù)庫(kù)的_sentinel:hello
頻道,當(dāng)其他哨兵收到消息后,會(huì)判斷該哨兵是不是新的哨兵,如果是則將其加入哨兵列表,并建立連接。
(3)每隔1s向所有主從節(jié)點(diǎn)和所有哨兵節(jié)點(diǎn)發(fā)送ping命令,作用是監(jiān)控節(jié)點(diǎn)是否存活。
1.2.3 主觀下線和客觀下線
哨兵節(jié)點(diǎn)發(fā)送ping命令時(shí),當(dāng)超過一定時(shí)間(down-after-millisecond
)后,如果節(jié)點(diǎn)未回復(fù),則哨兵認(rèn)為主觀下線。主觀下線表示當(dāng)前哨兵認(rèn)為該節(jié)點(diǎn)已經(jīng)下面,如果該節(jié)點(diǎn)為主數(shù)據(jù)庫(kù),哨兵會(huì)進(jìn)一步判斷是夠需要對(duì)其進(jìn)行故障切換,這時(shí)候就要發(fā)送命令(SENTINEL is-master-down-by-addr
)詢問其他哨兵節(jié)點(diǎn)是否認(rèn)為該主節(jié)點(diǎn)是主觀下線,當(dāng)達(dá)到指定數(shù)量(quorum)時(shí),哨兵就會(huì)認(rèn)為是客觀下線。
當(dāng)主節(jié)點(diǎn)客觀下線時(shí)就需要進(jìn)行主從切換,主從切換的步驟為:
-
選出領(lǐng)頭哨兵。
-
領(lǐng)頭哨兵所有的slave選出優(yōu)先級(jí)最高的從數(shù)據(jù)庫(kù)。優(yōu)先級(jí)可以通過
slave-priority
選項(xiàng)設(shè)置。 -
如果優(yōu)先級(jí)相同,則從復(fù)制的命令偏移量越大(即復(fù)制同步數(shù)據(jù)越多,數(shù)據(jù)越新),越優(yōu)先。
-
如果以上條件都一樣,則選擇run ID較小的從數(shù)據(jù)庫(kù)。
選出一個(gè)從數(shù)據(jù)庫(kù)后,哨兵發(fā)送slave no one
命令升級(jí)為主數(shù)據(jù)庫(kù),并發(fā)送slaveof命令將其他從節(jié)點(diǎn)的主數(shù)據(jù)庫(kù)設(shè)置為新的主數(shù)據(jù)庫(kù)。
1.2.4 哨兵模式優(yōu)缺點(diǎn)
1.優(yōu)點(diǎn)
-
哨兵模式是基于主從模式的,解決可主從模式中master故障不可以自動(dòng)切換故障的問題。
2.不足-問題
-
是一種中心化的集群實(shí)現(xiàn)方案:始終只有一個(gè)Redis主機(jī)來接收和處理寫請(qǐng)求,寫操作受單機(jī)瓶頸影響。
-
集群里所有節(jié)點(diǎn)保存的都是全量數(shù)據(jù),浪費(fèi)內(nèi)存空間,沒有真正實(shí)現(xiàn)分布式存儲(chǔ)。數(shù)據(jù)量過大時(shí),主從同步嚴(yán)重影響master的性能。
-
Redis主機(jī)宕機(jī)后,哨兵模式正在投票選舉的情況之外,因?yàn)橥镀边x舉結(jié)束之前,誰也不知道主機(jī)和從機(jī)是誰,此時(shí)Redis也會(huì)開啟保護(hù)機(jī)制,禁止寫操作,直到選舉出了新的Redis主機(jī)。
主從模式或哨兵模式每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)都是全量的數(shù)據(jù),數(shù)據(jù)量過大時(shí),就需要對(duì)存儲(chǔ)的數(shù)據(jù)進(jìn)行分片后存儲(chǔ)到多個(gè)redis實(shí)例上。此時(shí)就要用到Redis Sharding技術(shù)。
1.3、各大廠的Redis集群方案
Redis在3.0版本前只支持單實(shí)例模式,雖然Redis的開發(fā)者Antirez早在博客上就提出在Redis 3.0版本中加入集群的功能,但3.0版本等到2015年才發(fā)布正式版。各大企業(yè)等不急了,在3.0版本還沒發(fā)布前為了解決Redis的存儲(chǔ)瓶頸,紛紛推出了各自的Redis集群方案。這些方案的核心思想是把數(shù)據(jù)分片(sharding)存儲(chǔ)在多個(gè)Redis實(shí)例中,每一片就是一個(gè)Redis實(shí)例。
1.3.1 客戶端分片
客戶端分片是把分片的邏輯放在Redis客戶端實(shí)現(xiàn),(比如:jedis已支持Redis Sharding功能,即ShardedJedis),通過Redis客戶端預(yù)先定義好的路由規(guī)則(使用一致性哈希),把對(duì)Key的訪問轉(zhuǎn)發(fā)到不同的Redis實(shí)例中,查詢數(shù)據(jù)時(shí)把返回結(jié)果匯集。這種方案的模式如圖所示。
客戶端分片的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):客戶端sharding技術(shù)使用hash一致性算法分片的好處是所有的邏輯都是可控的,不依賴于第三方分布式中間件。服務(wù)端的Redis實(shí)例彼此獨(dú)立,相互無關(guān)聯(lián),每個(gè)Redis實(shí)例像單服務(wù)器一樣運(yùn)行,非常容易線性擴(kuò)展,系統(tǒng)的靈活性很強(qiáng)。開發(fā)人員清楚怎么實(shí)現(xiàn)分片、路由的規(guī)則,不用擔(dān)心踩坑。
1.一致性哈希算法:
是分布式系統(tǒng)中常用的算法。比如,一個(gè)分布式的存儲(chǔ)系統(tǒng),要將數(shù)據(jù)存儲(chǔ)到具體的節(jié)點(diǎn)上,如果采用普通的hash方法,將數(shù)據(jù)映射到具體的節(jié)點(diǎn)上,如mod(key,d),key是數(shù)據(jù)的key,d是機(jī)器節(jié)點(diǎn)數(shù),如果有一個(gè)機(jī)器加入或退出這個(gè)集群,則所有的數(shù)據(jù)映射都無效了。
一致性哈希算法解決了普通余數(shù)Hash算法伸縮性差的問題,可以保證在上線、下線服務(wù)器的情況下盡量有多的請(qǐng)求命中原來路由到的服務(wù)器。
2.實(shí)現(xiàn)方式:一致性hash算法,比如MURMUR_HASH散列算法、ketamahash算法
比如Jedis的Redis Sharding實(shí)現(xiàn),采用一致性哈希算法(consistent hashing),將key和節(jié)點(diǎn)name同時(shí)hashing,然后進(jìn)行映射匹配,采用的算法是MURMUR_HASH。
采用一致性哈希而不是采用簡(jiǎn)單類似哈希求模映射的主要原因是當(dāng)增加或減少節(jié)點(diǎn)時(shí),不會(huì)產(chǎn)生由于重新匹配造成的rehashing。一致性哈希只影響相鄰節(jié)點(diǎn)key分配,影響量小。
不足:
-
這是一種靜態(tài)的分片方案,需要增加或者減少Redis實(shí)例的數(shù)量,需要手工調(diào)整分片的程序。
-
運(yùn)維成本比較高,集群的數(shù)據(jù)出了任何問題都需要運(yùn)維人員和開發(fā)人員一起合作,減緩了解決問題的速度,增加了跨部門溝通的成本。
-
在不同的客戶端程序中,維護(hù)相同的路由分片邏輯成本巨大。比如:java項(xiàng)目、PHP項(xiàng)目里共用一套R(shí)edis集群,路由分片邏輯分別需要寫兩套一樣的邏輯,以后維護(hù)也是兩套。
客戶端分片有一個(gè)最大的問題就是,服務(wù)端Redis實(shí)例群拓?fù)浣Y(jié)構(gòu)有變化時(shí),每個(gè)客戶端都需要更新調(diào)整。如果能把客戶端分片模塊單獨(dú)拎出來,形成一個(gè)單獨(dú)的模塊(中間件),作為客戶端 和 服務(wù)端連接的橋梁就能解決這個(gè)問題了,此時(shí)代理分片就出現(xiàn)了。
1.3.2 代理分片
redis代理分片用得最多的就是Twemproxy,由Twitter開源的Redis代理,其基本原理是:通過中間件的形式,Redis客戶端把請(qǐng)求發(fā)送到Twemproxy,Twemproxy根據(jù)路由規(guī)則發(fā)送到正確的Redis實(shí)例,最后Twemproxy把結(jié)果匯集返回給客戶端。
Twemproxy通過引入一個(gè)代理層,將多個(gè)Redis實(shí)例進(jìn)行統(tǒng)一管理,使Redis客戶端只需要在Twemproxy上進(jìn)行操作,而不需要關(guān)心后面有多少個(gè)Redis實(shí)例,從而實(shí)現(xiàn)了Redis集群。
Twemproxy的優(yōu)點(diǎn):
-
客戶端像連接Redis實(shí)例一樣連接Twemproxy,不需要改任何的代碼邏輯。
-
支持無效Redis實(shí)例的自動(dòng)刪除。
-
Twemproxy與Redis實(shí)例保持連接,減少了客戶端與Redis實(shí)例的連接數(shù)。
Twemproxy的不足:
-
由于Redis客戶端的每個(gè)請(qǐng)求都經(jīng)過Twemproxy代理才能到達(dá)Redis服務(wù)器,這個(gè)過程中會(huì)產(chǎn)生性能損失。
-
沒有友好的監(jiān)控管理后臺(tái)界面,不利于運(yùn)維監(jiān)控。
-
Twemproxy最大的痛點(diǎn)在于,無法平滑地?cái)U(kuò)容/縮容。對(duì)于運(yùn)維人員來說,當(dāng)因?yàn)闃I(yè)務(wù)需要增加Redis實(shí)例時(shí)工作量非常大。
Twemproxy作為最被廣泛使用、最久經(jīng)考驗(yàn)、穩(wěn)定性最高的Redis代理,在業(yè)界被廣泛使用。
1.3.3 Codis
Twemproxy不能平滑增加Redis實(shí)例的問題帶來了很大的不便,于是豌豆莢自主研發(fā)了Codis,一個(gè)支持平滑增加Redis實(shí)例的Redis代理軟件,其基于Go和C語言開發(fā),并于2014年11月在GitHub上開源。
在Codis的架構(gòu)圖中,Codis引入了Redis Server Group
,其通過指定一個(gè)主CodisRedis和一個(gè)或多個(gè)從CodisRedis,實(shí)現(xiàn)了Redis集群的高可用。當(dāng)一個(gè)主CodisRedis掛掉時(shí),Codis不會(huì)自動(dòng)把一個(gè)從CodisRedis提升為主CodisRedis,這涉及數(shù)據(jù)的一致性問題(Redis本身的數(shù)據(jù)同步是采用主從異步復(fù)制,當(dāng)數(shù)據(jù)在主CodisRedis寫入成功時(shí),從CodisRedis是否已讀入這個(gè)數(shù)據(jù)是沒法保證的),需要管理員在管理界面上手動(dòng)把從CodisRedis提升為主CodisRedis。
如果手動(dòng)處理覺得麻煩,豌豆莢也提供了一個(gè)工具Codis-ha
,這個(gè)工具會(huì)在檢測(cè)到主CodisRedis掛掉的時(shí)候?qū)⑵湎戮€并提升一個(gè)從CodisRedis為主CodisRedis。
Codis中采用預(yù)分片的形式,啟動(dòng)的時(shí)候就創(chuàng)建了1024個(gè)slot,1個(gè)slot相當(dāng)于1個(gè)箱子,每個(gè)箱子有固定的編號(hào),范圍是1~1024。slot這個(gè)箱子用作存放Key,至于Key存放到哪個(gè)箱子,可以通過算法“crc32(key)%1024
”獲得一個(gè)數(shù)字,這個(gè)數(shù)字的范圍一定是1~1024之間,Key就放到這個(gè)數(shù)字對(duì)應(yīng)的slot。
例如,如果某個(gè)Key通過算法“crc32(key)%1024
”得到的數(shù)字是5,就放到編碼為5的slot(箱子)。1個(gè)slot只能放1個(gè)Redis Server Group
,不能把1個(gè)slot放到多個(gè)Redis Server Group
中。1個(gè)Redis Server Group
最少可以存放1個(gè)slot,最大可以存放1024個(gè)slot。因此,Codis中最多可以指定1024個(gè)Redis Server Group
。
Codis最大的優(yōu)勢(shì)在于支持平滑增加(減少)Redis Server Group
(Redis實(shí)例),能安全、透明地遷移數(shù)據(jù),這也是Codis 有別于Twemproxy等靜態(tài)分布式 Redis 解決方案的地方。Codis增加了Redis Server Group
后,就牽涉到slot的遷移問題。
例如,系統(tǒng)有兩個(gè)Redis Server Group
,Redis Server Group
和slot的對(duì)應(yīng)關(guān)系如下。
當(dāng)增加了一個(gè)Redis Server Group,slot就要重新分配了。Codis分配slot有兩種方法:
第一種:通過Codis管理工具Codisconfig手動(dòng)重新分配,指定每個(gè)Redis Server Group所對(duì)應(yīng)的slot的范圍,例如:可以指定Redis Server Group和slot的新的對(duì)應(yīng)關(guān)系如下。
第二種:通過Codis管理工具Codisconfig的rebalance功能,會(huì)自動(dòng)根據(jù)每個(gè)Redis Server Group的內(nèi)存對(duì)slot進(jìn)行遷移,以實(shí)現(xiàn)數(shù)據(jù)的均衡。
1.4、Redis Cluster
Redis 的哨兵模式雖然已經(jīng)可以實(shí)現(xiàn)高可用,讀寫分離 ,但是存在幾個(gè)方面的不足:
-
哨兵模式下每臺(tái) Redis 服務(wù)器都存儲(chǔ)相同的數(shù)據(jù),很浪費(fèi)內(nèi)存空間;數(shù)據(jù)量太大,主從同步時(shí)嚴(yán)重影響了master性能。
-
哨兵模式是中心化的集群實(shí)現(xiàn)方案,每個(gè)從機(jī)和主機(jī)的耦合度很高,master宕機(jī)到salve選舉master恢復(fù)期間服務(wù)不可用。
-
哨兵模式始終只有一個(gè)Redis主機(jī)來接收和處理寫請(qǐng)求,寫操作還是受單機(jī)瓶頸影響,沒有實(shí)現(xiàn)真正的分布式架構(gòu)。
redis在3.0上加入了 Cluster 集群模式,實(shí)現(xiàn)了 Redis 的分布式存儲(chǔ),也就是說每臺(tái) Redis 節(jié)點(diǎn)上存儲(chǔ)不同的數(shù)據(jù)。cluster模式為了解決單機(jī)Redis容量有限的問題,將數(shù)據(jù)按一定的規(guī)則分配到多臺(tái)機(jī)器,內(nèi)存/QPS不受限于單機(jī),可受益于分布式集群高擴(kuò)展性。
Redis Cluster是一種服務(wù)器Sharding技術(shù)(分片和路由都是在服務(wù)端實(shí)現(xiàn)),采用多主多從,每一個(gè)分區(qū)都是由一個(gè)Redis主機(jī)和多個(gè)從機(jī)組成,片區(qū)和片區(qū)之間是相互平行的。Redis Cluster集群采用了P2P的模式,完全去中心化。
如上圖,官方推薦,集群部署至少要 3 臺(tái)以上的master節(jié)點(diǎn),最好使用 3 主 3 從六個(gè)節(jié)點(diǎn)的模式。Redis Cluster集群具有如下幾個(gè)特點(diǎn):
-
集群完全去中心化,采用多主多從;所有的redis節(jié)點(diǎn)彼此互聯(lián)(PING-PONG機(jī)制),內(nèi)部使用二進(jìn)制協(xié)議優(yōu)化傳輸速度和帶寬。
-
客戶端與 Redis 節(jié)點(diǎn)直連,不需要中間代理層??蛻舳瞬恍枰B接集群所有節(jié)點(diǎn),連接集群中任何一個(gè)可用節(jié)點(diǎn)即可。
-
每一個(gè)分區(qū)都是由一個(gè)Redis主機(jī)和多個(gè)從機(jī)組成,分片和分片之間是相互平行的。
-
每一個(gè)master節(jié)點(diǎn)負(fù)責(zé)維護(hù)一部分槽,以及槽所映射的鍵值數(shù)據(jù);集群中每個(gè)節(jié)點(diǎn)都有全量的槽信息,通過槽每個(gè)node都知道具體數(shù)據(jù)存儲(chǔ)到哪個(gè)node上。
redis cluster主要是針對(duì)海量數(shù)據(jù)+高并發(fā)+高可用的場(chǎng)景,海量數(shù)據(jù),如果你的數(shù)據(jù)量很大,那么建議就用redis cluster,數(shù)據(jù)量不是很大時(shí),使用sentinel就夠了。redis cluster的性能和高可用性均優(yōu)于哨兵模式。
Redis Cluster采用虛擬哈希槽分區(qū)而非一致性hash算法,預(yù)先分配一些卡槽,所有的鍵根據(jù)哈希函數(shù)映射到這些槽內(nèi),每一個(gè)分區(qū)內(nèi)的master節(jié)點(diǎn)負(fù)責(zé)維護(hù)一部分槽以及槽所映射的鍵值數(shù)據(jù)。
二.RDB持久化
2.1 RDB全量寫入
2.1.1 rdb原理
RDB
持久化是把當(dāng)前進(jìn)程數(shù)據(jù)生成快照保存到硬盤的過程,觸發(fā)RDB
持久化過程分為手動(dòng)觸發(fā)和自動(dòng)觸發(fā)
過程:
- 1)執(zhí)行bgsave命令,Redis父進(jìn)程判斷當(dāng)前是否存在正在執(zhí)行的子進(jìn)程,如RDB/AOF子進(jìn)程,如果存在bgsave命令直接返回。
- 2)父進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程,fork操作過程中父進(jìn)程會(huì)阻塞,通過info stats命令查看latest_fork_usec選項(xiàng),可以獲取最近一個(gè)fork操作的耗時(shí),單位為微秒。
- 3)父進(jìn)程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父進(jìn)程,可以繼續(xù)響應(yīng)其他命令。
- 4)子進(jìn)程創(chuàng)建RDB文件,根據(jù)父進(jìn)程內(nèi)存生成臨時(shí)快照文件,完成后對(duì)原有文件進(jìn)行原子替換 執(zhí)行l(wèi)astsave命令可以獲取最后一次生成RDB的時(shí)間,對(duì)應(yīng)info統(tǒng)計(jì)的rdb_last_save_time選項(xiàng)。
- 5)進(jìn)程發(fā)送信號(hào)給父進(jìn)程表示完成,父進(jìn)程更新統(tǒng)計(jì)信息,具體見info Persistence下的rdb_*相關(guān)選項(xiàng)。
2.1.2?rdb模式
SAVE 阻塞式的RDB持久化,當(dāng)執(zhí)行這個(gè)命令時(shí)間時(shí)rdis的主進(jìn)程把內(nèi)存里的數(shù)據(jù)庫(kù)狀態(tài)寫入到rdb文件中,直到該文件創(chuàng)建完畢的這段時(shí)間內(nèi)redis講不能處理任何命令請(qǐng)求
BGSAVE 非阻塞式的持久化,它會(huì)創(chuàng)建一個(gè)子進(jìn)程,專門去把內(nèi)存中的數(shù)據(jù)庫(kù)狀態(tài)寫入RDB文件,同時(shí)主進(jìn)程還可以處理來自客戶端的請(qǐng)求命令,但子進(jìn)程基本是復(fù)制父進(jìn)程,這等于兩個(gè)相同大小的redis進(jìn)程在系統(tǒng)上運(yùn)行,會(huì)造成內(nèi)存使用率的大幅增加。
2.1.3?rdb觸發(fā)情況
1.手動(dòng)執(zhí)行bgsave或save命令 2.根據(jù)配置文件的save選項(xiàng)自動(dòng)觸發(fā) 3.主從結(jié)構(gòu)時(shí),從節(jié)點(diǎn)執(zhí)行全量復(fù)制操作,主節(jié)點(diǎn)自動(dòng)執(zhí)行,將生成的RDB文件發(fā)送給從 4.執(zhí)行debug reload命令重新加載Redis時(shí) 5.默認(rèn)情況下執(zhí)行shutdown命令關(guān)閉redis時(shí),如果沒有開啟AOF持久化功能則自動(dòng)執(zhí)行
2.1.4?rdb優(yōu)勢(shì)和劣勢(shì)
優(yōu)勢(shì):
- 一旦采用該方式,那么你的整個(gè)Redis數(shù)據(jù)庫(kù)將只包含一個(gè)文件,這對(duì)可以定時(shí)每天可以備份出一個(gè)整個(gè)的數(shù)據(jù)文件。
- 對(duì)于災(zāi)難恢復(fù)而言,RDB是非常不錯(cuò)的選擇。因?yàn)槲覀兛梢苑浅]p松的將一個(gè)單獨(dú)的文件壓縮后再轉(zhuǎn)移到其它存儲(chǔ)介質(zhì)上。
- 相比于AOF機(jī)制,如果數(shù)據(jù)集很大,RDB的啟動(dòng)效率會(huì)更高。
劣勢(shì):
- 由于RDB是通過fork子進(jìn)程來協(xié)助完成數(shù)據(jù)持久化工作的,因此,如果當(dāng)數(shù)據(jù)集較大時(shí),可能會(huì)導(dǎo)致整個(gè)服務(wù)器停止服務(wù)幾百毫秒,甚至是1秒鐘。
- RDB文件使用特定二進(jìn)制格式保存,Redis版本演進(jìn)過程中有多個(gè)格式的RDB版本,存在老版本Redis服務(wù)無法兼容新版RDB格式的問題。
2.1.5?rdb文件配置
redis.conf文件
#注釋所有save行則停止rdb持久化
#900秒(15分鐘)內(nèi)至少1個(gè)key值改變(則進(jìn)行數(shù)據(jù)庫(kù)保存--持久化)
save 900 1
#300秒(5分鐘)內(nèi)至少10個(gè)key值改變(則進(jìn)行數(shù)據(jù)庫(kù)保存--持久化)
save 300 10
#60秒(1分鐘)內(nèi)至少10000個(gè)key值改變(則進(jìn)行數(shù)據(jù)庫(kù)保存--持久化)
save 60 10000
#當(dāng)RDB持久化出現(xiàn)錯(cuò)誤后,再寫入數(shù)據(jù)會(huì)報(bào)錯(cuò),用于提示用戶出問題了。
#yes是開啟,no是關(guān)閉,默認(rèn)開啟
stop-writes-on-bgsave-error yes
#是否壓縮rdb文件,rdb文件壓縮使用LZF壓縮算法,壓縮會(huì)消耗一些cpu,不壓縮文件會(huì)很大
#yes開啟,no關(guān)閉,默認(rèn)開啟
rdbcompression yes
#使用CRC64算法來進(jìn)行數(shù)據(jù)校驗(yàn),防止RDB是錯(cuò)誤的,但是這樣做會(huì)增加大約10%的性能消耗
#yes開啟,no關(guān)閉,默認(rèn)開啟
rdbchecksum yes
復(fù)制
2.1.6?rdb命令配置
阻塞當(dāng)前Redis服務(wù)器 直到RDB過程完成為止,對(duì)于內(nèi)存比較大的實(shí)例會(huì)造成長(zhǎng)時(shí)間阻塞,線上環(huán)境不建議使用。 save
Redis進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程,RDB持久化過程由子進(jìn)程負(fù)責(zé),完成后自動(dòng)結(jié)束。阻塞只發(fā)生在fork階段,一般時(shí)間很短。 bgsave
查看latest_fork_usec選項(xiàng),可以獲取最近一個(gè)fork操作的耗時(shí),單位為微秒。 info stats
2.1.7?rdb數(shù)據(jù)恢復(fù)
1.將RDB備份放到配置文件指定的數(shù)據(jù)目錄下,啟動(dòng)redis將會(huì)自動(dòng)恢復(fù)。加載期間將會(huì)阻塞,無法進(jìn)行其它操作。
2.上述方法不行,或者恢復(fù)的集群,可以使用redis-migrate-tool工具進(jìn)行恢復(fù)。
2.2 AOF持久化:增量寫入
2.2.1aof原理
以獨(dú)立日志的方式記錄每次寫命令,重啟時(shí)再重新執(zhí)行AOF文件中的命令達(dá)到恢復(fù)數(shù)據(jù)的目的。AOF的主要作用是解決了數(shù)據(jù)持久化的實(shí)時(shí)性,目前已經(jīng)是Redis持久化的主流方式。
寫入的數(shù)據(jù)具有可讀性,同步時(shí)先寫入緩沖區(qū),再放入硬盤。如果直接寫入硬盤,性能將取決于磁盤負(fù)載,并且放到緩沖區(qū),可以提供各種同步策略。
過程:
- 1)所有的寫入命令會(huì)追加到aof_buf(緩沖區(qū))中。
- 2)AOF緩沖區(qū)根據(jù)對(duì)應(yīng)的策略向硬盤做同步操作。
- 3)隨著AOF文件越來越大,需要定期對(duì)AOF文件進(jìn)行重寫,達(dá)到壓縮的目的。
- 4)當(dāng)Redis服務(wù)器重啟時(shí),可以加載AOF文件進(jìn)行數(shù)據(jù)恢復(fù)。
2.2.2 aof觸發(fā)情況
1.根據(jù)配置文件自動(dòng)觸發(fā)
2.2.3 aof優(yōu)勢(shì)和劣勢(shì)
優(yōu)勢(shì):
- 該機(jī)制可以帶來更高的數(shù)據(jù)安全性,即數(shù)據(jù)持久性。根據(jù)策略不同,從而對(duì)數(shù)據(jù)安全性不同,可以在性能和安全區(qū)選擇一個(gè)。
- 由于該機(jī)制對(duì)日志文件的寫入操作采用的是append模式,因此在寫入過程中即使出現(xiàn)宕機(jī)現(xiàn)象,也不會(huì)破壞日志文件中已經(jīng)存在的內(nèi)容。
- 如果日志過大,將自動(dòng)啟用rewrite機(jī)制。以append模式不斷的將修改數(shù)據(jù)寫入到老的磁盤文件中,同時(shí)還會(huì)創(chuàng)建一個(gè)新的文件用于記錄此期間有哪些修改命令被執(zhí)行,保證安全性。
- AOF包含一個(gè)格式清晰、易于理解的日志文件用于記錄所有的修改操作。事實(shí)上,我們也可以通過該文件完成數(shù)據(jù)的重建。
劣勢(shì):
- 對(duì)于相同數(shù)量的數(shù)據(jù)集而言,AOF文件通常要大于RDB文件。RDB 在恢復(fù)大數(shù)據(jù)集時(shí)的速度比 AOF 的恢復(fù)速度要快。
- 根據(jù)同步策略的不同,AOF在運(yùn)行效率上往往會(huì)慢于RDB??傊?,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。
2.2.4 aof文件配置
在Redis的配置文件中存在三種同步方式,它們分別是:
#是否開啟aof持久化。默認(rèn)no,要打開
appendonly yes
#位置
appendfilename "appendonly.aof"
#每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫入AOF文件
#命令寫入aof_buf后調(diào)用系統(tǒng)fsync操作同步AOF文件,fsync完成后線程返回
appendfsync always
#每秒鐘同步一次,該策略為AOF的缺省策略
#命令寫入aof_buf后調(diào)用系統(tǒng)write操作,write完成后線程返回。fsync同步文件操作由專門線程每秒調(diào)用一次
#這個(gè)模式兼顧了效率的同時(shí)也保證了數(shù)據(jù)的完整性,即使在服務(wù)器宕機(jī)也只會(huì)丟失一秒內(nèi)對(duì)redis數(shù)據(jù)庫(kù)做的修改
appendfsync everysec
#不加入緩沖區(qū),直接寫到硬盤,速度最快,不安全
#命令寫入aof_buf后調(diào)用系統(tǒng)write操作,不對(duì)aof文件做fsync同步,同步硬盤操作由操作系統(tǒng)負(fù)責(zé),通常同步周期最長(zhǎng)30秒
#這種模式下效率是最快的,但對(duì)數(shù)據(jù)來說也是最不安全的,如果redis里的數(shù)據(jù)都是從后臺(tái)數(shù)據(jù)庫(kù)如mysql中取出來的,屬于隨時(shí)可以找回或者不重要的數(shù)據(jù),那么可以考慮設(shè)置成這種模式。
appendfsync no
復(fù)制
2.2.5 aof命令配置
aof文件重寫手動(dòng)觸發(fā) bgrewriteaof
aof文件重寫自動(dòng)觸發(fā),配置文件
#新的aof文件大小是上次的aof文件的大小2倍(100)時(shí),進(jìn)行重寫
auto-aof-rewrite-percentage 100
#表示運(yùn)行AOF重寫時(shí)文件最小體積, 默認(rèn)為64MB
auto-aof-rewrite-min-size 64mb
復(fù)制
2.2.6 aof數(shù)據(jù)恢復(fù)
- 將AOF備份放到配置文件指定的數(shù)據(jù)目錄下,啟動(dòng)redis將會(huì)自動(dòng)恢復(fù)。加載期間將會(huì)阻塞,無法進(jìn)行其它操作。
- 上述方法不行,或者恢復(fù)的集群,可以使用redis-migrate-tool工具進(jìn)行恢復(fù)。
- 可以使用pipline方式批量硬寫入,但效率會(huì)低
2.3.RDB&AOF對(duì)比
二者選擇的標(biāo)準(zhǔn),就是看系統(tǒng)是愿意犧牲一些性能,換取更高的緩存一致性(aof),還是愿意寫操作頻繁的時(shí)候,不啟用備份來換取更高的性能,待手動(dòng)運(yùn)行save的時(shí)候,再做備份(rdb)。
啟動(dòng)加載流程:
- AOF持久化開啟且存在AOF文件時(shí), 優(yōu)先加載AOF文件
- AOF關(guān)閉或者AOF文件不存在時(shí), 加載RDB文件
- 加載AOF/RDB文件成功后, Redis啟動(dòng)成功
- AOF/RDB文件存在錯(cuò)誤時(shí), Redis啟動(dòng)失敗并打印錯(cuò)誤信息
三、Redis高階
3.1 Redis高階之緩存擊穿
3.1.1 緩存擊穿定義
緩存擊穿
,是指緩存中沒有但數(shù)據(jù)庫(kù)中有的數(shù)據(jù)
,并且某一個(gè)key非常熱點(diǎn)
,在不停的扛著大并發(fā),大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問,當(dāng)這個(gè)key在失效的瞬間(一般是緩存時(shí)間到期),持續(xù)的大并發(fā)就穿破緩存,直接請(qǐng)求數(shù)據(jù)庫(kù),就像在一個(gè)屏障上鑿開了一個(gè)洞。
緩存擊穿看著有點(diǎn)像,其實(shí)它兩區(qū)別是,緩存雪奔是指數(shù)據(jù)庫(kù)壓力過大甚至down機(jī),緩存擊穿只是大量并發(fā)請(qǐng)求到了DB數(shù)據(jù)庫(kù)層面??梢哉J(rèn)為擊穿是緩存雪奔的一個(gè)子集吧。有些文章認(rèn)為它倆區(qū)別,是區(qū)別在于擊穿針對(duì)某一熱點(diǎn)key緩存,雪奔則是很多key。
3.1.2?緩存擊穿產(chǎn)生原因
可以看成緩存雪崩的一個(gè)特殊子集。
比如xxx塌房哩、xxx商品活動(dòng),這時(shí)候大量用戶都在訪問該熱點(diǎn)事件,但是可能優(yōu)于某種原因,redis的這個(gè)熱點(diǎn)key過期了,那么這時(shí)候大量高并發(fā)對(duì)于該key的請(qǐng)求就得不到redis的響應(yīng),那么就會(huì)將請(qǐng)求直接打在DB服務(wù)器上,導(dǎo)致整個(gè)DB癱瘓。
3.1.3?緩存擊穿解決方案
- 使用互斥鎖方案。緩存失效時(shí),不是立即去加載db數(shù)據(jù),而是先使用某些帶成功返回的原子操作命令,如(Redis的setnx)去操作,成功的時(shí)候,再去加載db數(shù)據(jù)庫(kù)數(shù)據(jù)和設(shè)置緩存。否則就去重試獲取緩存。
- ?“永不過期”,是指沒有設(shè)置過期時(shí)間,但是熱點(diǎn)數(shù)據(jù)快要過期時(shí),異步線程去更新和設(shè)置過期時(shí)間。
3.1.4?緩存擊穿解決方案之互斥鎖詳解
業(yè)界比較常用的做法,是使用mutex。簡(jiǎn)單地來說,就是在緩存失效的時(shí)候(判斷拿出來的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者M(jìn)emcache的ADD)去set一個(gè)mutex key,當(dāng)操作返回成功時(shí),再進(jìn)行l(wèi)oad db的操作并回設(shè)緩存;否則,就重試整個(gè)get緩存的方法。
SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時(shí)候才設(shè)置,可以利用它來實(shí)現(xiàn)鎖的效果。
public String get(key) {
String value = redis.get(key);
if (value == null) { //代表緩存值過期
//設(shè)置3min的超時(shí),防止del操作失敗的時(shí)候,下次緩存過期一直不能load db
if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表設(shè)置成功
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
} else { //這個(gè)時(shí)候代表同時(shí)候的其他線程已經(jīng)load db并回設(shè)到緩存了,這時(shí)候重試獲取緩存值即可
sleep(50);
get(key); //重試
}
} else {
return value;
}
}
3.2 Redis高階之緩存穿透
3.2.1 緩存穿透定義
緩存穿透
是指查詢一個(gè)數(shù)據(jù)庫(kù)一定不存在的數(shù)據(jù)
。正常的使用緩存流程大致是,數(shù)據(jù)查詢先進(jìn)行緩存查詢,如果key不存在或者key已經(jīng)過期,再對(duì)數(shù)據(jù)庫(kù)進(jìn)行查詢,并把查詢到的對(duì)象,放進(jìn)緩存。如果數(shù)據(jù)庫(kù)查詢對(duì)象為空,則不放進(jìn)緩存。
這里需要注意緩存擊穿
的區(qū)別,緩存擊穿,緩存擊穿是指緩存中沒有但數(shù)據(jù)庫(kù)中有的數(shù)據(jù)
,并且某一個(gè)key非常熱點(diǎn)
,在不停的扛著大并發(fā),大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問,當(dāng)這個(gè)key在失效的瞬間(一般是緩存時(shí)間到期),持續(xù)的大并發(fā)就穿破緩存,直接請(qǐng)求數(shù)據(jù)庫(kù),就像在一個(gè)屏障上鑿開了一個(gè)洞。
通俗點(diǎn)說,讀請(qǐng)求訪問時(shí),緩存和數(shù)據(jù)庫(kù)都沒有某個(gè)值,這樣就會(huì)導(dǎo)致每次對(duì)這個(gè)值的查詢請(qǐng)求都會(huì)穿透到數(shù)據(jù)庫(kù),這就是緩存穿透。
3.2.2?緩存穿透產(chǎn)生的原因
- 業(yè)務(wù)不合理的設(shè)計(jì),比如大多數(shù)用戶都沒開守護(hù),但是你的每個(gè)請(qǐng)求都去緩存,查詢某個(gè)userid查詢有沒有守護(hù)。
- 業(yè)務(wù)/運(yùn)維/開發(fā)失誤的操作,比如緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)都被誤刪除了。
- 黑客非法請(qǐng)求攻擊,比如黑客故意捏造大量非法請(qǐng)求,以讀取不存在的業(yè)務(wù)數(shù)據(jù)。
3.2.3?緩存穿透的三種解決方案
- 如果是非法請(qǐng)求,我們?cè)贏PI入口,對(duì)參數(shù)進(jìn)行校驗(yàn),過濾非法值。
- 如果查詢數(shù)據(jù)庫(kù)為空,我們可以給緩存設(shè)置個(gè)空值,或者默認(rèn)值。但是如有有寫請(qǐng)求進(jìn)來的話,需要更新緩存哈,以保證緩存一致性,同時(shí),最后給緩存設(shè)置適當(dāng)?shù)倪^期時(shí)間。(業(yè)務(wù)上比較常用,簡(jiǎn)單有效)
- 使用布隆過濾器快速判斷數(shù)據(jù)是否存在。即一個(gè)查詢請(qǐng)求過來時(shí),先通過布隆過濾器判斷值是否存在,存在才繼續(xù)往下查。
布隆過濾器原理:它由初始值為0的位圖數(shù)組和N個(gè)哈希函數(shù)組成。一個(gè)對(duì)一個(gè)key進(jìn)行N個(gè)hash算法獲取N個(gè)值,在比特?cái)?shù)組中將這N個(gè)值散列后設(shè)定為1,然后查的時(shí)候如果特定的這幾個(gè)位置都為1,那么布隆過濾器判斷該key存在。
3.2.4?緩存穿透解決方案之布隆過濾器詳解
布隆過濾器
是一個(gè)bit向量或者bit,如果我們要映射一個(gè)值到布隆過濾器中,我們使用多個(gè)不同的哈希函數(shù)生成多個(gè)哈希值,并將每個(gè)生成的哈希值指向的bit位設(shè)置為1,如下baidu一詞設(shè)置了三個(gè)位置為1。
原理:對(duì)一個(gè)key進(jìn)行k個(gè)hash算法獲取k個(gè)值,在比特?cái)?shù)組中將這k個(gè)值散列后設(shè)定為1,然后查的時(shí)候如果特定的這幾個(gè)位置都為1,那么布隆過濾器判斷該key存在。
“tencent”一詞,對(duì)應(yīng)的情況
可以看到,不同的詞對(duì)應(yīng)的bit位置可能相同,當(dāng)詞很多的情況時(shí),可能大部分bit位置都是1,這時(shí)查詢taobao可能對(duì)應(yīng)的位置都為1,只能說明taobao一詞可能存在,不是一定存在的,這時(shí)1就被覆蓋了,這就是布隆過濾器的誤判。如果它說不存在那肯定不存在,如果它說存在,那數(shù)據(jù)有可能實(shí)際不存在。
Redis的bitmap只支持2^32大小,對(duì)應(yīng)到內(nèi)存也就是512MB,誤判率萬分之一,可以放下2億左右的數(shù)據(jù),性能高,空間占用率及小,省去了大量無效的數(shù)據(jù)庫(kù)連接。
因此我們可以通過布隆過濾器,將Redis緩存穿透控制在一個(gè)可容范圍內(nèi)。
使用布隆過濾器:
導(dǎo)入依賴
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
代碼:
public class Test {
private static int size = 1000000;//預(yù)計(jì)要插入多少數(shù)據(jù)
private static double fpp = 0.01;//期望的誤判率
private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);
public static void main(String[] args) {
//插入數(shù)據(jù)
for (int i = 0; i < 1000000; i++) {
bloomFilter.put(i);
}
int count = 0;
for (int i = 1000000; i < 2000000; i++) {
if (bloomFilter.mightContain(i)) {
count++;
System.out.println(i + "誤判了");
}
}
System.out.println("總共的誤判數(shù):" + count);
}
}
應(yīng)用:
@Cacheable(value="key1")
public String get(String key) {
String value = redis.get(key);
// redis中不存在該緩存
if (value == null) {
//布隆過濾器也沒有,直接返回
if(!bloomfilter.mightContain(key)){
return null;
}else{
//布隆過濾器中能查到,不代表一定有,查出來放入redis,同樣也可以避免緩存穿透
value = db.get(key);
redis.set(key, value);
}
}
return value;
}
(2)、緩存空對(duì)象
當(dāng)存儲(chǔ)層不命中后,即使返回的空對(duì)象也將其緩存起來,同時(shí)會(huì)設(shè)置一個(gè)過期時(shí)間,之后再訪問這個(gè)數(shù)據(jù)將會(huì)從緩存中獲取,保護(hù)了后端數(shù)據(jù)源。
但是這種方法會(huì)存在兩個(gè)問題:
● 如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲(chǔ)更多的鍵
,因?yàn)檫@當(dāng)中可能會(huì)有很多的空值的鍵;
● 即使對(duì)空值設(shè)置了過期時(shí)間,還是會(huì)存在緩存層和存儲(chǔ)層的數(shù)據(jù)會(huì)有一段時(shí)間窗口的不一致,這對(duì)于需要保持一致性的業(yè)務(wù)會(huì)有影響
3.3 Redis高階之緩存雪崩
3.3.1?緩存雪奔定義
?指緩存中數(shù)據(jù)大批量到過期時(shí)間,而查詢數(shù)據(jù)量巨大,請(qǐng)求都直接訪問數(shù)據(jù)庫(kù),引起數(shù)據(jù)庫(kù)壓力過大甚至down機(jī)。
- 緩存雪奔一般是由于大量數(shù)據(jù)同時(shí)過期造成的,對(duì)于這個(gè)原因,可通過均勻設(shè)置過期時(shí)間解決,即讓過期時(shí)間相對(duì)離散一點(diǎn)。如采用一個(gè)較大固定值+一個(gè)較小的隨機(jī)值,5小時(shí)+0到1800秒醬紫。
- Redis 故障宕機(jī)也可能引起緩存雪奔。這就需要構(gòu)造Redis高可用集群啦。
3.3.2?產(chǎn)生雪崩的原因
假如馬上就要到雙十一零點(diǎn),很快就會(huì)迎來一波搶購(gòu),這波商品時(shí)間比較集中的放入了緩存,假設(shè)緩存一個(gè)小時(shí)。那么到了凌晨一點(diǎn)鐘的時(shí)候,這批商品的緩存就都過期了。而對(duì)這批商品的訪問查詢,都落到了數(shù)據(jù)庫(kù)上,對(duì)于數(shù)據(jù)庫(kù)而言,就會(huì)產(chǎn)生周期性的壓力波峰。
3.3.3 緩存雪崩的四種解決方案
- 采取不同分類商品,緩存不同周期。在同一分類中的商品,加上一個(gè)隨機(jī)因子。這樣能盡可能分散緩存過期時(shí)間,而且,熱門類目的商品緩存時(shí)間長(zhǎng)一些,冷門類目的商品緩存時(shí)間短一些,也能節(jié)省緩存服務(wù)的資源。
- 如果緩存數(shù)據(jù)庫(kù)是分布式部署,將 熱點(diǎn)數(shù)據(jù)均勻分布在不同的緩存數(shù)據(jù)庫(kù)中。
- 設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期。
- 使用加鎖限流的方式。
3.3.4 緩存雪崩解決方案之加鎖限流詳解
Redis常見面試問題
Redis有哪些特性?
- 性能高, 讀的速度是100000次/s,寫的速度是80000次/s;
- 數(shù)據(jù)持久化,支持RDB 、AOF;
- 支持事務(wù)。通過MULTI和EXEC指令包起來;
- 多種數(shù)據(jù)結(jié)構(gòu)類型;
- 主從復(fù)制;
- 其他特性:發(fā)布/訂閱、通知、key過期等;
Redis為什么這么快?
- 完全基于內(nèi)存,沒有磁盤IO上的開銷,異步持久化除外
- 單線程,避免多個(gè)線程切換的性能損耗
- 非阻塞的IO多路復(fù)用機(jī)制
- 底層的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)優(yōu)化,使用原生的數(shù)據(jù)結(jié)構(gòu)提升性能。
Redis底層的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)有哪些?
- 字符串。沒有采用C語言的傳統(tǒng)字符串,而是自己實(shí)現(xiàn)的一個(gè)簡(jiǎn)單動(dòng)態(tài)字符串SDS的抽象類型,并保存了?度
- 信息。
- 鏈表(linkedlist)。雙向無環(huán)鏈表結(jié)構(gòu),每個(gè)鏈表的節(jié)點(diǎn)由一個(gè)listNode結(jié)構(gòu)來表示,每個(gè)節(jié)點(diǎn)都有前置和
- 后置節(jié)點(diǎn)的指針
- 字典(hashtable)。保存鍵值對(duì)的抽象數(shù)據(jù)結(jié)構(gòu),底層使用hash表,每個(gè)字典帶有兩個(gè)hash表,供平時(shí)使
- 用和rehash時(shí)使用。
- 跳躍表(skiplist)。跳躍表是有序集合的底層實(shí)現(xiàn)之一。redis跳躍表由zskiplist和zskiplistNode組成,
- zskiplist用于保存跳躍表 信息(表頭、表尾節(jié)點(diǎn)、?度等),zskiplistNode用于表示表跳躍節(jié)點(diǎn),每個(gè)跳躍表的
- 層高都是1- 32的隨機(jī)數(shù),在同一個(gè)跳躍表中,多個(gè)節(jié)點(diǎn)可以包含相同的分值,但是每個(gè)節(jié)點(diǎn)的成員對(duì)象必須
- 是唯一的,節(jié)點(diǎn)按照分值大小排序,如果分值相同,則按照成員對(duì)象的大小排序。
- 整數(shù)集合(intset)。用于保存整數(shù)值的集合抽象數(shù)據(jù)結(jié)構(gòu),不會(huì)出現(xiàn)重復(fù)元素,底層實(shí)現(xiàn)為數(shù)組。
- 壓縮列表(ziplist)。為節(jié)約內(nèi)存而開發(fā)的順序性數(shù)據(jù)結(jié)構(gòu),可以包含多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)可以保存一個(gè)字節(jié)
- 數(shù)組或者整數(shù)值。
Redis支持哪些數(shù)據(jù)類型?
- 五種常用數(shù)據(jù)類型:String、Hash、Set、List、SortedSet。
- 三種特殊的數(shù)據(jù)類型:Bitmap、HyperLogLog、Geospatial,其中Bitmap 、HyperLogLog的底層都是 String 數(shù)據(jù)類型,Geospatial 底層是 Sorted Set 數(shù)據(jù)類型;
- 字符串對(duì)象string:int整數(shù)、embstr編碼的簡(jiǎn)單動(dòng)態(tài)字符串、raw簡(jiǎn)單動(dòng)態(tài)字符串
- 列表對(duì)象list:ziplist、linkedlist
- 哈希對(duì)象hash:ziplist、hashtable
- 集合對(duì)象set:intset、hashtable
- 有序集合對(duì)象zset:ziplist、skiplist
Redis常用的5種數(shù)據(jù)結(jié)構(gòu)和應(yīng)用場(chǎng)景?
- String:緩存、計(jì)數(shù)器、分布式鎖等
- List:鏈表、隊(duì)列、微博關(guān)注人時(shí)間軸列表等
- Hash:用戶信息、Hash 表等
- Set:去重、贊、踩、共同好友等
- Zset:訪問量排行榜、點(diǎn)擊量排行榜等
Redis為什么采用單線程?
官方回復(fù),CPU不會(huì)成為Redis的制約瓶頸,Redis主要受內(nèi)存、網(wǎng)絡(luò)限制。
例如,在一個(gè)普通的 Linux 系統(tǒng)上,使用pipelining 可以每秒傳遞 100 萬個(gè)請(qǐng)求,所以如果您的應(yīng)用程序主要使用 O(N) 或 O(log(N)) 命令,則幾乎不會(huì)使用太多 CPU,屬于IO密集型系統(tǒng)。
Redis6.0之后又改用多線程呢
Redis的多線程主要是處理數(shù)據(jù)的讀寫、協(xié)議解析。執(zhí)行命令還是采用單線程順序執(zhí)行。
主要是因?yàn)閞edis的性能瓶頸在于網(wǎng)絡(luò)IO而非CPU,使用多線程進(jìn)行一些周邊預(yù)處理,提升了IO的讀寫效率,從而提高了整體的吞吐量。antirez 在 RedisConf 2019 分享時(shí)提到,Redis 6 引入的多線程 IO 對(duì)性能提升至少一倍以上。
Redis過期鍵Key 的刪除策略有哪些?
有3種過期刪除策略。惰性刪除、定期刪除、定時(shí)刪除
- 惰性刪除:使用key時(shí)才進(jìn)行檢查,如果已經(jīng)過期,則刪除,缺點(diǎn):過期的key如果沒有被訪問到,一直無法刪除,一直占用內(nèi)存,造成空間浪費(fèi)。
- 定期刪除:每隔一段時(shí)間做一次檢查,刪除過期的key,每次只是隨機(jī)取一些key去檢查。
- 定時(shí)刪除:為每個(gè)key設(shè)置過期時(shí)間,同時(shí)創(chuàng)建一個(gè)定時(shí)器。一旦到期,立即執(zhí)行刪除。缺點(diǎn):如果過期鍵比較多時(shí),占用CPU較多,對(duì)服務(wù)的性能有很大影響。
如果Redis的內(nèi)存空間不足,淘汰機(jī)制?
- volatile-lru:從已設(shè)置過期時(shí)間的key中,移出最近最少使用的key進(jìn)行淘汰
- allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,移除最近最少使用的key(這個(gè)是最常用的)
- volatile-ttl:從已設(shè)置過期時(shí)間的key中,移出將要過期的key
- volatile-random:從已設(shè)置過期時(shí)間的key中,隨機(jī)選擇key淘汰
- allkeys-random:從key中隨機(jī)選擇key進(jìn)行淘汰
- no-eviction:禁止淘汰數(shù)據(jù)。當(dāng)內(nèi)存達(dá)到閾值的時(shí)候,新寫入操作報(bào)錯(cuò)
- volatile-lfu:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰(LFU(Least
- Frequently Used)算法,也就是最頻繁被訪問的數(shù)據(jù)將來最有可能被訪問到)
- allkeys-lfu:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,移除最不經(jīng)常使用的key。
Redis突然掛了怎么解決?
- 從系統(tǒng)可用性?度思考,Redis Cluster引入主備機(jī)制,當(dāng)主節(jié)點(diǎn)掛了后,自動(dòng)切換到備用節(jié)點(diǎn),繼續(xù)提供服務(wù)。
- Client端引入本地緩存,通過開關(guān)切換,避免Redis突然掛掉,高并發(fā)流量把數(shù)據(jù)庫(kù)打掛。?
Redis持久化有哪些方式?
- 快照RDB。將某個(gè)時(shí)間點(diǎn)上的數(shù)據(jù)庫(kù)狀態(tài)保存到 RDB文件 中,RDB文件是一個(gè)壓縮的二進(jìn)制文件,保存在磁盤上。當(dāng)Redis崩潰時(shí),可用于恢復(fù)數(shù)據(jù)。通過 SAVE 或 BGSAVE 來生成RDB文件。
- SAVE:會(huì)阻塞redis進(jìn)程,直到RDB文件創(chuàng)建完畢,在進(jìn)程阻塞期間,redis不能處理任何命令請(qǐng)求。
- BGSAVE:會(huì)fork出一個(gè)子進(jìn)程,然后由子進(jìn)程去負(fù)責(zé)生成RDB文件,父進(jìn)程還可以繼續(xù)處理命令請(qǐng)求,不會(huì)阻塞進(jìn)程。
- 只追加文件AOF。以日志的形式記錄每個(gè)寫操作(非讀操作)。當(dāng)不同節(jié)點(diǎn)同步數(shù)據(jù)時(shí),讀取日志文件的內(nèi)容將寫指令從前到后執(zhí)行一次,即可完成數(shù)據(jù)恢復(fù)。
Redis常用場(chǎng)景
- 緩存,有句話說的好,「性能不夠,緩存來湊」
- 分布式鎖,利用Redis 的 setnx
- 分布式session
- 計(jì)數(shù)器,通過incr命令
- 排行榜,Redis 的 有序集合
- 其他
Redis 緩存要注意的七大經(jīng)典問題?
列舉了億級(jí)系統(tǒng),高訪問量情況下Redis緩存可能會(huì)遇到哪些問題?以及對(duì)應(yīng)的解決方案。
- 緩存集中失效
- 緩存穿透
- 緩存雪崩
- 緩存熱點(diǎn)
- 緩存大Key
- 緩存數(shù)據(jù)的一致性
- 數(shù)據(jù)并發(fā)競(jìng)爭(zhēng)預(yù)熱
Redis集群方案有哪幾種?
- 主從復(fù)制模式
- Sentinel(哨兵)模式
- Redis Cluster 模式
Redis主從數(shù)據(jù)同步(主從復(fù)制)的過程?
- slave啟動(dòng)后,向master發(fā)送sync命令
- master收到sync之后,執(zhí)行bgsave保存快照,生成RDB全量文件
- master把slave的寫命令記錄到緩存
- bgsave執(zhí)行完畢之后,發(fā)送RDB文件到slave,slave執(zhí)行
- master發(fā)送緩沖區(qū)的寫命令給slave,slave接收命令并執(zhí)行,完成復(fù)制初始化。
- 此后,master每次執(zhí)行一個(gè)寫命令都會(huì)同步發(fā)送給slave,保持master與slave之間數(shù)據(jù)的一致性
Redis主從復(fù)制的優(yōu)缺點(diǎn)?
- 1、優(yōu)點(diǎn):master能自動(dòng)將數(shù)據(jù)同步到slave,可以進(jìn)行讀寫分離,分擔(dān)master的讀壓力master、slave之間的同步是以非阻塞的方式進(jìn)行的,同步期間,客戶端仍然可以提交查詢或更新請(qǐng)求
- 缺點(diǎn):不具備自動(dòng)容錯(cuò)與恢復(fù)功能,master 節(jié)點(diǎn)宕機(jī)后,需要手動(dòng)指定新的 master,master宕機(jī),如果宕機(jī)前數(shù)據(jù)沒有同步完,則切換IP后會(huì)存在數(shù)據(jù)不一致的問題,難以支持在線擴(kuò)容,Redis的容量受限于單機(jī)配置
Redis Sentinel(哨兵)模式的優(yōu)缺點(diǎn)?
哨兵模式基于主從復(fù)制模式,增加了哨兵來監(jiān)控與自動(dòng)處理故障。
- 優(yōu)點(diǎn):哨兵模式基于主從復(fù)制模式,所以主從復(fù)制模式有的優(yōu)點(diǎn),哨兵模式也有master 掛掉可以自動(dòng)進(jìn)行切換,系統(tǒng)可用性更高
- 缺點(diǎn):Redis的容量受限于單機(jī)配置需要額外的資源來啟動(dòng)sentinel進(jìn)程
Redis Cluster 模式的優(yōu)缺點(diǎn)?
實(shí)現(xiàn)了Redis的分布式存儲(chǔ),即每臺(tái)節(jié)點(diǎn)存儲(chǔ)不同的內(nèi)容,來解決在線擴(kuò)容的問題。
- 優(yōu)點(diǎn):
- 無中心架構(gòu),數(shù)據(jù)按照slot分布在多個(gè)節(jié)點(diǎn)
- 集群中的每個(gè)節(jié)點(diǎn)都是平等的,每個(gè)節(jié)點(diǎn)都保存各自的數(shù)據(jù)和整個(gè)集群的狀態(tài)。
- 每個(gè)節(jié)點(diǎn)都和其他所有節(jié)點(diǎn)連接,而且這些連接保持活躍,這樣就保證了我們只需要連接集群中的任意一個(gè)節(jié)點(diǎn),就可以獲取到其他節(jié)點(diǎn)的數(shù)據(jù)。
- 可線性擴(kuò)展到1000多個(gè)節(jié)點(diǎn),節(jié)點(diǎn)可動(dòng)態(tài)添加或刪除。
- 能夠?qū)崿F(xiàn)自動(dòng)故障轉(zhuǎn)移,節(jié)點(diǎn)之間通過gossip協(xié)議交換狀態(tài)信息,用投票機(jī)制完成slave到master的?色轉(zhuǎn)換。
- 缺點(diǎn):
- 數(shù)據(jù)通過異步復(fù)制,不保證數(shù)據(jù)的強(qiáng)一致性。
- slave充當(dāng) “冷備”,不對(duì)外提供讀、寫服務(wù),只作為故障轉(zhuǎn)移使用。
- 批量操作限制,目前只支持具有相同slot值的key執(zhí)行批量操作,對(duì)mset、mget、sunion等操作支持不友好
- key事務(wù)操作支持有限,只支持多key在同一節(jié)點(diǎn)的事務(wù)操作,多key分布在不同節(jié)點(diǎn)時(shí)無法使用事務(wù)功能
- 不支持多數(shù)據(jù)庫(kù)空間,一臺(tái)redis可以支持16個(gè)db,集群模式下只能使用一個(gè),即db0 。
- Redis Cluster模式不建議使用pipeline和multi-keys操作,減少max redirect產(chǎn)生的場(chǎng)景。
Redis 如何做擴(kuò)容?
為了避免數(shù)據(jù)遷移失效,通常使用一致性哈希 實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)容縮容,有效減少需要遷移的Key數(shù)量。
但是Cluster 模式,采用固定Slot槽位方式(16384個(gè)),對(duì)每個(gè)key計(jì)算CRC16值,然后對(duì)16384取模,然后根據(jù)slot值找到目標(biāo)機(jī)器,擴(kuò)容時(shí),我們只需要遷移一部分的slot到新節(jié)點(diǎn)即可。
Redis的集群原理?
一個(gè)redis集群由多個(gè)節(jié)點(diǎn)node組成,而多個(gè)node之間通過 cluster meet命令來進(jìn)行連接,組成一個(gè)集群。
數(shù)據(jù)存儲(chǔ)通過分片的形式,整個(gè)集群分成了16384個(gè)slot,每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分槽位。整個(gè)槽位的信息會(huì)同步到所有節(jié)點(diǎn)中。
key與slot的映射關(guān)系:健值對(duì) key,進(jìn)行 CRC16 計(jì)算,計(jì)算出一個(gè)16bit的值,將16bit的值對(duì)16384取模,得到0~16383的數(shù)表示 key 對(duì)應(yīng)的哈希槽
Redis 如何做到高可用?
哨兵機(jī)制。具有自動(dòng)故障轉(zhuǎn)移、集群監(jiān)控、消息通知等功能。
哨兵可以同時(shí)監(jiān)視所有的主、從服務(wù)器,當(dāng)某個(gè)master下線時(shí),自動(dòng)提升對(duì)應(yīng)的slave為master,然后由新master對(duì)外提供服務(wù)。
什么是Redis 事務(wù)?
Redis事務(wù)是一組命令的集合,將多個(gè)命令打包,然后把這些命令按順序添加到隊(duì)列中,并且按順序執(zhí)行這些命令。
Redis事務(wù)中沒有像Mysql關(guān)系型數(shù)據(jù)庫(kù)事務(wù)隔離級(jí)別的概念,不能保證原子性操作,也沒有像Mysql那樣執(zhí)行事務(wù)失敗會(huì)進(jìn)行回滾操作
Redis事務(wù)執(zhí)行流程?
通過MULTI 、EXEC、WATCH等命令來實(shí)現(xiàn)事務(wù)機(jī)制,事務(wù)執(zhí)行過程將一系列多個(gè)命令按照順序一次性執(zhí)行,在執(zhí)行期間,事務(wù)不會(huì)被中斷,也不會(huì)去執(zhí)行客戶端的其他請(qǐng)求,直到所有命令執(zhí)行完畢。
具體過程:服務(wù)端收到客戶端請(qǐng)求,事務(wù)以MULTI 開始如果正處于事務(wù)狀態(tài)時(shí),則會(huì)把后續(xù)命令放入隊(duì)列同時(shí)返回給客戶端 QUEUED ,反之則直接執(zhí)行這個(gè)命令
當(dāng)收到客戶端的EXEC命令時(shí),才會(huì)將隊(duì)列里的命令取出、順序執(zhí)行,執(zhí)行完將當(dāng)前狀態(tài)從事務(wù)狀態(tài)改為非事務(wù)狀態(tài)
如果收到DISCARD命令,放棄執(zhí)行隊(duì)列中的命令,可以理解為Mysql的回滾操作,并且將當(dāng)前的狀態(tài)從事務(wù)狀態(tài)改為非事務(wù)狀態(tài)
WATCH 監(jiān)視某個(gè)key,該命令只能在MULTI命令之前執(zhí)行。如果監(jiān)視的key被其他客戶端修改,EXEC將會(huì)放棄執(zhí)行隊(duì)列中的所有命令。 UNWATCH 取消監(jiān)視之前通過WATCH 命令監(jiān)視的key。通過執(zhí)行EXEC、DISCARD 兩個(gè)命令之前監(jiān)視的key也會(huì)被取消監(jiān)視。
Redis與Guava、Caffeine 有什么區(qū)別?
緩存分為本地緩存和分布式緩存。文章來源:http://www.zghlxwxcb.cn/news/detail-570394.html
- Caffeine、Guava,屬于本地緩存,特點(diǎn):
- 直接訪問內(nèi)存,速度快,受內(nèi)存限制,無法進(jìn)行大數(shù)據(jù)存儲(chǔ)。
- 無網(wǎng)絡(luò)通訊開銷,性能更高。
- 只支持本地應(yīng)用進(jìn)程訪問,同步更新所有節(jié)點(diǎn)的本地緩存數(shù)據(jù)成本較高。
- 應(yīng)用進(jìn)程重啟,數(shù)據(jù)會(huì)丟失。
- 所以,本地緩存適合存儲(chǔ)一些不易改變或者低頻改變的高熱點(diǎn)數(shù)據(jù)。
- Redis屬于分布式緩存,特點(diǎn):
- 集群模式,支持大數(shù)據(jù)量存儲(chǔ)
- 數(shù)據(jù)集中存儲(chǔ),保證數(shù)據(jù)的一致性
- 數(shù)據(jù)跨網(wǎng)絡(luò)傳輸,性能低于本地緩存。但同一個(gè)機(jī)房,兩臺(tái)服務(wù)器之間請(qǐng)求跑一個(gè)來回也就需要500微秒,比
- 起其優(yōu)勢(shì),這點(diǎn)損耗完全可以忽略,這也是分布式緩存受歡迎的原因。
- 支持副本機(jī)制,有效的保證了高可用性。
如何實(shí)現(xiàn)一個(gè)分布式鎖?文章來源地址http://www.zghlxwxcb.cn/news/detail-570394.html
- 數(shù)據(jù)庫(kù)表,性能比較差
- 使用Lua腳本 (包含 SETNX + EXPIRE 兩條指令)
- SET的擴(kuò)展命令(SET key value [EX][PX] [NX|XX])
- Redlock 框架
- Zookeeper Curator 框架提供了現(xiàn)成的分布式
到了這里,關(guān)于互聯(lián)網(wǎng)大廠技術(shù)-Redis-集群模型、架構(gòu)原理、難點(diǎn)應(yīng)用場(chǎng)景、高頻面試問題詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!