分享幾道 Redis 高頻面試題,面試不用愁
1、說(shuō)說(shuō) Redis 都有哪些應(yīng)用場(chǎng)景?
- 緩存:這應(yīng)該是 Redis 主要的功能了,也是大型網(wǎng)站必備機(jī)制,合理地使用緩存不僅可以加 快數(shù)據(jù)的訪(fǎng)問(wèn)速度,而且能夠有效地降低后端數(shù)據(jù)源的壓力。
- 共享Session:對(duì)于一些依賴(lài) session 功能的服務(wù)來(lái)說(shuō),如果需要從單機(jī)變成集群的話(huà),可以選擇 redis 來(lái)統(tǒng)一管理 session。
- 消息隊(duì)列系統(tǒng):消息隊(duì)列系統(tǒng)可以說(shuō)是一個(gè)大型網(wǎng)站的必備基礎(chǔ)組件,因?yàn)槠渚哂袠I(yè)務(wù) 解耦、非實(shí)時(shí)業(yè)務(wù)削峰等特性。Redis提供了發(fā)布訂閱功能和阻塞隊(duì)列的功 能,雖然和專(zhuān)業(yè)的消息隊(duì)列比還不夠足夠強(qiáng)大,但是對(duì)于一般的消息隊(duì)列功 能基本可以滿(mǎn)足。比如在分布式爬蟲(chóng)系統(tǒng)中,使用 redis 來(lái)統(tǒng)一管理 url隊(duì)列。
- 分布式鎖:在分布式服務(wù)中。可以利用Redis的setnx功能來(lái)編寫(xiě)分布式的鎖,雖然這個(gè)可能不是太常用。
當(dāng)然還有諸如排行榜、點(diǎn)贊功能都可以使用 Redis 來(lái)實(shí)現(xiàn),但是 Redis 也不是什么都可以做,比如數(shù)據(jù)量特別大時(shí),不適合 Redis,我們知道 Redis 是基于內(nèi)存的,雖然內(nèi)存很便宜,但是如果你每天的數(shù)據(jù)量特別大,比如幾億條的用戶(hù)行為日志數(shù)據(jù),用 Redis 來(lái)存儲(chǔ)的話(huà),成本相當(dāng)?shù)母摺?/p>
2、單線(xiàn)程的 Redis 為什么這么快?
Redis 有多快?官方給出的答案是讀寫(xiě)速度 10萬(wàn)/秒,如果說(shuō)這是在單線(xiàn)程情況下跑出來(lái)的成績(jī),你會(huì)不會(huì)驚訝?為什么單線(xiàn)程的 Redis 速度這么快?原因有以下幾點(diǎn):
- 純內(nèi)存操作:Redis 是完全基于內(nèi)存的,所以讀寫(xiě)效率非常的高,當(dāng)然 Redis 存在持久化操作,在持久化操作是都是 fork 子進(jìn)程和利用 Linux 系統(tǒng)的頁(yè)緩存技術(shù)來(lái)完成,并不會(huì)影響 Redis 的性能。
- 單線(xiàn)程操作:?jiǎn)尉€(xiàn)程并不是壞事,單線(xiàn)程可以避免了頻繁的上下文切換,頻繁的上下文切換也會(huì)影響性能的。
- 合理高效的數(shù)據(jù)結(jié)構(gòu)
- 采用了非阻塞 I/O 多路復(fù)用機(jī)制:多路I/O復(fù)用模型是利用 select、poll、epoll 可以同時(shí)監(jiān)察多個(gè)流的 I/O 事件的能力,在空閑的時(shí)候,會(huì)把當(dāng)前線(xiàn)程阻塞掉,當(dāng)有一個(gè)或多個(gè)流有 I/O 事件時(shí),就從阻塞態(tài)中喚醒,于是程序就會(huì)輪詢(xún)一遍所有的流(epoll 是只輪詢(xún)那些真正發(fā)出了事件的流),并且只依次順序的處理就緒的流,這種做法就避免了大量的無(wú)用操作。
3、說(shuō)說(shuō) Redis 的數(shù)據(jù)結(jié)構(gòu)及使用場(chǎng)景
Redis 提供了 5種數(shù)據(jù)結(jié)構(gòu),每一種數(shù)據(jù)結(jié)構(gòu)有各種的使用場(chǎng)景。
1、String 字符串
字符串類(lèi)型是 Redis 最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),首先鍵都是字符串類(lèi)型,而且 其他幾種數(shù)據(jù)結(jié)構(gòu)都是在字符串類(lèi)型基礎(chǔ)上構(gòu)建的,我們常使用的 set key value 命令就是字符串。常用在緩存、計(jì)數(shù)、共享Session、限速等。
2、Hash 哈希
在Redis中,哈希類(lèi)型是指鍵值本身又是一個(gè)鍵值對(duì) 結(jié)構(gòu),形如value={{field1,value1},...{fieldN,valueN}},添加命令:hset key field value。哈希可以用來(lái)存放用戶(hù)信息,比如實(shí)現(xiàn)購(gòu)物車(chē)
3、List 列表
列表(list)類(lèi)型是用來(lái)存儲(chǔ)多個(gè)有序的字符串。可以做簡(jiǎn)單的消息隊(duì)列的功能。另外,可以利用 lrange 命令,做基于 Redis的分頁(yè)功能,性能極佳,用戶(hù)體驗(yàn)好。
4、Set 集合
集合(set)類(lèi)型也是用來(lái)保存多個(gè)的字符串元素,但和列表類(lèi)型不一 樣的是,集合中不允許有重復(fù)元素,并且集合中的元素是無(wú)序的,不能通過(guò) 索引下標(biāo)獲取元素。利用 Set 的交集、并集、差集等操作,可以計(jì)算共同喜好,全部的喜好,自己獨(dú)有的喜好等功能。
5、Sorted Set 有序集合
Sorted Set 多了一個(gè)權(quán)重參數(shù) Score,集合中的元素能夠按 Score 進(jìn)行排列。可以做排行榜應(yīng)用,取 TOP N 操作
4、說(shuō)一說(shuō) Redis 的數(shù)據(jù)過(guò)期淘汰策略
先給大家一個(gè)結(jié)論,Redis 中數(shù)據(jù)過(guò)期策略采用定期刪除+惰性刪除策略。
1、定期刪除、惰性刪除策略是什么?
- 定期刪除策略:Redis 啟用一個(gè)定時(shí)器定時(shí)監(jiān)視所有的 key,判斷key是否過(guò)期,過(guò)期的話(huà)就刪除。這種策略可以保證過(guò)期的 key 最終都會(huì)被刪除,但是也存在嚴(yán)重的缺點(diǎn):每次都遍歷內(nèi)存中所有的數(shù)據(jù),非常消耗 CPU 資源,并且當(dāng) key 已過(guò)期,但是定時(shí)器還處于未喚起狀態(tài),這段時(shí)間內(nèi) key 仍然可以用。
- 惰性刪除策略:在獲取 key 時(shí),先判斷 key 是否過(guò)期,如果過(guò)期則刪除。這種方式存在一個(gè)缺點(diǎn):如果這個(gè) key 一直未被使用,那么它一直在內(nèi)存中,其實(shí)它已經(jīng)過(guò)期了,會(huì)浪費(fèi)大量的空間。
2、定期刪除+惰性刪除策略是如何工作的?
這兩種策略天然的互補(bǔ),結(jié)合起來(lái)之后,定時(shí)刪除策略就發(fā)生了一些改變,不在是每次掃描全部的 key 了,而是隨機(jī)抽取一部分 key 進(jìn)行檢查,這樣就降低了對(duì) CPU 資源的損耗,惰性刪除策略互補(bǔ)了為檢查到的key,基本上滿(mǎn)足了所有要求。但是有時(shí)候就是那么的巧,既沒(méi)有被定時(shí)器抽取到,又沒(méi)有被使用,這些數(shù)據(jù)又如何從內(nèi)存中消失?沒(méi)關(guān)系,還有內(nèi)存淘汰機(jī)制,當(dāng)內(nèi)存不夠用時(shí),內(nèi)存淘汰機(jī)制就會(huì)上場(chǎng)。Redis 內(nèi)存淘汰機(jī)制有以下幾種策略:
- noeviction:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),新寫(xiě)入操作會(huì)報(bào)錯(cuò)。(Redis 默認(rèn)策略)
- allkeys-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在鍵空間中,移除最近最少使用的 Key。(推薦使用)
- allkeys-random:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在鍵空間中,隨機(jī)移除某個(gè) Key。
- volatile-lru:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中,移除最近最少使用的 Key。這種情況一般是把 Redis 既當(dāng)緩存,又做持久化存儲(chǔ)的時(shí)候才用。
- volatile-random:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中,隨機(jī)移除某個(gè) Key。
- volatile-ttl:當(dāng)內(nèi)存不足以容納新寫(xiě)入數(shù)據(jù)時(shí),在設(shè)置了過(guò)期時(shí)間的鍵空間中,有更早過(guò)期時(shí)間的 Key 優(yōu)先移除。
修改內(nèi)存淘汰機(jī)制只需要在 redis.conf 配置文件中配置 maxmemory-policy 參數(shù)即可。
5、如何解決 Redis 緩存穿透和緩存雪崩問(wèn)題
緩存雪崩: 由于緩存層承載著大量請(qǐng)求,有效地 保護(hù)了存儲(chǔ)層,但是如果緩存層由于某些原因不能提供服務(wù),比如 Redis 節(jié)點(diǎn)掛掉了,熱點(diǎn) key 全部失效了,在這些情況下,所有的請(qǐng)求都會(huì)直接請(qǐng)求到數(shù)據(jù)庫(kù),可能會(huì)造成數(shù)據(jù)庫(kù)宕機(jī)的情況。
預(yù)防和解決緩存雪崩問(wèn)題,可以從以下三個(gè)方面進(jìn)行著手:
1、使用 Redis 高可用架構(gòu):使用 Redis 集群來(lái)保證 Redis 服務(wù)不會(huì)掛掉
2、緩存時(shí)間不一致: 給緩存的失效時(shí)間,加上一個(gè)隨機(jī)值,避免集體失效
3、限流降級(jí)策略:有一定的備案,比如個(gè)性推薦服務(wù)不可用了,換成熱點(diǎn)數(shù)據(jù)推薦服務(wù)
緩存穿透: 緩存穿透是指查詢(xún)一個(gè)根本不存在的數(shù)據(jù),這樣的數(shù)據(jù)肯定不在緩存中,這會(huì)導(dǎo)致請(qǐng)求全部落到數(shù)據(jù)庫(kù)上,有可能出現(xiàn)數(shù)據(jù)庫(kù)宕機(jī)的情況。
預(yù)防和解決緩存穿透問(wèn)題,可以考慮以下兩種方法:
1、緩存空對(duì)象: 將空值緩存起來(lái),但是這樣就有一個(gè)問(wèn)題,大量無(wú)效的空值將占用空間,非常浪費(fèi)。
2、布隆過(guò)濾器攔截: 將所有可能的查詢(xún)key 先映射到布隆過(guò)濾器中,查詢(xún)時(shí)先判斷key是否存在布隆過(guò)濾器中,存在才繼續(xù)向下執(zhí)行,如果不存在,則直接返回。布隆過(guò)濾器有一定的誤判,所以需要你的業(yè)務(wù)允許一定的容錯(cuò)性。



























