您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Redis面試題的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
緩存
共享Session
消息隊列系統
分布式鎖
相關推薦:Redis視頻教程
純內存操作
單線程操作,避免了頻繁的上下文切換
合理高效的數據結構
采用了非阻塞I/O多路復用機制(有一個文件描述符同時監聽多個文件描述符是否有數據到來)
String字符串:字符串類型是 Redis 最基礎的數據結構,首先鍵都是字符串類型,而且 其他幾種數據結構都是在字符串類型基礎上構建的,我們常使用的 set key value 命令就是字符串。常用在緩存、計數、共享Session、限速等。
Hash哈希:在Redis中,哈希類型是指鍵值本身又是一個鍵值對結構,哈希可以用來存放用戶信息,比如實現購物車。
List列表(雙向鏈表):列表(list)類型是用來存儲多個有序的字符串。可以做簡單的消息隊列的功能。
Set集合:集合(set)類型也是用來保存多個的字符串元素,但和列表類型不一 樣的是,集合中不允許有重復元素,并且集合中的元素是無序的,不能通過索引下標獲取元素。利用 Set 的交集、并集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。
Sorted Set有序集合(跳表實現):Sorted Set 多了一個權重參數 Score,集合中的元素能夠按 Score 進行排列。可以做排行榜應用,取 TOP N 操作。
Redis 中數據過期策略采用定期刪除+惰性刪除策略
定期刪除策略:Redis 啟用一個定時器定時監視所有的 key,判斷key是否過期,過期的話就刪除。這種策略可以保證過期的 key 最終都會被刪除,但是也存在嚴重的缺點:每次都遍歷內存中所有的數據,非常消耗 CPU 資源,并且當 key 已過期,但是定時器還處于未喚起狀態,這段時間內 key 仍然可以用。
惰性刪除策略:在獲取 key 時,先判斷 key 是否過期,如果過期則刪除。這種方式存在一個缺點:如果這個 key 一直未被使用,那么它一直在內存中,其實它已經過期了,會浪費大量的空間。
這兩種策略天然的互補,結合起來之后,定時刪除策略就發生了一些改變,不再是每次掃描全部的 key 了,而是隨機抽取一部分 key 進行檢查,這樣就降低了對 CPU 資源的損耗,惰性刪除策略互補了未檢查到的key,基本上滿足了所有要求。但是有時候就是那么的巧,既沒有被定時器抽取到,又沒有被使用,這些數據又如何從內存中消失?沒關系,還有內存淘汰機制,當內存不夠用時,內存淘汰機制就會上場。淘汰策略分為:當內存不足以容納新寫入數據時,新寫入操作會報錯。(Redis 默認策略)當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的 Key。(LRU推薦使用)當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個 Key。當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的 Key。這種情況一般是把 Redis 既當緩存,又做持久化存儲的時候才用。當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個 Key。當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的 Key 優先移除。
Redis中setnx不支持設置過期時間,做分布式鎖時要想避免某一客戶端中斷導致死鎖,需設置lock過期時間,在高并發時 setnx與 expire 不能實現原子操作,如果要用,得在程序代碼上顯示的加鎖。使用SET代替SETNX ,相當于SETNX+EXPIRE實現了原子性,不必擔心SETNX成功,EXPIRE失敗的問題。
傳統的LRU是使用棧的形式,每次都將最新使用的移入棧頂,但是用棧的形式會導致執行select *的時候大量非熱點數據占領頭部數據,所以需要改進。Redis每次按key獲取一個值的時候,都會更新value中的lru字段為當前秒級別的時間戳。Redis初始的實現算法很簡單,隨機從dict中取出五個key,淘汰一個lru字段值最小的。在3.0的時候,又改進了一版算法,首先第一次隨機選取的key都會放入一個pool中(pool的大小為16),pool中的key是按lru大小順序排列的。接下來每次隨機選取的keylru值必須小于pool中最小的lru才會繼續放入,直到將pool放滿。放滿之后,每次如果有新的key需要放入,需要將pool中lru最大的一個key取出。淘汰的時候,直接從pool中選取一個lru最小的值然后將其淘汰。
憑借經驗,進行預估:例如提前知道了某個活動的開啟,那么就將此Key作為熱點Key。
服務端收集:在操作redis之前,加入一行代碼進行數據統計。
抓包進行評估:Redis使用TCP協議與客戶端進行通信,通信協議采用的是RESP,所以自己寫程序監聽端口也能進行攔截包進行解析。
在proxy層,對每一個 redis 請求進行收集上報。
Redis自帶命令查詢:Redis4.0.4版本提供了redis-cli –hotkeys就能找出熱點Key。(如果要用Redis自帶命令查詢時,要注意需要先把內存逐出策略設置為allkeys-lfu或者volatile-lfu,否則會返回錯誤。進入Redis中使用config set maxmemory-policy allkeys-lfu即可。)
服務端緩存:即將熱點數據緩存至服務端的內存中.(利用Redis自帶的消息通知機制來保證Redis和服務端熱點Key的數據一致性,對于熱點Key客戶端建立一個監聽,當熱點Key有更新操作的時候,服務端也隨之更新。)
備份熱點Key:即將熱點Key+隨機數,隨機分配至Redis其他節點中。這樣訪問熱點key的時候就不會全部命中到一臺機器上了。
使用 Redis 高可用架構:使用 Redis 集群來保證 Redis 服務不會掛掉
緩存時間不一致,給緩存的失效時間,加上一個隨機值,避免集體失效
限流降級策略:有一定的備案,比如個性推薦服務不可用了,換成熱點數據推薦服務
在接口做校驗
存null值(緩存擊穿加鎖,或設置不過期)
布隆過濾器攔截:將所有可能的查詢key 先映射到布隆過濾器中,查詢時先判斷key是否存在布隆過濾器中,存在才繼續向下執行,如果不存在,則直接返回。布隆過濾器將值進行多次哈希bit存儲,布隆過濾器說某個元素在,可能會被誤判。布隆過濾器說某個元素不在,那么一定不在。
Redis為了保證效率,數據緩存在了內存中,但是會周期性地把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件中,以保證數據的持久化。Redis的持久化策略有兩種:
RDB:快照形式是直接把內存中的數據保存到一個dump的文件中,定時保存,保存策略。當Redis需要做持久化時,Redis會fork一個子進程,子進程將數據寫到磁盤上一個臨時RDB文件中。當子進程完成寫臨時文件后,將原來的RDB替換掉。
AOF:把所有的對Redis的服務器進行修改的命令都存到一個文件里,命令的集合。
使用AOF做持久化,每一個寫命令都通過write函數追加到appendonly.aof中。aof的默認策略是每秒鐘fsync一次,在這種配置下,就算發生故障停機,也最多丟失一秒鐘的數據。缺點是對于相同的數據集來說,AOF的文件體積通常要大于RDB文件的體積。根據所使用的fsync策略,AOF的速度可能會慢于RDB。Redis默認是快照RDB的持久化方式。對于主從同步來說,主從剛剛連接的時候,進行全量同步(RDB);全同步結束后,進行增量同步(AOF)。
Redis 事務的本質是一組命令的集合。事務支持一次執行多個命令,一個事務中所有命令都會被序列化。在事務執行過程,會按照順序串行化執行隊列中的命令,其他客戶端提交的命令請求不會插入到事務執行命令序列中。總結說:redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令。
Redis事務沒有隔離級別的概念,批量操作在發送 EXEC 命令前被放入隊列緩存,并不會被實際執行,也就不存在事務內的查詢要看到事務里的更新,事務外查詢不能看到。
Redis中,單條命令是原子性執行的,但事務不保證原子性,且沒有回滾。事務中任意命令執行失敗,其余的命令仍會被執行。
watch key1 key2 ... : 監視一或多個key,如果在事務執行之前,被監視的key被其他命令改動,則事務被打斷(類似樂觀鎖)
multi : 標記一個事務塊的開始(queued)
exec : 執行所有事務塊的命令(一旦執行exec后,之前加的監控鎖都會被取消掉)
discard : 取消事務,放棄事務塊中的所有命令
unwatch : 取消watch對所有key的監控
存儲方式上:memcache會把數據全部存在內存之中,斷電后會掛掉,數據不能超過內存大小。redis有部分數據存在硬盤上,這樣能保證數據的持久性。
數據支持類型上:memcache對數據類型的支持簡單,只支持簡單的key-value,,而redis支持五種數據類型。
用底層模型不同:它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣。redis直接自己構建了VM機制,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
value的大小:redis可以達到1GB,而memcache只有1MB。
主從復制
哨兵模式
cluster模式
哨兵是一個分布式系統,在主從復制的基礎上你可以在一個架構中運行多個哨兵進程,這些進程使用流言協議來接收關于Master是否下線的信息,并使用投票協議來決定是否執行自動故障遷移,以及選擇哪個Slave作為新的Master。
每個哨兵會向其它哨兵、master、slave定時發送消息,以確認對方是否活著,如果發現對方在指定時間(可配置)內未回應,則暫時認為對方已掛(所謂的”主觀認為宕機”)。
若“哨兵群“中的多數sentinel,都報告某一master沒響應,系統才認為該master"徹底死亡"(即:客觀上的真正down機),通過一定的vote算法,從剩下的slave節點中,選一臺提升為master,然后自動修改相關配置。
Redis的rehash 操作并不是一次性、集中式完成的,而是分多次、漸進式地完成的,redis會維護維持一個索引計數器變量rehashidx來表示rehash的進度。
這種漸進式的 rehash 避免了集中式rehash帶來的龐大計算量和內存操作,但是需要注意的是redis在進行rehash的時候,正常的訪問請求可能需要做多要訪問兩次hashtable(ht[0], ht[1]),例如鍵值被rehash到新ht1,則需要先訪問ht0,如果ht0中找不到,則去ht1中找。
哈希表中保存的key數量超過了哈希表的大小.
Redis服務器目前沒有在執行BGSAVE命令(rdb)或BGREWRITEAOF命令,并且哈希表的負載因子大于等于1.
Redis服務器目前在執行BGSAVE命令(rdb)或BGREWRITEAOF命令,并且哈希表的負載因子大于等于5.(負載因子=哈希表已保存節點數量 / 哈希表大小,當哈希表的負載因子小于0.1時,對哈希表執行收縮操作。)
分布式鎖+時間戳
利用消息隊列
對于單線程阻塞式的Redis,Pipeline可以滿足批量的操作,把多個命令連續的發送給Redis Server,然后一一解析響應結果。Pipelining可以提高批量處理性能,提升的原因主要是TCP連接中減少了“交互往返”的時間。pipeline 底層是通過把所有的操作封裝成流,redis有定義自己的出入輸出流。在 sync() 方法執行操作,每次請求放在隊列里面,解析響應包。
先更新數據庫,再刪緩存。數據庫的讀操作的速度遠快于寫操作的,所以臟數據很難出現。可以對異步延時刪除策略,保證讀請求完成以后,再進行刪除操作。
感謝各位的閱讀!關于“Redis面試題的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。