1. 程式人生 > 實用技巧 >Redis 面試一定要知道的 3 個 問題!

Redis 面試一定要知道的 3 個 問題!

作者:_BKing
地址:cnblogs.com/xiaowei123/p/13211403.html

最近都沒看Redis,現在回來溫習下,現在從Redis的三大快取開始重新探一探有多深有多淺()

讓我來開始知識的醍醐灌頂把!是時候表演真正的技術了。(嗶嗶嗶嗶....)

鐵子們,看在二哈這麼賣力的份上,如果覺得本文對你有幫助的話,請動動你的小手,比個❥(^_-)愛心推薦喲。

接下來就開始我們的Redis的三大快取問題之旅,讓我們坐上二哈的小飛船遊一遊這聖女峰。

Redis快取中有三個必須要知道概念:快取穿透、快取擊穿和快取雪崩。

快取穿透

那什麼是快取穿透,它就是指當用戶在查詢一條資料的時候,而此時資料庫和快取卻沒有關於這條資料的任何記錄,而這條資料在快取中沒找到就會向資料庫請求獲取資料。它拿不到資料時,是會一直查詢資料庫,這樣會對資料庫的訪問造成很大的壓力。

如:使用者查詢一個 id = -1 的商品資訊,一般資料庫 id 值都是從 1 開始自增,很明顯這條資訊是不在資料庫中,當沒有資訊返回時,會一直向資料庫查詢,給當前資料庫的造成很大的訪問壓力。

這時候我們要想一想,該如何解決這個問題呢?o(╥﹏╥)o

一般我們可以想到從快取開始出發,想如果我們給快取設定一個如果當前資料庫不存在的資訊,把它快取成一個空物件,返回給使用者。

_沒錯,這是一個解決方案,也就是我們常說的快取空物件(程式碼維護簡單,但是效果不是很好)。

Redis 也為我們提供了一種解決方案,那就是布隆過濾器(程式碼維護比較複雜,效果挺好的)。

那接下來,二哈先解釋下這兩種方案:

快取空物件

那什麼是快取空物件呀,二哈!別急,快取空物件它就是指一個請求傳送過來,如果此時快取中和資料庫都不存在這個請求所要查詢的相關資訊,那麼資料庫就會返回一個空物件,並將這個空物件和請求關聯起來存到快取中,當下次還是這個請求過來的時候,這時快取就會命中,就直接從快取中返回這個空物件,這樣可以減少訪問資料庫的壓力,提高當前資料庫的訪問效能。我們接下來可以看下面這個流程呀~

這時候,我們就會問了呀 ,如果大量不存在的請求過來,那麼這時候快取豈不是會快取許多空物件了嗎~~

沒錯哦!這也是使用快取空物件會導致的一個問題:如果時間一長這樣會導致快取中存在大量空物件,這樣不僅會佔用許多的記憶體空間,還會浪費許多資源呀!。那這有沒有什麼可以解決的方法呢?我們來想一想:我們可以將這些物件在一段時間之後清理下不久可以了嗎 ~

嗯嗯,沒錯!在想想 Redis 裡是不是給我們提供了有關過期時間的命令呀(),這樣我們可以在設定空物件的時間,順便設定一個過期時間,就可以解決個問題了呀!

號外號外,大家可以關注公眾號Java技術棧在後臺回覆福利可以獲取一份我整理的最新面試題資料。

setex key seconds valule:設定鍵值對的同時指定過期時間(s)

在Java 中直接呼叫 API 操作即可:

redisCache.put(Integer.toString(id), null, 60) //過期時間為 60s

布隆過濾器

布隆過濾器是不是不是一個過濾器,過濾東西的呀!哎呀,你太聰明瞭,沒錯它就是用來過濾東西的,它是一種基於概率的資料結構,主要使用愛判斷當前某個元素是否在該集合中,執行速度快。我們也可以簡單理解為是一個不怎麼精確的 set 結構(set 具有去重的效果)。

但是有個小問題是:當你使用它的 contains 方法去判斷某個物件是否存在時,它可能會誤判。也就是說布隆過濾器不是特別不精確,但是隻要引數設定的合理,它的精確度可以控制的相對足夠精確,只會有小小的誤判概率(這是可以接受的呀 ~)。當布隆過濾器說某個值存在時,這個值可能不存在;當它說不存在時,那就肯定不存在。

這裡有個典型的例子呀,來自錢大:

打個比方,當它說不認識你時,肯定就不認識;當它說見過你時,可能根本就沒見過面,不過因為你的臉跟它認識的人中某臉比較相似 (某些熟臉的係數組合),所以誤判以前見過你。

在上面的使用場景中,布隆過濾器能準確過濾掉那些已經看過的內容,那些沒有看過的新內容,它也會過濾掉極小一部分 (誤判),但是絕大多數新內容它都能準確識別。這樣就可以完全保證推薦給使用者的內容都是無重複的。

說了這麼久,那布隆過濾器到底有什麼特點呢:

特點嗎,多多來讓一個個跟你吹吹(吹到你懷疑人生(≧∇≦)ノ)

  1. 一個非常大的二進位制位陣列(陣列中只存在 0 和 1)

  2. 擁有若干個雜湊函式(Hash Function)

  3. 在空間效率和查詢效率都非常高

  4. 布隆過濾器不會提供刪除方法,在程式碼維護上比較困難。

每個布隆過濾器對應到 Redis 的資料結構裡面就是一個大型的位陣列和幾個不一樣的無偏 hash 函式。所謂無偏就是能夠把元素的 hash 值算得比較均勻。具體可以參考這篇文章:布隆過濾器到底有什麼用?

布隆過濾器中新增 key 時,會使用多個 hash 函式對 key 進行 hash 算得一個整數索引值然後對位陣列長度進行取模運算得到一個位置,每個 hash 函式都會算得一個不同的位置。再把位陣列的這幾個位置都置為 1 就完成了 add 操作。( 每一個 key 都通過若干的hash函式對映到一個巨大位陣列上,對映成功後,會在把位陣列上對應的位置改為1。)

那為什麼布隆過濾器會存在誤判率呢?

誤判嗎?人生哪有不摔跤,只要鋤頭揮得好,照樣能挖到。(咳咳咳,說偏了...)

其實它會誤判是如下這個情況:

當 key1 和 key2 對映到位陣列上的位置為 1 時,假設這時候來了個 key3,要查詢是不是在裡面,恰好 key3 對應位置也對映到了這之間,那麼布隆過濾器會認為它是存在的,這時候就會產生誤判(因為明明 key3 是不在的)。

O(∩_∩)O哈哈~,這時候你會問了:如何提高布隆過濾器的準確率呢?

要提高布隆過濾器的準確率,就要說到影響它的三個重要因素:

  1. 雜湊函式的好壞

  2. 儲存空間大小

  3. 雜湊函式個數

hash函式的設計也是一個十分重要的問題,對於好的hash函式能大大降低布隆過濾器的誤判率。

(這就好比優秀的配件之所以能夠執行這麼順暢就在於其內部設計的得當。)

同時,對於一個布隆過濾器來說,如果其位陣列越大的話,那麼每個key通過hash函式對映的位置會變得稀疏許多,不會那麼緊湊,有利於提高布隆過濾器的準確率。

同時,對於一個布隆過濾器來說,如果key通過許多hash函式對映,那麼在位陣列上就會有許多位置有標誌,這樣當用戶查詢的時候,在通過布隆過濾器來找的時候,誤判率也會相應降低。

對於其內部原理,有興趣的同學可以看看關於布隆過濾的數學知識,裡面有關於它的設計演算法和數學知識。(其實也挺簡單~)

快取擊穿

快取擊穿是指有某個key經常被查詢,經常被使用者特殊關懷,使用者非常 love 它 (),也就類比“熟客” 或者 一個key經常不被訪問。推薦閱讀:快取三大問題及解決方案

但是這時候,如果這個key在快取的過期時間失效的時候或者這是個冷門key時,這時候突然有大量有關這個key的訪問請求,這樣會導致大併發請求直接穿透快取,請求資料庫,瞬間對資料庫的訪問壓力增大。

歸納起來:造成快取擊穿的原因有兩個。

(1)一個“冷門”key,突然被大量使用者請求訪問。

(2)一個“熱門”key,在快取中時間恰好過期,這時有大量使用者來進行訪問。

對於快取擊穿的問題:我們常用的解決方案是加鎖。對於key過期的時候,當key要查詢資料庫的時候加上一把鎖,這時只能讓第一個請求進行查詢資料庫,然後把從資料庫中查詢到的值儲存到快取中,對於剩下的相同的key,可以直接從快取中獲取即可。

如果我們是在單機環境下:直接使用常用的鎖即可(如:LockSynchronized等),在分散式環境下我們可以使用分散式鎖,如:基於資料庫、基於Redis 或者 zookeeper 的分散式鎖。

快取雪崩

快取雪崩是指在某一個時間段內,快取集中過期失效,如果這個時間段內有大量請求,而查詢資料量巨大,所有的請求都會達到儲存層,儲存層的呼叫量會暴增,引起資料庫壓力過大甚至宕機。

原因:

  1. Redis突然宕機

  2. 大部分資料失效

舉個例子理解下吧:

比如我們基本上都經歷過購物狂歡節,假設商家舉辦 23:00-24:00 商品打骨折促銷活動。程式小哥哥在設計的時候,在 23:00 把商家打骨折的商品放到快取中,並通過redis的expire設定了過期時間為1小時。

這個時間段許多使用者訪問這些商品資訊、購買等等。但是剛好到了24:00點的時候,恰好還有許多使用者在訪問這些商品,這時候對這些商品的訪問都會落到資料庫上,導致資料庫要抗住巨大的壓力,稍有不慎會導致,資料庫直接宕機(over)。

當商品沒有失效的時候是這樣的:

當快取GG(失效)的時候卻是這樣的:

對於快取雪崩有以下解決方案:

(1)redis高可用

Redis有可能掛掉,多增加幾臺redis例項,(一主多從或者多主多從),這樣一臺掛掉之後其他的還可以繼續工作,其實就是搭建的叢集。

(2)限流降級

在快取失效後,通過加鎖或者佇列來控制讀資料庫寫快取的執行緒數量,對某個key只允許一個執行緒查詢資料和寫快取,其他執行緒等待。

(3)資料預熱

資料加熱的含義就是在正式部署之前,我先把可能的資料先預先訪問一遍,這樣部分可能大量訪問的資料就會載入到快取中。在即將發生大併發訪問前手動觸發載入快取不同的key。

(4)不同的過期時間

設定不同的過期時間,讓快取失效的時間點儘量均勻。

_(感興趣的小夥伴,可以幫忙點個推薦(*  ̄3)(ε ̄ _)謝謝呀,(づ ̄3 ̄)づ╭❤~愛你們)__

推薦去我的部落格閱讀更多:

1.Java JVM、集合、多執行緒、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、後端、架構、阿里巴巴等大廠最新面試題

覺得不錯,別忘了點贊+轉發哦!