Redis是一個(gè)非?;馃岬囊粋€(gè)“專有詞”在互聯(lián)網(wǎng)和大數(shù)據(jù)中占有一席之位。Redis是一款高性能的NOSQL系列的非關(guān)系型數(shù)據(jù)庫(kù),也是之所以為何這么火的原因了吧!下面是小編為大家總結(jié)的一些關(guān)于Redis的面試題(個(gè)人總結(jié))希望大家會(huì)喜歡。
Redis的基礎(chǔ)
什么是Redis ?簡(jiǎn)述它的優(yōu)缺點(diǎn):Redis的全稱是Remote DictionarylServer ,本質(zhì)上是一個(gè)Key-Value類型的內(nèi)存數(shù)據(jù)庫(kù),很像memcached ,整個(gè)數(shù)據(jù)庫(kù)統(tǒng)統(tǒng)加載在內(nèi)存當(dāng)中進(jìn)行操作,定期通過(guò)異步操作把數(shù)據(jù)庫(kù)數(shù)據(jù)flush到硬盤上進(jìn)行保存。Redis的主要缺點(diǎn)是數(shù)據(jù)庫(kù)容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫,因此Redis適合的場(chǎng)景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上。
為什么Redis需要把所有數(shù)據(jù)放到內(nèi)存中:Redis為了達(dá)到最快的讀寫速度將數(shù)據(jù)都讀到內(nèi)存中,并通過(guò)異步的方式將數(shù)據(jù)寫入磁盤。所以redis具有快速和數(shù)據(jù)持久化的特征,如果不將數(shù)據(jù)放在內(nèi)存中,磁盤I/O速度為嚴(yán)重影響redis的性能。在內(nèi)存越來(lái)越便宜的今天, redis將會(huì)越來(lái)越受歡迎,如果設(shè)置了最大使用的內(nèi)存,則數(shù)據(jù)已有記錄數(shù)達(dá)到內(nèi)存限值后不能繼續(xù)插入新值。
Redis和Redisson有什么關(guān)系:Redisson是-個(gè)高級(jí)的分布式協(xié)調(diào)Redis客服端,能幫助用戶在分布式環(huán)境中輕松實(shí)現(xiàn)一些Java的對(duì)象(Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap,List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock,ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。
Jedis與Redisson對(duì)比有什么優(yōu)缺點(diǎn):Jedis是Redis的Java實(shí)現(xiàn)的客戶端,其API提供了比較全面的Redis命令的支持;Redisson實(shí)現(xiàn)了分布式和可擴(kuò)展的Java數(shù)據(jù)結(jié)構(gòu),和Jedis相比,功能較為簡(jiǎn)單,不支持字符串操作,不支持排序、事務(wù)、管道、分區(qū)等Redis特性。Redisson 的宗旨是促進(jìn)使用者對(duì)Redis的關(guān)注分離,從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務(wù)邏輯上。
Redis的緩存穿透、緩存崩潰、緩存擊穿的理解?
1.緩存穿透:是指查詢一個(gè)數(shù)據(jù)庫(kù)一定不存在的數(shù)據(jù)。
正常的使用緩存流程大致是,數(shù)據(jù)查詢先進(jìn)行緩存查詢,如果key不存在或 者key已經(jīng)過(guò)期,再對(duì)數(shù)據(jù)庫(kù)進(jìn)行查詢,并把查詢到的對(duì)象,放進(jìn)緩存。如果數(shù)據(jù)庫(kù)查詢對(duì)象為空,則不放進(jìn)緩存。
發(fā)生場(chǎng)景:
如果傳入的參數(shù)為-1,會(huì)是怎么樣?這個(gè)-1,就是一定不存在的對(duì)象。就會(huì)每次都去查詢數(shù)據(jù)庫(kù),而每次查詢都是空,每次又都不會(huì)進(jìn)行緩存。假如有惡意攻擊,就可以利用這個(gè)漏洞,對(duì)數(shù)據(jù)庫(kù)造成壓力,甚至壓垮數(shù)據(jù)庫(kù)。即便是采用UUID,也是很容易找到一個(gè)不存在的KEY,進(jìn)行攻擊。
2.緩存擊穿: 是指一個(gè)key非常熱點(diǎn),在不停的扛著大并發(fā),大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問(wèn),當(dāng)這個(gè)key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請(qǐng)求數(shù)據(jù)庫(kù),就像在一個(gè)屏障上鑿開(kāi)了一個(gè)洞。
發(fā)生場(chǎng)景:某一個(gè)商品爆款的時(shí)候會(huì)導(dǎo)致這種情況的產(chǎn)生。解決方案:
設(shè)置緩存永不過(guò)期(或者過(guò)期時(shí)間比較大)。
設(shè)置雙重緩存?zhèn)浞軦和B,當(dāng)A緩存失效時(shí),使用B緩存。
3.緩存雪崩:緩存在同一時(shí)間內(nèi)大量鍵過(guò)期(失效),接著來(lái)的一大波請(qǐng)求瞬間都落在了數(shù)據(jù)庫(kù)中導(dǎo)致連接異常。
解決方案:
也是像解決緩存穿透一樣加鎖排隊(duì);
建立備份緩存,緩存A和緩存B,A設(shè)置超時(shí)時(shí)間,B不設(shè)置超時(shí)時(shí)間,先從A讀緩存,A沒(méi)有讀B,并且更新A緩存和B緩存;
設(shè)置緩存超時(shí)時(shí)間的時(shí)候加上一個(gè)隨機(jī)的時(shí)間長(zhǎng)度,比如這個(gè)緩存key的超時(shí)時(shí)間是固定的5分鐘加上隨機(jī)的2分鐘,醬紫可從一定程度上避免雪崩問(wèn)題;
Redis 和 Memecache 有什么區(qū)別?
Redis和Memcache都是將數(shù)據(jù)存放在內(nèi)存中,都是內(nèi)存數(shù)據(jù)庫(kù)。不過(guò)memcache還可用于緩存其他東西,例如圖片、視頻等等。
Redis不僅僅支持簡(jiǎn)單的k/v類型的數(shù)據(jù),同時(shí)還提供list,set,hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。
虛擬內(nèi)存–Redis當(dāng)物理內(nèi)存用完時(shí),可以將一些很久沒(méi)用到的value 交換到磁盤
過(guò)期策略–memcache在set時(shí)就指定,例如set key1 0 0 8,即永不過(guò)期。Redis可以通過(guò)例如expire 設(shè)定,例如expire name 10
分布式–設(shè)定memcache集群,利用magent做一主多從;redis可以做一主多從。都可以一主一從
存儲(chǔ)數(shù)據(jù)安全–memcache掛掉后,數(shù)據(jù)沒(méi)了;redis可以定期保存到磁盤(持久化)
災(zāi)難恢復(fù)–memcache掛掉后,數(shù)據(jù)不可恢復(fù); redis數(shù)據(jù)丟失后可以通過(guò)aof恢復(fù)
Redis支持?jǐn)?shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。
Redis的分布式鎖如何實(shí)現(xiàn),有什么優(yōu)缺點(diǎn)?
1.分布式鎖需要解決的問(wèn)題
互斥性:任意時(shí)刻只能有一個(gè)客戶端擁有鎖,不能同時(shí)多個(gè)客戶端獲取
安全性:鎖只能被持有該鎖的用戶刪除,而不能被其他用戶刪除
死鎖:獲取鎖的客戶端因?yàn)槟承┰蚨礄C(jī),而未能釋放鎖,其他客戶端無(wú)法獲取此鎖,需要有機(jī)制來(lái)避免該類問(wèn)題的發(fā)生
容錯(cuò):當(dāng)部分節(jié)點(diǎn)宕機(jī),客戶端仍能獲取鎖或者釋放鎖。
2.如何通過(guò)Redis實(shí)現(xiàn)分布式鎖:(非完善方法)
SETNX key value :如果key不存在,則創(chuàng)建并賦值
時(shí)間復(fù)雜度: 0(1)
返回值:設(shè)置成功,返回1;設(shè)置失敗,返回0。
但是此時(shí)我們獲取的key是長(zhǎng)期有效的,所以我們應(yīng)該如何解決長(zhǎng)期有效的問(wèn)題呢?
如何解決SETNX長(zhǎng)期有效的問(wèn)題?
EXPIRE key seconds
設(shè)置key的生存時(shí)間,當(dāng)key過(guò)期時(shí)(生存時(shí)間為0) ,會(huì)被自動(dòng)刪除
缺點(diǎn):原子性得不到滿足

3.如何通過(guò)Redis實(shí)現(xiàn)分布式鎖:(正確方式)
SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX second :設(shè)置鍵的過(guò)期時(shí)間為second秒
PX millisecond :設(shè)置鍵的過(guò)期時(shí)間為millisecond毫秒
NX :只在鍵不存在時(shí),才對(duì)鍵進(jìn)行設(shè)置操作
XX:只在鍵已經(jīng)存在時(shí),才對(duì)鍵進(jìn)行設(shè)置操作
SET操作成功完成時(shí),返回OK ,否則返回nil

4.大量的key同時(shí)過(guò)期的注意事項(xiàng)
集中過(guò)期,由于清除大量的key很耗時(shí),會(huì)出現(xiàn)短暫的卡頓現(xiàn)象
解放方案:在設(shè)置key的過(guò)期時(shí)間的時(shí)候,給每個(gè)key加上隨機(jī)值
特殊場(chǎng)景1:超時(shí)后使用del 導(dǎo)致誤刪其他線程的鎖
又是一個(gè)極端場(chǎng)景,假如某線程成功得到了鎖,并且設(shè)置的超時(shí)時(shí)間是30秒。
如果某些原因?qū)е戮€程B執(zhí)行的很慢很慢,過(guò)了30秒都沒(méi)執(zhí)行完,這時(shí)候鎖過(guò)期自動(dòng)釋放,線程B得到了鎖。
隨后,線程A執(zhí)行完了任務(wù),線程A接著執(zhí)行del指令來(lái)釋放鎖。但這時(shí)候線程B還沒(méi)執(zhí)行完,線程A實(shí)際上刪除的是線程B加的鎖。
怎么避免這種情況呢?可以在del釋放鎖之前做一個(gè)判斷,驗(yàn)證當(dāng)前的鎖是不是自己加的鎖。
至于具體的實(shí)現(xiàn),可以在加鎖的時(shí)候把當(dāng)前的線程ID當(dāng)做value,并在刪除之前驗(yàn)證key對(duì)應(yīng)的value是不是自己線程的ID。
if判斷和釋放鎖是兩個(gè)獨(dú)立操作,不是原子性。
我們都是追求極致的程序員,所以這一塊要用Lua腳本來(lái)實(shí)現(xiàn):

這樣一來(lái),驗(yàn)證和刪除過(guò)程就是原子操作了。
特殊場(chǎng)景2: 出現(xiàn)并發(fā)的可能性
還是剛才的場(chǎng)景1,雖然我們避免了線程A誤刪掉key的情況,但是同一時(shí)間有A,B兩個(gè)線程在訪問(wèn)代碼塊,仍然是不完美的。
怎么辦呢?我們可以讓獲得鎖的線程開(kāi)啟一個(gè)守護(hù)線程,用來(lái)給快要過(guò)期的鎖“續(xù)航”。
當(dāng)過(guò)去了29秒,線程A還沒(méi)執(zhí)行完,這時(shí)候守護(hù)線程會(huì)執(zhí)行expire指令,為這把鎖“續(xù)命”20秒。守護(hù)線程從第29秒開(kāi)始執(zhí)行,每20秒執(zhí)行一次。
當(dāng)線程A執(zhí)行完任務(wù),會(huì)顯式關(guān)掉守護(hù)線程。
另一種情況,如果節(jié)點(diǎn)1 忽然斷電,由于線程A和守護(hù)線程在同一個(gè)進(jìn)程,守護(hù)線程也會(huì)停下。這把鎖到了超時(shí)的時(shí)候,沒(méi)人給它續(xù)命,也就自動(dòng)釋放了。
由于文章限制小編把剩下的面試題整理成文檔和視頻的形勢(shì)列在下方,面試哪里還不懂?趕緊領(lǐng)取資料吧!
獲取方式:轉(zhuǎn)發(fā)文章關(guān)注小編,++++Vx : bjmsb2020來(lái)進(jìn)行領(lǐng)取吧~~~~