溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis面試題的示例分析

發(fā)布時間:2021-04-14 10:41:03 來源:億速云 閱讀:161 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章給大家分享的是有關(guān)Redis面試題的示例分析的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

應(yīng)用場景

  • 緩存

  • 共享Session

  • 消息隊列系統(tǒng)

  • 分布式鎖

相關(guān)推薦:Redis視頻教程

單線程的Redis為什么快

  • 純內(nèi)存操作

  • 單線程操作,避免了頻繁的上下文切換

  • 合理高效的數(shù)據(jù)結(jié)構(gòu)

  • 采用了非阻塞I/O多路復(fù)用機制(有一個文件描述符同時監(jiān)聽多個文件描述符是否有數(shù)據(jù)到來)

Redis 的數(shù)據(jù)結(jié)構(gòu)及使用場景

  • String字符串:字符串類型是 Redis 最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),首先鍵都是字符串類型,而且 其他幾種數(shù)據(jù)結(jié)構(gòu)都是在字符串類型基礎(chǔ)上構(gòu)建的,我們常使用的 set key value 命令就是字符串。常用在緩存、計數(shù)、共享Session、限速等。

  • Hash哈希:在Redis中,哈希類型是指鍵值本身又是一個鍵值對結(jié)構(gòu),哈??梢杂脕泶娣庞脩粜畔?,比如實現(xiàn)購物車。

  • List列表(雙向鏈表):列表(list)類型是用來存儲多個有序的字符串。可以做簡單的消息隊列的功能。

  • Set集合:集合(set)類型也是用來保存多個的字符串元素,但和列表類型不一 樣的是,集合中不允許有重復(fù)元素,并且集合中的元素是無序的,不能通過索引下標獲取元素。利用 Set 的交集、并集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。

  • Sorted Set有序集合(跳表實現(xiàn)):Sorted Set 多了一個權(quán)重參數(shù) Score,集合中的元素能夠按 Score 進行排列??梢宰雠判邪駪?yīng)用,取 TOP N 操作。

Redis 的數(shù)據(jù)過期策略

Redis 中數(shù)據(jù)過期策略采用定期刪除+惰性刪除策略

  • 定期刪除策略:Redis 啟用一個定時器定時監(jiān)視所有的 key,判斷key是否過期,過期的話就刪除。這種策略可以保證過期的 key 最終都會被刪除,但是也存在嚴重的缺點:每次都遍歷內(nèi)存中所有的數(shù)據(jù),非常消耗 CPU 資源,并且當 key 已過期,但是定時器還處于未喚起狀態(tài),這段時間內(nèi) key 仍然可以用。

  • 惰性刪除策略:在獲取 key 時,先判斷 key 是否過期,如果過期則刪除。這種方式存在一個缺點:如果這個 key 一直未被使用,那么它一直在內(nèi)存中,其實它已經(jīng)過期了,會浪費大量的空間。

  • 這兩種策略天然的互補,結(jié)合起來之后,定時刪除策略就發(fā)生了一些改變,不再是每次掃描全部的 key 了,而是隨機抽取一部分 key 進行檢查,這樣就降低了對 CPU 資源的損耗,惰性刪除策略互補了未檢查到的key,基本上滿足了所有要求。但是有時候就是那么的巧,既沒有被定時器抽取到,又沒有被使用,這些數(shù)據(jù)又如何從內(nèi)存中消失?沒關(guān)系,還有內(nèi)存淘汰機制,當內(nèi)存不夠用時,內(nèi)存淘汰機制就會上場。淘汰策略分為:當內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報錯。(Redis 默認策略)當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的 Key。(LRU推薦使用)當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,隨機移除某個 Key。當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,移除最近最少使用的 Key。這種情況一般是把 Redis 既當緩存,又做持久化存儲的時候才用。當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,隨機移除某個 Key。當內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,有更早過期時間的 Key 優(yōu)先移除。

Redis的set和setnx

Redis中setnx不支持設(shè)置過期時間,做分布式鎖時要想避免某一客戶端中斷導(dǎo)致死鎖,需設(shè)置lock過期時間,在高并發(fā)時 setnx與 expire 不能實現(xiàn)原子操作,如果要用,得在程序代碼上顯示的加鎖。使用SET代替SETNX ,相當于SETNX+EXPIRE實現(xiàn)了原子性,不必擔(dān)心SETNX成功,EXPIRE失敗的問題。

Redis的LRU具體實現(xiàn):

傳統(tǒng)的LRU是使用棧的形式,每次都將最新使用的移入棧頂,但是用棧的形式會導(dǎo)致執(zhí)行select *的時候大量非熱點數(shù)據(jù)占領(lǐng)頭部數(shù)據(jù),所以需要改進。Redis每次按key獲取一個值的時候,都會更新value中的lru字段為當前秒級別的時間戳。Redis初始的實現(xiàn)算法很簡單,隨機從dict中取出五個key,淘汰一個lru字段值最小的。在3.0的時候,又改進了一版算法,首先第一次隨機選取的key都會放入一個pool中(pool的大小為16),pool中的key是按lru大小順序排列的。接下來每次隨機選取的keylru值必須小于pool中最小的lru才會繼續(xù)放入,直到將pool放滿。放滿之后,每次如果有新的key需要放入,需要將pool中l(wèi)ru最大的一個key取出。淘汰的時候,直接從pool中選取一個lru最小的值然后將其淘汰。

Redis如何發(fā)現(xiàn)熱點key

  • 憑借經(jīng)驗,進行預(yù)估:例如提前知道了某個活動的開啟,那么就將此Key作為熱點Key。

  • 服務(wù)端收集:在操作redis之前,加入一行代碼進行數(shù)據(jù)統(tǒng)計。

  • 抓包進行評估:Redis使用TCP協(xié)議與客戶端進行通信,通信協(xié)議采用的是RESP,所以自己寫程序監(jiān)聽端口也能進行攔截包進行解析。

  • 在proxy層,對每一個 redis 請求進行收集上報。

  • Redis自帶命令查詢:Redis4.0.4版本提供了redis-cli –hotkeys就能找出熱點Key。(如果要用Redis自帶命令查詢時,要注意需要先把內(nèi)存逐出策略設(shè)置為allkeys-lfu或者volatile-lfu,否則會返回錯誤。進入Redis中使用config set maxmemory-policy allkeys-lfu即可。)

Redis的熱點key解決方案

  • 服務(wù)端緩存:即將熱點數(shù)據(jù)緩存至服務(wù)端的內(nèi)存中.(利用Redis自帶的消息通知機制來保證Redis和服務(wù)端熱點Key的數(shù)據(jù)一致性,對于熱點Key客戶端建立一個監(jiān)聽,當熱點Key有更新操作的時候,服務(wù)端也隨之更新。)

  • 備份熱點Key:即將熱點Key+隨機數(shù),隨機分配至Redis其他節(jié)點中。這樣訪問熱點key的時候就不會全部命中到一臺機器上了。

如何解決 Redis 緩存雪崩問題

  • 使用 Redis 高可用架構(gòu):使用 Redis 集群來保證 Redis 服務(wù)不會掛掉

  • 緩存時間不一致,給緩存的失效時間,加上一個隨機值,避免集體失效

  • 限流降級策略:有一定的備案,比如個性推薦服務(wù)不可用了,換成熱點數(shù)據(jù)推薦服務(wù)

如何解決 Redis 緩存穿透問題

  • 在接口做校驗

  • 存null值(緩存擊穿加鎖,或設(shè)置不過期)

  • 布隆過濾器攔截:將所有可能的查詢key 先映射到布隆過濾器中,查詢時先判斷key是否存在布隆過濾器中,存在才繼續(xù)向下執(zhí)行,如果不存在,則直接返回。布隆過濾器將值進行多次哈希bit存儲,布隆過濾器說某個元素在,可能會被誤判。布隆過濾器說某個元素不在,那么一定不在。

Redis的持久化機制

Redis為了保證效率,數(shù)據(jù)緩存在了內(nèi)存中,但是會周期性地把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件中,以保證數(shù)據(jù)的持久化。Redis的持久化策略有兩種:

  • RDB:快照形式是直接把內(nèi)存中的數(shù)據(jù)保存到一個dump的文件中,定時保存,保存策略。當Redis需要做持久化時,Redis會fork一個子進程,子進程將數(shù)據(jù)寫到磁盤上一個臨時RDB文件中。當子進程完成寫臨時文件后,將原來的RDB替換掉。

  • AOF:把所有的對Redis的服務(wù)器進行修改的命令都存到一個文件里,命令的集合。

使用AOF做持久化,每一個寫命令都通過write函數(shù)追加到appendonly.aof中。aof的默認策略是每秒鐘fsync一次,在這種配置下,就算發(fā)生故障停機,也最多丟失一秒鐘的數(shù)據(jù)。缺點是對于相同的數(shù)據(jù)集來說,AOF的文件體積通常要大于RDB文件的體積。根據(jù)所使用的fsync策略,AOF的速度可能會慢于RDB。Redis默認是快照RDB的持久化方式。對于主從同步來說,主從剛剛連接的時候,進行全量同步(RDB);全同步結(jié)束后,進行增量同步(AOF)。

Redis的事務(wù)

  • Redis 事務(wù)的本質(zhì)是一組命令的集合。事務(wù)支持一次執(zhí)行多個命令,一個事務(wù)中所有命令都會被序列化。在事務(wù)執(zhí)行過程,會按照順序串行化執(zhí)行隊列中的命令,其他客戶端提交的命令請求不會插入到事務(wù)執(zhí)行命令序列中??偨Y(jié)說:redis事務(wù)就是一次性、順序性、排他性的執(zhí)行一個隊列中的一系列命令。

  • Redis事務(wù)沒有隔離級別的概念,批量操作在發(fā)送 EXEC 命令前被放入隊列緩存,并不會被實際執(zhí)行,也就不存在事務(wù)內(nèi)的查詢要看到事務(wù)里的更新,事務(wù)外查詢不能看到。

  • Redis中,單條命令是原子性執(zhí)行的,但事務(wù)不保證原子性,且沒有回滾。事務(wù)中任意命令執(zhí)行失敗,其余的命令仍會被執(zhí)行。

Redis事務(wù)相關(guān)命令

  • watch key1 key2 ... : 監(jiān)視一或多個key,如果在事務(wù)執(zhí)行之前,被監(jiān)視的key被其他命令改動,則事務(wù)被打斷(類似樂觀鎖)

  • multi : 標記一個事務(wù)塊的開始(queued)

  • exec : 執(zhí)行所有事務(wù)塊的命令(一旦執(zhí)行exec后,之前加的監(jiān)控鎖都會被取消掉)

  • discard : 取消事務(wù),放棄事務(wù)塊中的所有命令

  • unwatch : 取消watch對所有key的監(jiān)控

Redis和 memcached 的區(qū)別

  • 存儲方式上:memcache會把數(shù)據(jù)全部存在內(nèi)存之中,斷電后會掛掉,數(shù)據(jù)不能超過內(nèi)存大小。redis有部分數(shù)據(jù)存在硬盤上,這樣能保證數(shù)據(jù)的持久性。

  • 數(shù)據(jù)支持類型上:memcache對數(shù)據(jù)類型的支持簡單,只支持簡單的key-value,,而redis支持五種數(shù)據(jù)類型。

  • 用底層模型不同:它們之間底層實現(xiàn)方式以及與客戶端之間通信的應(yīng)用協(xié)議不一樣。redis直接自己構(gòu)建了VM機制,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費一定的時間去移動和請求。

  • value的大小:redis可以達到1GB,而memcache只有1MB。

Redis的幾種集群模式

  • 主從復(fù)制

  • 哨兵模式

  • cluster模式

Redis的哨兵模式

哨兵是一個分布式系統(tǒng),在主從復(fù)制的基礎(chǔ)上你可以在一個架構(gòu)中運行多個哨兵進程,這些進程使用流言協(xié)議來接收關(guān)于Master是否下線的信息,并使用投票協(xié)議來決定是否執(zhí)行自動故障遷移,以及選擇哪個Slave作為新的Master。

每個哨兵會向其它哨兵、master、slave定時發(fā)送消息,以確認對方是否活著,如果發(fā)現(xiàn)對方在指定時間(可配置)內(nèi)未回應(yīng),則暫時認為對方已掛(所謂的”主觀認為宕機”)。

若“哨兵群“中的多數(shù)sentinel,都報告某一master沒響應(yīng),系統(tǒng)才認為該master"徹底死亡"(即:客觀上的真正down機),通過一定的vote算法,從剩下的slave節(jié)點中,選一臺提升為master,然后自動修改相關(guān)配置。

Redis的rehash

Redis的rehash 操作并不是一次性、集中式完成的,而是分多次、漸進式地完成的,redis會維護維持一個索引計數(shù)器變量rehashidx來表示rehash的進度。

這種漸進式的 rehash 避免了集中式rehash帶來的龐大計算量和內(nèi)存操作,但是需要注意的是redis在進行rehash的時候,正常的訪問請求可能需要做多要訪問兩次hashtable(ht[0], ht[1]),例如鍵值被rehash到新ht1,則需要先訪問ht0,如果ht0中找不到,則去ht1中找。

Redis的hash表被擴展的條件

  • 哈希表中保存的key數(shù)量超過了哈希表的大小.

  • Redis服務(wù)器目前沒有在執(zhí)行BGSAVE命令(rdb)或BGREWRITEAOF命令,并且哈希表的負載因子大于等于1.

  • Redis服務(wù)器目前在執(zhí)行BGSAVE命令(rdb)或BGREWRITEAOF命令,并且哈希表的負載因子大于等于5.(負載因子=哈希表已保存節(jié)點數(shù)量 / 哈希表大小,當哈希表的負載因子小于0.1時,對哈希表執(zhí)行收縮操作。)

Redis并發(fā)競爭key的解決方案

  • 分布式鎖+時間戳

  • 利用消息隊列

Redis的管道pipeline

對于單線程阻塞式的Redis,Pipeline可以滿足批量的操作,把多個命令連續(xù)的發(fā)送給Redis Server,然后一一解析響應(yīng)結(jié)果。Pipelining可以提高批量處理性能,提升的原因主要是TCP連接中減少了“交互往返”的時間。pipeline 底層是通過把所有的操作封裝成流,redis有定義自己的出入輸出流。在 sync() 方法執(zhí)行操作,每次請求放在隊列里面,解析響應(yīng)包。

Redis與Mysql雙寫一致性方案

先更新數(shù)據(jù)庫,再刪緩存。數(shù)據(jù)庫的讀操作的速度遠快于寫操作的,所以臟數(shù)據(jù)很難出現(xiàn)??梢詫Ξ惒窖訒r刪除策略,保證讀請求完成以后,再進行刪除操作。

感謝各位的閱讀!關(guān)于“Redis面試題的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI