必知必會 | 關於Redis緩存這三大問題,必知必會



HI!我是小小,咱們昨天沒有見面,是由於昨天小小一天都在火車上呆,準備去廣州的考試,因此脫稿一天,不過今天,小小的小blog已經開始恢復更新了。web

彙報一下進度

小小今天坐車路過武漢,武漢武昌的一張路過照片。redis

下面開始今天的正文,看見小小怎麼辛苦的份上,滑到底下,給個素質三連?數據庫


緩存雪崩

緩存雪崩是指在某一個時間段內,緩存集中過時失效,若是這個時間段內有大量請求,而查詢數據量巨大,全部的請求都會達到存儲層,存儲層的調用量會暴增,引發數據庫壓力過大甚至宕機。數組

緣由

  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)不一樣的過時時間

設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻。

緩存穿透

什麼是緩存穿透,當用戶在查詢一條數據的時候,而此時數據庫和緩存沒有任何關於這條數據的任何記錄的時候,當這條數據再緩存中沒找到數據,就會向數據庫請求數據,這樣就會對數據庫形成比較大的壓力。如:用戶查詢一個 id = -1 的商品信息,通常數據庫 id 值都是從 1 開始自增,很明顯這條信息是不在數據庫中,當沒有信息返回時,會一直向數據庫查詢,給當前數據庫的形成很大的訪問壓力。解決方案有倆個,分別爲緩存空對象,布隆過濾器。

緩存空對象

緩存空對象它就是指一個請求發送過來,若是此時緩存中和數據庫都不存在這個請求所要查詢的相關信息,那麼數據庫就會返回一個空對象,並將這個空對象和請求關聯起來存到緩存中,當下次仍是這個請求過來的時候,這時緩存就會命中,就直接從緩存中返回這個空對象,這樣能夠減小訪問數據庫的壓力,提升當前數據庫的訪問性能。咱們接下來能夠看下面這個流程而且爲了大量的空對象過多,致使緩存空對象也過多,因此須要利用Redis的過時機制,解決這個問題。

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

在Java中

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 是不在的)。

提升準確率

  1. 哈希函數的好壞
  2. 存儲空間大小
  3. 哈希函數個數 hash函數的設計也是一個十分重要的問題,對於好的hash函數能大大下降布隆過濾器的誤判率。同時,對於一個布隆過濾器來講,若是其位數組越大的話,那麼每一個key經過hash函數映射的位置會變得稀疏許多,不會那麼緊湊,有利於提升布隆過濾器的準確率。同時,對於一個布隆過濾器來講,若是key經過許多hash函數映射,那麼在位數組上就會有許多位置有標誌,這樣當用戶查詢的時候,在經過布隆過濾器來找的時候,誤判率也會相應下降。

緩存擊穿

一個被常常訪問而且查詢到的key,常常有用戶訪問,可是這個時候,這個key正好到了失效時間,或者忽然變成冷門key,此時仍然有大量的關於這個的key的請求,這樣會形成大量的併發訪問到數據庫,形成數據庫的壓力劇增。致使緩存擊穿的產生。

緣由有兩條。

  1.  一個冷門的key,忽然有大量的用戶請求訪問。

  2. 一個熱門的key剛好到了過時的時間。

緩存擊穿問題的解決: 加鎖,對於key過時的時候,查詢數據庫的時候加鎖,可讓只有一個鏈接訪問到數據庫,而後獲取到key緩存到redis中,減小了緩存的壓力。在單機幻覺使用單機的鎖,在分佈式環境下使用分佈式鎖。


關於做者

一個生於二線,生存在一線的程序猿,佛系生活,佛系度日,我是小小,咱們下期再見。

小明菜市場

推薦閱讀

● 必備收藏 |詳解 | 求你別用效率低下的I/O了,要不試試這種I/O

● 明瞭 | 看了這篇文章,多年不能理解的分佈式事物,終於看懂了!

● 推薦 | 做爲IDEA的死忠粉,這樣設置,效果棒棒噠!

● 異常 | 求你別再寫滿屏的try-catch了,用全局異常好嗎?- 夾私貨-行測

● 探討 | 深刻探討Redis管道

給我個好看再走好嗎?


本文分享自微信公衆號 - 小明菜市場(fileGeek)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索