Redis---常見面試題整理

今日份雞湯:成年人的世界哪有容易可言,但我們依舊要做打不死的小強猪叙!

1娇斩、Redis用了哪些數(shù)據(jù)結(jié)構(gòu)、場景穴翩?
(1)String:單值緩存犬第、對象緩存(對象設(shè)置成一個json串)、分布式鎖芒帕、計數(shù)器(文章閱讀數(shù)量)歉嗓、分布式系統(tǒng)全局序列號(分庫分表使用redis實現(xiàn)自增id:業(yè)務(wù)量大的時候,影響性能背蟆,因為他主要是用做緩存鉴分,可以批量獲取,一次拿100個带膀,incrby orderid 100)志珍。
(2)hash:對象緩存(一個表中有很多字段,但是我經(jīng)常就只用某一個字段垛叨,比如余額伦糯,這種場景適合使用hash,不適合使用string)、電商購物車(用戶id為key舔株,商品id為filed莺琳,商品數(shù)量為value)。
(3)list:常用數(shù)據(jù)結(jié)構(gòu)(棧 = LPUSH + LPOP载慈、隊列 = LPUSH + RPOP惭等、阻塞隊列 = LPUSH + BRPOP,屬于分布式數(shù)據(jù)結(jié)構(gòu),所以沒用java的數(shù)據(jù)結(jié)構(gòu))办铡、微博和微信公眾號消息流(用數(shù)據(jù)庫實現(xiàn)的話辞做,性能低,因為是時間倒排)寡具。
(4)set:微信抽獎小程序秤茅、微信微博點贊收藏標簽、集合操作實現(xiàn)微博微信關(guān)注模型(sinter set1 set2童叠,找出共同關(guān)注的人)框喳。
(5)zset:排行榜(熱搜新聞)。
數(shù)據(jù)結(jié)構(gòu)底層:跳表(skiplist:原始跳表是按照分值從小到大一次排列的一個鏈表厦坛。就是把我們的有序鏈表改造為支持“折半查找”算法的一個結(jié)構(gòu)五垮,每兩個元素往上建立一個索引層,這個索引層也會建立一個指針關(guān)系杜秸,以空間換時間放仗,耗費空間大約一倍,效率也提升一倍撬碟,元素越多用跳表越好诞挨,默認超過128個元素自動轉(zhuǎn)為skiplist)、壓縮列表(ziplist:原本是一個鏈表呢蛤,他把指針去掉了惶傻,類似于數(shù)組,區(qū)別在于記錄了相對的偏移位置顾稀,元素少的時候可以用壓縮列表)达罗。

2坝撑、雪崩静秆、穿透、擊穿
(1)雪崩
原因:(1)redis服務(wù)掛掉巡李。(2)redis中的key大面積失效抚笔,可能是key過期,也可能是服務(wù)宕機侨拦,導致請求直接打到數(shù)據(jù)庫殊橙。(redis緩存key同一時間大面積失效,導致請求打到數(shù)據(jù)庫,造成數(shù)據(jù)庫掛掉)膨蛮。
解決:
1》設(shè)置緩存失效時間叠纹,讓他不要在同一時間失效,設(shè)置緩存時敞葛,隨機初始化他的失效時間誉察,讓緩存不在同一時間全部失效。
2》redis集群部署惹谐,熱點key放到不同節(jié)點持偏,讓熱點緩存平均分布在redis節(jié)點上。
3》不設(shè)置緩存失效時間氨肌,讓緩存永遠不失效鸿秆。
4》跑定時任務(wù),定時刷緩存怎囚,比如說設(shè)置三小時失效卿叽,失效前,把緩存刷進去恳守。然后再設(shè)置三個小時附帽,不斷用定時任務(wù)去跑,這樣就不會失效井誉。

(2)穿透
原因:redis緩存和數(shù)據(jù)庫中都沒有這樣的數(shù)據(jù)蕉扮,一般出現(xiàn)這種情況都是惡意用戶。
解決:
1》請求穿過redis直接到數(shù)據(jù)庫颗圣,數(shù)據(jù)庫無論查出什么結(jié)果喳钟,是空還是有值,都會緩存到redis里面去在岂,這樣下次同一參數(shù)發(fā)請求就不會穿透redis奔则。但請求可以換不同的參數(shù)。
2》把這個ip拉黑蔽午,但他可能換不同的ip易茬。
3》對參數(shù)合法性進行校驗,參數(shù)不合法直接return掉及老。
4》使用布隆過濾器抽莱。bloom算法類似一個hash set,用來判斷某個元素(key)是否在某個集合中骄恶。就是他能保證食铐,存在的數(shù)據(jù)一定會在集合中,但是不存在的數(shù)據(jù)有可能存在僧鲁,存在誤判率虐呻,但是很低

(3)擊穿
原因:大量請求訪問某個熱點key象泵,當這個熱點的key突然失效,請求將打到數(shù)據(jù)庫斟叼。
解決:
1》key不設(shè)置過期時間偶惠。
2》使用分布式鎖。當熱點key失效的時候朗涩,請求打到數(shù)據(jù)庫洲鸠,將請求數(shù)據(jù)庫這一步給他加上鎖,這個時候就只有這一個線程能搶到這個鎖馋缅,所以也就有一個線程能操作這個數(shù)據(jù)庫扒腕,這個時候?qū)?shù)據(jù)庫的壓力就比較小,當他查詢到這個數(shù)據(jù)后萤悴,再把這個數(shù)據(jù)重新寫到redis里面去瘾腰,其他沒有搶到鎖的線程,讓他先睡幾毫秒覆履,然后再重新去redis里面去查詢這個數(shù)據(jù)蹋盆。

3、緩存一致性怎么保證硝全?
(1)延遲雙刪:沒有辦法預(yù)估等待時間栖雾,可能還會出現(xiàn)數(shù)據(jù)不一致問題。
延時雙刪的方案的思路是伟众,為了避免更新數(shù)據(jù)庫的時候析藕,其他線程從緩存中讀取不到數(shù)據(jù),就在更新完數(shù)據(jù)庫之后凳厢,再sleep一段時間账胧,然后再次刪除緩存。

sleep的時間要對業(yè)務(wù)讀寫緩存的時間做出評估先紫,sleep時間大于讀寫緩存的時間即可治泥。

流程如下:

線程1刪除緩存,然后去更新數(shù)據(jù)庫

線程2來讀緩存遮精,發(fā)現(xiàn)緩存已經(jīng)被刪除居夹,所以直接從數(shù)據(jù)庫中讀取,這時候由于線程1還沒有更新完成本冲,所以讀到的是舊值准脂,然后把舊值寫入緩存

線程1,根據(jù)估算的時間眼俊,sleep意狠,由于sleep的時間大于線程2讀數(shù)據(jù)+寫緩存的時間,所以緩存被再次刪除

如果還有其他線程來讀取緩存的話疮胖,就會再次從數(shù)據(jù)庫中讀取到最新值

(2)內(nèi)存隊列:性能低环戈,相當于串行執(zhí)行。
這是網(wǎng)上很多文章里都有寫過的方案澎灸。但是這個方案的缺陷會更明顯一點院塞。

先更新數(shù)據(jù)庫,成功后往消息隊列發(fā)消息性昭,消費到消息后再刪除緩存拦止,借助消息隊列的重試機制來實現(xiàn),達到最終一致性的效果糜颠。
這個解決方案其實問題更多汹族。

引入消息中間件之后,問題更復雜了其兴,怎么保證消息不丟失更麻煩

就算更新數(shù)據(jù)庫和刪除緩存都沒有發(fā)生問題顶瞒,消息的延遲也會帶來短暫的不一致性,不過這個延遲相對來說還是可以接受的

(3)進階版消息隊列:
為了解決緩存一致性的問題單獨引入一個消息隊列元旬,太復雜了榴徐。

其實,一般大公司本身都會有監(jiān)聽binlog消息的消息隊列存在匀归,主要是為了做一些核對的工作坑资。

這樣,我們可以借助監(jiān)聽binlog的消息隊列來做刪除緩存的操作穆端。這樣做的好處是袱贮,不用你自己引入,侵入到你的業(yè)務(wù)代碼中体啰,中間件幫你做了解耦字柠,同時,中間件的這個東西本身就保證了高可用狡赐。

當然窑业,這樣消息延遲的問題依然存在,但是相比單純引入消息隊列的做法更好一點枕屉。

而且常柄,如果并發(fā)不是特別高的話,這種做法的實時性和一致性都還算可以接受的搀擂。

(4)分布式鎖西潘,但是分布式鎖效率比較低。

(5)讀寫鎖哨颂,適合于讀多寫少的場景喷市。

(6)設(shè)置緩存過期時間。
每次放入緩存的時候威恼,設(shè)置一個過期時間品姓,比如5分鐘寝并,以后的操作只修改數(shù)據(jù)庫,不操作緩存腹备,等待緩存超時后從數(shù)據(jù)庫重新讀取衬潦。

如果對于一致性要求不是很高的情況,可以采用這種方案植酥。

這個方案還會有另外一個問題镀岛,就是如果數(shù)據(jù)更新的特別頻繁,不一致性的問題就很大了友驮。

在實際生產(chǎn)中漂羊,我們有一些活動的緩存數(shù)據(jù)是使用這種方式處理的。

因為活動并不頻繁發(fā)生改變卸留,而且對于活動來說走越,短暫的不一致性并不會有什么大的問題。
(7)TiDB艾猜。

4买喧、Redis分布式鎖的實現(xiàn)及要注意的問題
synchronized單機版是ok的,但是分布式項目中就不可以了匆赃,這時候就考慮到取消單機鎖淤毛,使用redis的分布式鎖setnx,使用分布式鎖的情況算柳,需要注意鎖是否被釋放低淡,比如出現(xiàn)異常情況,所以要在代碼層面finally中釋放鎖瞬项。除了這種情況蔗蹋,比如說宕機了,根本沒有走到finally塊里面囱淋,這樣也沒有辦法保證釋放鎖猪杭,所以在緩存這個key的時候,需要設(shè)置過期時間妥衣。這個時候也要注意皂吮,必須要setnx和過期時間設(shè)置的代碼寫在同一行,來保證原子操作税手。除此以外蜂筹,還要規(guī)定只能自己刪除自己的鎖,你不能把別人的鎖刪除了(比如說芦倒,我加鎖超時時間為10s艺挪,然后我線程1過來執(zhí)行了10s還沒有執(zhí)行完,然后鎖釋放了兵扬,這時候線程二過來麻裳,正好拿到了線程1釋放的鎖口蝠,然后線程1、線程二都執(zhí)行5s掂器,線程1現(xiàn)在執(zhí)行結(jié)束了亚皂,然后他開始釋放鎖俱箱,這時候国瓮,他釋放的就是線程2所加的鎖。)另外狞谱,redis集群環(huán)境下乃摹,我們即便是上面的所有操作都保證沒問題了,也不能保證加鎖沒問題跟衅,主節(jié)點加鎖后掛了孵睬,從節(jié)點沒有拿到鎖數(shù)據(jù),所以我們就使用redlock的redisson來實現(xiàn)伶跷,使用redisson在unlock的時候掰读,加上判斷,redisson.islocked() && redisson.isHeldByCurrentThread(),判斷當前是否是加鎖狀態(tài)叭莫,以及是否是當前線程加的鎖蹈集。

5、Redis單線程為什么性能還很高
(1)內(nèi)存級別操作:數(shù)據(jù)讀寫在內(nèi)存中雇初,去除了磁盤IO的時間拢肆,異步持久化到磁盤。
(2)基于非阻塞的io多路復用機制:加一個監(jiān)視的效果靖诗,請求準備完畢就直接讓redis對這個請求進行處理郭怪。epoll:監(jiān)視請求的時候,給每個請求都設(shè)置一個標識符刊橘,標識請求是否準備完畢鄙才。
(3)work線程是單線程,避免了線程上下文切換促绵。
(4)豐富的數(shù)據(jù)結(jié)構(gòu):底層數(shù)據(jù)結(jié)構(gòu)攒庵。hash、壓縮表绞愚、跳表叙甸。

6、Redis淘汰策略
(1)惰性過期:只有當訪問一個key的時候位衩,才會判斷這個key是否過期裆蒸,如果過期就刪除,比較耗內(nèi)存糖驴。
(2)定時過期:redis中沒有用到僚祷,但是也是一種常見的策略佛致,給每一個key設(shè)置一個定時器,到時間就把key刪除掉辙谜,對內(nèi)存友好俺榆,但是對cpu不友好。
(3)定期過期:每隔一段時間装哆,會掃描一定數(shù)量的key罐脊,然后判斷key是否過期,如果過期就刪除蜕琴。
redis中同時使用了惰性過期和定期過期萍桌。

7、Redis集群還是哨兵凌简?集群key分布上炎?
使用的是哨兵模式,因為主從復制模式雏搂,如果master掛掉就無法提供服務(wù)藕施,不是高可用,為了達到高可用使用了哨兵模式凸郑,主節(jié)點掛掉后裳食,會內(nèi)部投票機制從從節(jié)點中選擇出來一個新的主節(jié)點,類似心跳機制线椰,一般設(shè)置3-5秒去檢測一次胞谈。耗費性能和資源
redis集群模式是在3.0之后才有的:完成高可用高并發(fā),三主三從憨愉,無中心結(jié)構(gòu)烦绳,就是沒有master

Redis Cluster 集群引入了主從模式,一個主節(jié)點對應(yīng)一個或者多個從節(jié)點配紫,當主節(jié)點宕機的時候径密,就會啟用從節(jié)點。當其它主節(jié)點 PING一個主節(jié)點時躺孝,如果半數(shù)以上的主節(jié)點與該主節(jié)點通信超時享扔,那么認為主節(jié)點A下線,這時它的從節(jié)點會頂上去服務(wù)植袍。但是如果該主節(jié)點和它的從節(jié)點都宕機了惧眠,那么此集群就無法再提供服務(wù)了。 在對應(yīng)的所有鍵中通過 Redis 內(nèi)部實現(xiàn)算法 CRC16 對鍵進行哈希算法運算得到一個整數(shù)值后在 mod上 16384后于个,將得到的值映射對應(yīng)到編號為 0 ~ 16383的槽子中氛魁。 Cluster 還允許用戶強制將某個 key 掛在特定槽位上,通過在 key 字符串里面寫入 tag 標記,這時key 所掛在的槽位等于 tag 所在的槽位秀存。

8捶码、Redis集群之間怎么通訊?
在分布式存儲中需要提供維護節(jié)點元數(shù)據(jù)信息的機制或链,所謂元數(shù)據(jù)是指:節(jié)點負責哪些數(shù)據(jù)惫恼,是否出現(xiàn)故障等狀態(tài)信息。常見的元數(shù)據(jù)維護方式分為:集中式和P2P方式澳盐。Redis集群采用P2P的Gossip(流言)協(xié)議祈纯,Gossip協(xié)議工作原理就是節(jié)點彼此不斷通信交換信息,一段時間后所有的節(jié)點都會知道集群完整的信息洞就,這種方式類似流言傳播
集群中的每個節(jié)點都會單獨開辟一個TCP通道盆繁,用于節(jié)點之間彼此通信掀淘,通信端口號在基礎(chǔ)端口上加10000

每個節(jié)點在固定周期內(nèi)通過特定規(guī)則選擇幾個節(jié)點發(fā)送ping消息

接收到ping消息的節(jié)點用pong消息作為響應(yīng)

集群中每個節(jié)點通過一定規(guī)則挑選要通信的節(jié)點旬蟋,每個節(jié)點可能知道全部節(jié)點,也可能僅知道部分節(jié)點革娄,只要這些節(jié)點彼此可以正常通信倾贰,最終它們會達到一致的狀態(tài)。當節(jié)點出故障拦惋、新節(jié)點加入匆浙、主從角色變化、槽信息變更等事件發(fā)生時厕妖,通過不斷的ping/pong消息通信首尼,經(jīng)過一段時間后所有的節(jié)點都會知道整個集群全部節(jié)點的最新狀態(tài),從而達到集群狀態(tài)同步的目的言秸。

Gossip消息

Gossip協(xié)議的主要職責就是信息交換软能。信息交換的載體就是節(jié)點彼此發(fā)送的Gossip消息,常用的Gossip消息可分為:ping消息举畸、pong消息查排、meet消息、fail消息

meet消息:用于通知新節(jié)點加入抄沮。消息發(fā)送者通知接收者加入到當前集群跋核,meet消息通信正常完成后,接收節(jié)點會加入到集群中并進行周期性的ping叛买、pong消息交換

ping消息:集群內(nèi)交換最頻繁的消息砂代,集群內(nèi)每個節(jié)點每秒向多個其他節(jié)點發(fā)送ping消息,用于檢測節(jié)點是否在線和交換彼此狀態(tài)信息率挣。ping消息發(fā)送封裝了自身節(jié)點和部分其他節(jié)點的狀態(tài)數(shù)據(jù)

pong消息:當接收到ping刻伊、meet消息時,作為響應(yīng)消息回復給發(fā)送方確認消息正常通信。pong消息內(nèi)部封裝了自身狀態(tài)數(shù)據(jù)娃圆。節(jié)點也可以向集群內(nèi)廣播自身的pong消息來通知整個集群對自身狀態(tài)進行更新

fail消息:當節(jié)點判定集群內(nèi)另一個節(jié)點下線時玫锋,會向集群內(nèi)廣播一個fail消息,其他節(jié)點接收到fail消息之后把對應(yīng)節(jié)點更新為下線狀態(tài)

在所有的 redis 實例節(jié)點之間彼此使用 Gossip 協(xié)議進行通信讼呢,通過 PING-PONG 機制來達到互聯(lián)狀態(tài)撩鹿,在傳輸過程中使用特殊的二進制協(xié)議相互交互集群信息。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悦屏,一起剝皮案震驚了整個濱河市节沦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌础爬,老刑警劉巖甫贯,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異看蚜,居然都是意外死亡叫搁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門供炎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渴逻,“玉大人,你說我怎么就攤上這事音诫〔肄龋” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵竭钝,是天一觀的道長梨撞。 經(jīng)常有香客問我,道長香罐,這世上最難降的妖魔是什么卧波? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮穴吹,結(jié)果婚禮上幽勒,老公的妹妹穿的比我還像新娘。我一直安慰自己港令,他們只是感情好啥容,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著顷霹,像睡著了一般咪惠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淋淀,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天遥昧,我揣著相機與錄音,去河邊找鬼。 笑死炭臭,一個胖子當著我的面吹牛永脓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鞋仍,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼常摧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了威创?” 一聲冷哼從身側(cè)響起落午,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肚豺,沒想到半個月后溃斋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡吸申,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年梗劫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呛谜。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡在跳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隐岛,到底是詐尸還是另有隱情,我是刑警寧澤瓷翻,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布聚凹,位于F島的核電站,受9級特大地震影響齐帚,放射性物質(zhì)發(fā)生泄漏妒牙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一对妄、第九天 我趴在偏房一處隱蔽的房頂上張望湘今。 院中可真熱鬧,春花似錦剪菱、人聲如沸摩瞎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春谁帕,著一層夾襖步出監(jiān)牢的瞬間笋额,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稠氮,地道東北人曹阔。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像隔披,于是被迫代替她去往敵國和親次兆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

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