Java非關係型數據庫Redis相關面試題

1、Redis常見數據結構

String字符串、Hash、List、Set、Zset

2、zset的底層實現

ziplist/skiplist
參考

3、持久化方案

  • RDB:默認,週期性的保存快照方式
  • AOF:對每條寫入命令作爲日誌記錄,以append-only模式寫入日誌文件。

參考

4、rehash

rehash是指對hash表進行擴容或收縮。爲了讓哈希表的負載因子(load factor)維持在一個合理的範圍之內, 當哈希表保存的鍵值對數量太多或者太少時, 程序需要對哈希表的大小進行相應的擴展或者收縮。
參考

5、Redis事務的特點

Redis學習二:事務

6、爲什麼單線程的Redis可達到10萬+的QPS?

(一)純內存操作
(二)單線程操作,避免了頻繁的上下文切換
(三)採用了非阻塞I/O多路複用機制

7、Redis的線程模型

經典圖
在這裏插入圖片描述
參考

8、redis的過期策略以及內存淘汰機制

過期策略
定期刪除+惰性刪除策略
定期刪除:指的是redis默認是每隔100ms就隨機抽取一些設置了過期時間的key,檢查其是否過期,如果過期就刪除
惰性刪除:在你獲取某個key的時候,redis會檢查一下 ,這個key如果設置了過期時間那麼是否過期了,如果過期了此時就會刪除,不會給你返回任何東西。

內存淘汰機制
爲什麼還需要內存淘汰機制:
如果定期刪除沒刪除key。然後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會越來越高。那麼就應該採用內存淘汰機制。
在這裏插入圖片描述
參考

9、redis的hash槽

參考1
參考2
Redis集羣介紹
一致性哈希與哈希槽

10、redis如何實現延時隊列?

使用zset,以時間戳爲score,是zadd生產任務,使用zrangebyscore消費任務。

11、緩存雪崩、緩存穿透、緩存預熱、緩存更新、緩存降級等問題

(1)緩存雪崩:某一時刻存在大量的緩存更新或者過期等導致緩存命中失效,從而導致所有請求都去查數據庫,導致數據庫CPU和內存負載過高,甚至宕機。
在這裏插入圖片描述
解決方案:

  • 通過設置不同的過期時間,來錯開緩存過期,從而避免緩存集中失效,這樣子,我們就可以將緩存過期時間均勻地分佈在時間軸上,避免緩存同時失效、更新的情況發生。
  • 從應用架構角度,我們可以通過限流、熔斷等手段來降低影響,也可以通過多級緩存來避免這種災難。
    限流方案:
    在這裏插入圖片描述
    用戶發送一個請求,系統 A 收到請求後,先查本地 ehcache 緩存,如果沒查到再查 redis。如果 ehcache 和 redis 都沒有,再查數據庫,
    將數據庫中的結果,寫入 ehcache 和 redis 中。
    限流組件,可以設置每秒的請求,有多少能通過組件,剩餘的未通過的請求,怎麼辦?走降級!可以返回一些默認的值,或者友情提示,或者
    空白的值。
    好處:
    數據庫絕對不會死,限流組件確保了每秒只有多少個請求能通過。
    只要數據庫不死,就是說,對用戶來說,2/5 的請求都是可以被處理的。
    只要有 2/5 的請求可以被處理,就意味着你的系統沒死,對用戶來說,可能就是點擊幾次刷不出來頁面,但是多點幾次,就可以刷出來一次。

(2)緩存穿透
在高併發場景下,如果某一個key被高併發訪問,沒有被命中,出於對容錯性考慮,會嘗試去從後端數據庫中獲取,從而導致了大量請求達到數據庫,而當該key對應的數據本身就是空的情況下,這就導致數據庫中併發的去執行了很多不必要的查詢操作,從而導致巨大沖擊和壓力。很容易被黑客利用來攻擊。
解決方案:
對所有可能對應數據不爲空的key進行統一的存放,並在請求前做攔截,這樣避免請求穿透到後端數據庫。

布隆過濾器是一個集合數據結構類似於ArrayList,它就一個最主要的方法,判斷是否包含(用於確定某個特定元素是否包含在一組元素中)。
其優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率。因此Bloom Filter不適合那些“零錯誤”的應用
場合,適用於能容忍低錯誤率的應用場合。
(3)緩存擊穿:
緩存擊穿,就是說某個 key 非常熱點,訪問非常頻繁,處於集中式高併發訪問的情況,當這個 key 在失效的瞬間,大量的請求就擊穿了緩存,直接請求數據庫,就像是在一道屏障上鑿開了一個洞。
解決方案:
可以將熱點數據設置爲永遠不過期;或者基於 redis or zookeeper 實現互斥鎖,等待第一個請求構建完緩存之後,再釋放鎖,進而其它請求才能通過該 key 訪問數據。
參考

12、Redis如何解決鍵衝突

鏈地址法

13、Redis存在線程安全問題嗎?

當然存在。redis只能保證單條命令的原子性,要麼失敗要麼成功,但是無法保證多條命令的原子性,即使是使用事務,也只能保證命令的順序和隔離性,事務中其中一條失敗後依然會繼續執行。
解決辦法:
(1)redis中也有CAS(check-and-set)機制,使用watch命令做自旋鎖
(2)加鎖

14、redis集羣的一致性hash算法

參考

15、Redis做緩存時如何保證數據一致性

使用Redis做緩存,必然存在的一個問題就是更新數據的時候需要同步更新數據庫和Redis,若是其中一個更新失敗,一個成功則可能導致數據不一致。
強一致性的解決方案:
(1)爲數據庫更新操作添加事務控制,更新數據成功後,刪除緩存。
實現簡單,缺點是刪除緩存後,如果有多個查詢請求併發過來,都發現緩存中沒數據,都會將請求落到數據庫上,導致數據庫壓力瞬間增加。
(2)爲數據庫更新操作添加事務控制,更新數據成功後,同步更新緩存。
這是對刪除方式的改進,但也有缺點,寫入前要多一次查詢,在部分場景下是沒法使用的,比如修改的數據牽扯到多個緩存,自然無法主動寫入,只能等緩存失效。

最終一致性解決方案:
(1)MQ異步刷新、定時刷新
採用MQ異步消息機制刷新,如果更新失敗要有適當的補償機制。
所有需要更新的對象存儲到一張定時任務表,定時任務掃描任務表異步更新。
這兩種更新機制不能保證查詢緩存同DB的一致性,但是能夠保證最終一致性。
(2)自動失效
合理設置緩存失效時間,需根據業務場景設置每個緩存的失效時間,一致性要求越高,自然失效時間也要越短。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章