Redis緩存那點破事 | 絕殺面試官 25 問!
時間:2021-10-21 14:37:34
手機看文章
掃描二維碼
隨時隨地手機看文章
[導(dǎo)讀]為了便于大家查找問題,了解全貌,整理個目錄,我們可以快速全局了解關(guān)于Redis緩存,面試官一般喜歡問哪些問題?接下來,我們逐條來看看每個問題及答案Redis有哪些特性?答案:性能高,讀的速度是100000次/s,寫的速度是80000次/s數(shù)據(jù)持久化,支持RDB、AOF支持事務(wù)。通...
為了便于大家查找問題,了解全貌,整理個目錄,我們可以快速全局了解關(guān)于Redis 緩存,面試官一般喜歡問哪些問題?
接下來,我們逐條來看看每個問題及答案
Redis 有哪些特性?答案:
Redis 為什么這么快?答案:
Redis 底層的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)有哪些?答案:
Redis 支持哪些數(shù)據(jù)類型?答案:五種常用數(shù)據(jù)類型:
Redis 常用的 5 種數(shù)據(jù)結(jié)構(gòu)和應(yīng)用場景?答案:
為什么采用單線程?答案:官方回復(fù),CPU不會成為Redis的制約瓶頸,Redis主要受內(nèi)存、網(wǎng)絡(luò)限制。例如,在一個普通的 Linux 系統(tǒng)上,使用pipelining 可以每秒傳遞 100 萬個請求,所以如果您的應(yīng)用程序主要使用 O(N) 或 O(log(N)) 命令,則幾乎不會使用太多 CPU,屬于IO密集型系統(tǒng)。
Redis 6.0 之后又改用多線程呢?答案:Redis的多線程主要是處理數(shù)據(jù)的讀寫、協(xié)議解析。執(zhí)行命令還是采用單線程順序執(zhí)行。主要是因為redis的性能瓶頸在于網(wǎng)絡(luò)IO而非CPU,使用多線程進行一些周邊預(yù)處理,提升了IO的讀寫效率,從而提高了整體的吞吐量。antirez 在 RedisConf 2019 分享時提到,Redis 6 引入的多線程 IO 對性能提升至少一倍以上。
過期鍵Key 的刪除策略有哪些?答案:有3種過期刪除策略。惰性刪除、定期刪除、定時刪除
如果Redis的內(nèi)存空間不足,淘汰機制?答案:
Redis 突然掛了怎么解決?答案:1、從系統(tǒng)可用性角度思考,Redis Cluster引入主備機制,當主節(jié)點掛了后,自動切換到備用節(jié)點,繼續(xù)提供服務(wù)。2、Client端引入本地緩存,通過開關(guān)切換,避免Redis突然掛掉,高并發(fā)流量把數(shù)據(jù)庫打掛。
Redis 持久化有哪些方式?答案:1、快照RDB。將某個時間點上的數(shù)據(jù)庫狀態(tài)保存到
Redis 常用場景答案:
Redis 緩存要注意的七大經(jīng)典問題?答案:列舉了億級系統(tǒng),高訪問量情況下Redis緩存可能會遇到哪些問題?以及對應(yīng)的解決方案。
Redis 集群方案有哪幾種?答案:
Redis 主從數(shù)據(jù)同步(主從復(fù)制)的過程?答案:
主從復(fù)制的優(yōu)缺點?答案:1、優(yōu)點:
Sentinel(哨兵)模式的優(yōu)缺點?答案:哨兵模式基于主從復(fù)制模式,增加了哨兵來監(jiān)控與自動處理故障。1、優(yōu)點:
Redis Cluster 模式的優(yōu)缺點?答案:實現(xiàn)了Redis的分布式存儲,即每臺節(jié)點存儲不同的內(nèi)容,來解決在線擴容的問題。1、優(yōu)點:
Redis 如何做擴容?答案:為了避免數(shù)據(jù)遷移失效,通常使用
Redis 的集群原理?答案:一個redis集群由多個節(jié)點node組成,而多個node之間通過
Redis 如何做到高可用?答案:哨兵機制。具有自動故障轉(zhuǎn)移、集群監(jiān)控、消息通知等功能。哨兵可以同時監(jiān)視所有的主、從服務(wù)器,當某個master下線時,自動提升對應(yīng)的slave為master,然后由新master對外提供服務(wù)。
什么是 Redis 事務(wù)?答案:Redis事務(wù)是一組命令的集合,將多個命令打包,然后把這些命令按順序添加到隊列中,并且按順序執(zhí)行這些命令。Redis事務(wù)中沒有像Mysql關(guān)系型數(shù)據(jù)庫事務(wù)隔離級別的概念,不能保證原子性操作,也沒有像Mysql那樣執(zhí)行事務(wù)失敗會進行回滾操作
Redis 事務(wù)執(zhí)行流程?答案:通過
Redis 與 Guava 、Caffeine 有什么區(qū)別?答案:緩存分為本地緩存和分布式緩存。1、Caffeine、Guava,屬于本地緩存,特點:
如何實現(xiàn)一個分布式鎖?答案:
接下來,我們逐條來看看每個問題及答案
Redis 有哪些特性?答案:
- 性能高, 讀的速度是100000次/s,寫的速度是80000次/s
- 數(shù)據(jù)持久化,支持RDB 、AOF
- 支持事務(wù)。通過
MULTI
和EXEC
指令包起來。 - 多種數(shù)據(jù)結(jié)構(gòu)類型
- 主從復(fù)制
- 其他特性:發(fā)布/訂閱、通知、key過期等
Redis 為什么這么快?答案:
- 完全基于內(nèi)存,沒有磁盤IO上的開銷,異步持久化除外
- 單線程,避免多個線程切換的性能損耗
- 非阻塞的IO多路復(fù)用機制
- 底層的數(shù)據(jù)存儲結(jié)構(gòu)優(yōu)化,使用原生的數(shù)據(jù)結(jié)構(gòu)提升性能。
Redis 底層的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)有哪些?答案:
- 字符串。沒有采用C語言的傳統(tǒng)字符串,而是自己實現(xiàn)的一個簡單動態(tài)字符串SDS的抽象類型,并保存了長度信息。
- 鏈表(linkedlist)。雙向無環(huán)鏈表結(jié)構(gòu),每個鏈表的節(jié)點由一個listNode結(jié)構(gòu)來表示,每個節(jié)點都有前置和后置節(jié)點的指針
- 字典(hashtable)。保存鍵值對的抽象數(shù)據(jù)結(jié)構(gòu),底層使用hash表,每個字典帶有兩個hash表,供平時使用和rehash時使用。
- 跳躍表(skiplist)。跳躍表是有序集合的底層實現(xiàn)之一。redis跳躍表由zskiplist和zskiplistNode組成,zskiplist用于保存跳躍表 信息(表頭、表尾節(jié)點、?度等),zskiplistNode用于表示表跳躍節(jié)點,每個跳躍表的層高都是1- 32的隨機數(shù),在同一個跳躍表中,多個節(jié)點可以包含相同的分值,但是每個節(jié)點的成員對象必須是唯一的,節(jié)點按照分值大小排序,如果分值相同,則按照成員對象的大小排序。
- 整數(shù)集合(intset)。用于保存整數(shù)值的集合抽象數(shù)據(jù)結(jié)構(gòu),不會出現(xiàn)重復(fù)元素,底層實現(xiàn)為數(shù)組。
- 壓縮列表(ziplist)。為節(jié)約內(nèi)存而開發(fā)的順序性數(shù)據(jù)結(jié)構(gòu),可以包含多個節(jié)點,每個節(jié)點可以保存一個字節(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ù)類型。- 字符串對象string:int整數(shù)、embstr編碼的簡單動態(tài)字符串、raw簡單動態(tài)字符串
- 列表對象list:ziplist、linkedlist
- 哈希對象hash:ziplist、hashtable
- 集合對象set:intset、hashtable
- 有序集合對象zset:ziplist、skiplist
Redis 常用的 5 種數(shù)據(jù)結(jié)構(gòu)和應(yīng)用場景?答案:
- String:緩存、計數(shù)器、分布式鎖等
- List:鏈表、隊列、微博關(guān)注人時間軸列表等
- Hash:用戶信息、Hash 表等
- Set:去重、贊、踩、共同好友等
- Zset:訪問量排行榜、點擊量排行榜等
為什么采用單線程?答案:官方回復(fù),CPU不會成為Redis的制約瓶頸,Redis主要受內(nèi)存、網(wǎng)絡(luò)限制。例如,在一個普通的 Linux 系統(tǒng)上,使用pipelining 可以每秒傳遞 100 萬個請求,所以如果您的應(yīng)用程序主要使用 O(N) 或 O(log(N)) 命令,則幾乎不會使用太多 CPU,屬于IO密集型系統(tǒng)。
Redis 6.0 之后又改用多線程呢?答案:Redis的多線程主要是處理數(shù)據(jù)的讀寫、協(xié)議解析。執(zhí)行命令還是采用單線程順序執(zhí)行。主要是因為redis的性能瓶頸在于網(wǎng)絡(luò)IO而非CPU,使用多線程進行一些周邊預(yù)處理,提升了IO的讀寫效率,從而提高了整體的吞吐量。antirez 在 RedisConf 2019 分享時提到,Redis 6 引入的多線程 IO 對性能提升至少一倍以上。
過期鍵Key 的刪除策略有哪些?答案:有3種過期刪除策略。惰性刪除、定期刪除、定時刪除
- 惰性刪除。使用key時才進行檢查,如果已經(jīng)過期,則刪除。缺點:過期的key如果沒有被訪問到,一直無法刪除,一直占用內(nèi)存,造成空間浪費。
- 定期刪除。每隔一段時間做一次檢查,刪除過期的key,每次只是隨機取一些key去檢查。
- 定時刪除。為每個key設(shè)置過期時間,同時創(chuàng)建一個定時器。一旦到期,立即執(zhí)行刪除。缺點:如果過期鍵比較多時,占用CPU較多,對服務(wù)的性能有很大影響。
如果Redis的內(nèi)存空間不足,淘汰機制?答案:
- volatile-lru:從已設(shè)置過期時間的key中,移出最近最少使用的key進行淘汰
- allkeys-lru:當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的key(這個是最常用的)
- volatile-ttl:從已設(shè)置過期時間的key中,移出將要過期的key
- volatile-random:從已設(shè)置過期時間的key中,隨機選擇key淘汰
- allkeys-random:從key中隨機選擇key進行淘汰
- no-eviction:禁止淘汰數(shù)據(jù)。當內(nèi)存達到閾值的時候,新寫入操作報錯
- volatile-lfu:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰(LFU(Least Frequently Used)算法,也就是最頻繁被訪問的數(shù)據(jù)將來最有可能被訪問到)
- allkeys-lfu:當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最不經(jīng)常使用的key。
Redis 突然掛了怎么解決?答案:1、從系統(tǒng)可用性角度思考,Redis Cluster引入主備機制,當主節(jié)點掛了后,自動切換到備用節(jié)點,繼續(xù)提供服務(wù)。2、Client端引入本地緩存,通過開關(guān)切換,避免Redis突然掛掉,高并發(fā)流量把數(shù)據(jù)庫打掛。
Redis 持久化有哪些方式?答案:1、快照RDB。將某個時間點上的數(shù)據(jù)庫狀態(tài)保存到
RDB文件
中,RDB文件是一個壓縮的二進制文件,保存在磁盤上。當Redis崩潰時,可用于恢復(fù)數(shù)據(jù)。通過SAVE
或BGSAVE
來生成RDB文件。- SAVE:會阻塞redis進程,直到RDB文件創(chuàng)建完畢,在進程阻塞期間,redis不能處理任何命令請求。
- BGSAVE:會fork出一個子進程,然后由子進程去負責生成RDB文件,父進程還可以繼續(xù)處理命令請求,不會阻塞進程。
Redis 常用場景答案:
- 1、緩存,有句話說的好,「性能不夠,緩存來湊」
- 2、分布式鎖,利用Redis 的 setnx
- 3、分布式session
- 4、計數(shù)器,通過incr命令
- 5、排行榜,Redis 的 有序集合
- 6、其他
Redis 緩存要注意的七大經(jīng)典問題?答案:列舉了億級系統(tǒng),高訪問量情況下Redis緩存可能會遇到哪些問題?以及對應(yīng)的解決方案。
- 1、緩存集中失效
- 2、緩存穿透
- 3、緩存雪崩
- 4、緩存熱點
- 5、緩存大Key
- 6、緩存數(shù)據(jù)的一致性
- 7、數(shù)據(jù)并發(fā)競爭預(yù)熱
Redis 集群方案有哪幾種?答案:
- 主從復(fù)制模式
- Sentinel(哨兵)模式
- Redis Cluster模式
Redis 主從數(shù)據(jù)同步(主從復(fù)制)的過程?答案:
- 1、slave啟動后,向master發(fā)送sync命令
- 2、master收到sync之后,執(zhí)行bgsave保存快照,生成RDB全量文件
- 3、master把slave的寫命令記錄到緩存
- 4、bgsave執(zhí)行完畢之后,發(fā)送RDB文件到slave,slave執(zhí)行
- 5、master發(fā)送緩沖區(qū)的寫命令給slave,slave接收命令并執(zhí)行,完成復(fù)制初始化。
- 6、此后,master每次執(zhí)行一個寫命令都會同步發(fā)送給slave,保持master與slave之間數(shù)據(jù)的一致性
主從復(fù)制的優(yōu)缺點?答案:1、優(yōu)點:
- master能自動將數(shù)據(jù)同步到slave,可以進行讀寫分離,分擔master的讀壓力
- master、slave之間的同步是以非阻塞的方式進行的,同步期間,客戶端仍然可以提交查詢或更新請求
- 不具備自動容錯與恢復(fù)功能,master 節(jié)點宕機后,需要手動指定新的 master
- master宕機,如果宕機前數(shù)據(jù)沒有同步完,則切換IP后會存在數(shù)據(jù)不一致的問題
- 難以支持在線擴容,Redis的容量受限于單機配置
Sentinel(哨兵)模式的優(yōu)缺點?答案:哨兵模式基于主從復(fù)制模式,增加了哨兵來監(jiān)控與自動處理故障。1、優(yōu)點:
- 哨兵模式基于主從復(fù)制模式,所以主從復(fù)制模式有的優(yōu)點,哨兵模式也有
- master 掛掉可以自動進行切換,系統(tǒng)可用性更高
- Redis的容量受限于單機配置
- 需要額外的資源來啟動sentinel進程
Redis Cluster 模式的優(yōu)缺點?答案:實現(xiàn)了Redis的分布式存儲,即每臺節(jié)點存儲不同的內(nèi)容,來解決在線擴容的問題。1、優(yōu)點:
- 無中心架構(gòu),數(shù)據(jù)按照slot分布在多個節(jié)點
- 集群中的每個節(jié)點都是平等的,每個節(jié)點都保存各自的數(shù)據(jù)和整個集群的狀態(tài)。每個節(jié)點都和其他所有節(jié)點連接,而且這些連接保持活躍,這樣就保證了我們只需要連接集群中的任意一個節(jié)點,就可以獲取到其他節(jié)點的數(shù)據(jù)。
- 可線性擴展到1000多個節(jié)點,節(jié)點可動態(tài)添加或刪除
- 能夠?qū)崿F(xiàn)自動故障轉(zhuǎn)移,節(jié)點之間通過
gossip協(xié)議
交換狀態(tài)信息,用投票機制完成slave到master的角色轉(zhuǎn)換
- 數(shù)據(jù)通過異步復(fù)制,不保證數(shù)據(jù)的強一致性
- slave充當 “冷備”,不對外提供讀、寫服務(wù),只作為故障轉(zhuǎn)移使用。
- 批量操作限制,目前只支持具有相同slot值的key執(zhí)行批量操作,對mset、mget、sunion等操作支持不友好
- key事務(wù)操作支持有限,只支持多key在同一節(jié)點的事務(wù)操作,多key分布在不同節(jié)點時無法使用事務(wù)功能
- 不支持多數(shù)據(jù)庫空間,一臺redis可以支持16個db,集群模式下只能使用一個,即
db 0
。Redis Cluster模式不建議使用pipeline和multi-keys操作,減少max redirect產(chǎn)生的場景。
Redis 如何做擴容?答案:為了避免數(shù)據(jù)遷移失效,通常使用
一致性哈希
實現(xiàn)動態(tài)擴容縮容,有效減少需要遷移的Key數(shù)量。但是Cluster 模式,采用固定Slot槽位方式(16384個),對每個key計算CRC16值,然后對16384取模,然后根據(jù)slot值找到目標機器,擴容時,我們只需要遷移一部分的slot到新節(jié)點即可。Redis 的集群原理?答案:一個redis集群由多個節(jié)點node組成,而多個node之間通過
cluster meet
命令來進行連接,組成一個集群。數(shù)據(jù)存儲通過分片的形式,整個集群分成了16384
個slot,每個節(jié)點負責一部分槽位。整個槽位的信息會同步到所有節(jié)點中。key與slot的映射關(guān)系:- 健值對 key,進行
CRC16
計算,計算出一個 16 bit 的值 - 將 16 bit 的值對 16384 取模,得到 0 ~ 16383 的數(shù)表示 key 對應(yīng)的哈希槽
Redis 如何做到高可用?答案:哨兵機制。具有自動故障轉(zhuǎn)移、集群監(jiān)控、消息通知等功能。哨兵可以同時監(jiān)視所有的主、從服務(wù)器,當某個master下線時,自動提升對應(yīng)的slave為master,然后由新master對外提供服務(wù)。
什么是 Redis 事務(wù)?答案:Redis事務(wù)是一組命令的集合,將多個命令打包,然后把這些命令按順序添加到隊列中,并且按順序執(zhí)行這些命令。Redis事務(wù)中沒有像Mysql關(guān)系型數(shù)據(jù)庫事務(wù)隔離級別的概念,不能保證原子性操作,也沒有像Mysql那樣執(zhí)行事務(wù)失敗會進行回滾操作
Redis 事務(wù)執(zhí)行流程?答案:通過
MULTI
、EXEC
、WATCH
等命令來實現(xiàn)事務(wù)機制,事務(wù)執(zhí)行過程將一系列多個命令按照順序一次性執(zhí)行,在執(zhí)行期間,事務(wù)不會被中斷,也不會去執(zhí)行客戶端的其他請求,直到所有命令執(zhí)行完畢。具體過程:- 服務(wù)端收到客戶端請求,事務(wù)以
MULTI
開始 - 如果正處于事務(wù)狀態(tài)時,則會把后續(xù)命令放入隊列同時返回給客戶端
QUEUED
,反之則直接執(zhí)行這 個命令 - 當收到客戶端的
EXEC
命令時,才會將隊列里的命令取出、順序執(zhí)行,執(zhí)行完將當前狀態(tài)從事務(wù)狀態(tài)改為非事務(wù)狀態(tài) - 如果收到
DISCARD
命令,放棄執(zhí)行隊列中的命令,可以理解為Mysql的回滾操作,并且將當前的狀態(tài)從事務(wù)狀態(tài)改為非事務(wù)狀態(tài)
WATCH 監(jiān)視某個key,該命令只能在MULTI命令之前執(zhí)行。如果監(jiān)視的key被其他客戶端修改,EXEC將會放棄執(zhí)行隊列中的所有命令。UNWATCH 取消監(jiān)視之前通過WATCH 命令監(jiān)視的key。通過執(zhí)行EXEC 、DISCARD 兩個命令之前監(jiān)視的key也會被取消監(jiān)視。
Redis 與 Guava 、Caffeine 有什么區(qū)別?答案:緩存分為本地緩存和分布式緩存。1、Caffeine、Guava,屬于本地緩存,特點:
- 直接訪問內(nèi)存,速度快,受內(nèi)存限制,無法進行大數(shù)據(jù)存儲。
- 無網(wǎng)絡(luò)通訊開銷,性能更高。
- 只支持本地應(yīng)用進程訪問,同步更新所有節(jié)點的本地緩存數(shù)據(jù)成本較高。
- 應(yīng)用進程重啟,數(shù)據(jù)會丟失。
- 集群模式,支持大數(shù)據(jù)量存儲
- 數(shù)據(jù)集中存儲,保證數(shù)據(jù)的一致性
- 數(shù)據(jù)跨網(wǎng)絡(luò)傳輸,性能低于本地緩存。但同一個機房,兩臺服務(wù)器之間請求跑一個來回也就需要500微秒,比起其優(yōu)勢,這點損耗完全可以忽略,這也是分布式緩存受歡迎的原因。
- 支持副本機制,有效的保證了高可用性。
如何實現(xiàn)一個分布式鎖?答案:
- 1、數(shù)據(jù)庫表,性能比較差
- 2、使用Lua腳本 (包含 SETNX EXPIRE 兩條指令)
- 3、SET的擴展命令(SET key value [EX][PX] [NX|XX])
- 4、Redlock 框架
- 5、Zookeeper Curator框架提供了現(xiàn)成的分布式鎖