【JAVA今法修真】 第四章 redis特性 擊穿雪崩!

感謝這段時間大家的支援,關注我的微訊號:南橘ryc ,回復雲小霄,就可以獲取到最新的福利靚照一張,還等什麼,趕快來加入我們吧~

「明日便是決賽了,咋只會用法器沒練過法術呢。」。

選手休息室內,一臉嫉妒的陳彥宇盯著正在擦拭(炫耀)法器的李小庚,揶揄道。

陳彥宇,通遼州可汗市人,三年前突破築基期,在去往天道劍宗的路上被凶人擄走,待醒來時已經出現在了萬法仙門裡。當時身邊站著一個聲音像極了綁架自己的凶人的人,他自稱是萬法仙門教研室主任。據那人描述當時正在行俠仗義,發現陳彥宇被邪惡的天道劍宗的邪修抓住,便怒從心生,與其大戰了三百回合,最後解救下自己,同時並且為了補償自己便強行將自己收入門下。

「你知道人與動物最大的區別是什麼嗎?」李小庚沒有理會這個未來手下敗將的挑釁。

「你知道作為資料庫類型的法器,最害怕的是什麼嗎?」陳彥宇見李小庚如此目中無人,沒有再在休息室待下去,轉頭走向擂台:「希望你回去不要被你師父打屁股。」

「額,也不是不行。」

「?」


決賽現場,因為是築基期比賽,所以來的觀眾並不多,主要分為三部分:李小庚的迷妹和少量迷弟,之前的陳彥宇和李小庚的手下敗將,還有級別不夠無法觀看結丹期比賽的鍊氣期弟子。

「李小庚師兄好帥!李小庚師兄必勝!」

「哼,要不是我當初棋差一招,今天台上的兩人之中必有我。」

「解說呢?解說快點就位,馬上開始了!」

作為傳統老牌強派,萬法仙門門派大比的基本秩序還是有的,至少不會出現什麼賣瓜子花生潛水艇之類的流動小販。

擂台上。

李小庚還是那一襲白衣(雲霄殿專屬校服),配上背後若隱若現的如羽毛般的紅白飛劍,如同天使降臨,一瞥一笑皆是畫卷。

陳彥宇那邊則顯得普通很多,普通的萬法仙門弟子服裝加上手上普通的小盒子。

望著擂台下最大的組織「李小庚後援會」,陳彥宇心中暗暗想到:「三十年河東,三十年河西,平日里只教你李小庚放火,今日我陳彥宇也要點燈!」

「李小庚,你可知JMeter?」陳彥宇舉起手中的小盒子,活脫脫就像銀角大王拿著葫蘆。

「知道怎樣,不知又怎樣?」李小庚撇了撇灰濛濛的盒子,又看了看自己背後的天使之翼,笑麻了。

「好!」陳彥宇被李小庚的囂張給震驚到了,不氣反笑:「我今日便好好給你講講什麼是JMeter。」

JMeter忽然自己漂浮在空中,陳彥宇則像是在進行鋼琴演奏一般,雙手在上面揮舞出了殘影,無數只有修真人士才能看見的電磁波從盒子上向李小庚激蕩而出。

jmeter -n -t testplan/RedisLock.jmx -l testplan/result/result.txt -e -o testplan/webreport

「不知道你用了那麼久的資料庫類法器,知不知道什麼叫擊穿、雪崩和穿透!」陳彥宇彷彿已經看見了自己的勝利。

作為一個正常的築基期弟子,參加普通的門派大比,一路打敗各殿優秀弟子終於走到了決賽,卻發現決賽的對手不僅帥的慘絕人寰,還從一開始就拿出了很多金丹真人都沒有的大殺器redis集群,對於任何人來說都是崩潰的。不過,針對這種資料庫類型的法器,陳彥宇還是有過了解的,只需要通過大量的數據擊穿對方一點,便能夠讓其超載重啟。那個時候,這個自己和小白臉就可以正面對決了,甚至法器超載還會影響對方的處理能力。

「看來你對redis的了解實在是太少了。」李小庚甚至直接背對著陳彥宇,背後紅白小劍組成的翅膀無風自動,完全無視了陳彥宇的攻擊。

一、redis解決快取雪崩、擊穿、穿透問題

1、1 快取雪崩

顧名思義,大家應該都見過雪崩,無論是現實中還是網路上。那場景,頗有種天崩地裂的感覺,而對於資料庫來說,快取雪崩,也說得上是一種天崩地裂了。

同一時間Redis快取大面積失效,那一瞬間Redis跟不存在一樣,這個時候數據直接請求到資料庫。你想想,快取的意義就是減少DB,如果快取沒有了,大量的請求還不直接打爆資料庫?

快取雪崩如何出現的?

  • 大量的快取同時失效,可能是同時間生成,同時間到期
  • 快取同時被刪除
  • 快取層出現了錯誤,不能正常工作了

解決辦法:

  • 1、批量往Redis存數據的時候,把每個KEY失效時間都增加隨機值,保證不會同時失效
  • 2、設置熱點數據永不過期,有更新操作就更新快取(但是這個方法不好,永不過期導致快取大量堆積,很多快取不一定有用)
  • 3、Redis集群部署,將熱點數據均勻分布在不同Redis庫中也能避免全部失效,避免了Redis出現問題導致快取雪崩

1、2快取擊穿

有一個Key非常熱點,在不停扛著大並發,大並發集中對這一點進行訪問,當這個Key失效的瞬間、大量並發擊穿快取,直接訪問資料庫。

其實快取擊穿,真的算不上什麼特別大的問題,畢竟不是每個公司都在同一個Key上都有那麼大的熱點,只需要設置好過期時間,穩定好Redis集群,快取擊穿不難避免。

解決辦法:

  • 1、設置熱點數據永不過期
  • 2、增加互斥鎖【簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用快取工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作並回設快取】

在我的經驗來看,設置互斥鎖顯然沒有必要,一個熱點永不過期就能解決的問題,為什麼還要用到鎖?這不是平白增加複雜度嗎?也許在特殊場景能看到,但是對於我這個小白來說,僅僅能在各位大牛的部落格里看到這個觀點。

1、3快取穿透

從名字上來看,快取擊穿和快取穿透很像,實際上頁比較像,但是既然區分了出來,自然有一些不同的地方

快取穿透的概念很簡單,用戶想要查詢一個數據,發現redis記憶體資料庫沒有,也就是快取沒有命中,於是向持久層資料庫查詢。發現也沒有,於是本次查詢失敗。當用戶很多的時候,快取都沒有命中,於是都去請求了持久層資料庫。這會給持久層資料庫造成很大的壓力,這時候就相當於出現了快取穿透。

但是,快取穿透真正要防止的是黑客。

如果一個黑客每次故意查詢一個在快取內必然不存在的數據,導致每次請求都要去存儲層去查詢,這樣快取就失去了意義。如果在大流量下資料庫可能掛掉,這也是快取擊穿。
解決辦法:

  • 1、增加參數校驗
  • 2、從網關層Nginx增加配置項,對單個IP每秒訪問次數超出閾值的拉黑處理
  • 3、Bloom Filter 能很好地防止快取穿透、他的原理也很簡單的就是利用高效的數據結構和演算法快速判斷出你這個Key是否在資料庫,不存在直接return、存在就直接去DB刷新KV再return

redis利用布隆過濾器來防止快取擊穿,主要是通過將已存在的快取放到布隆過濾器中,當黑客訪問不存在的快取時迅速返迴避免快取及DB掛掉。

1、4布隆過濾器

布隆過濾器本質上布隆過濾器是一種數據結構,比較巧妙的概率型數據結構(probabilistic data structure),特點是高效地插入和查詢,可以用來告訴你 「某樣東西一定不存在或者可能存在」。

布隆過濾器是由一個很長的bit數組和一系列哈希函數組成的。

數組的每個元素都只佔1bit空間,並且每個元素只能為0或1。

布隆過濾器擁有k個哈希函數,當一個元素加入布隆過濾器時,會使用k個哈希函數對其進行k次計算,得到k個哈希值,並且根據得到的哈希值,在位數組中把對應下標的值置位1。

判斷某個數是否在布隆過濾器中,就對該元素進行k次哈希計算,得到的值在位數組中判斷每個元素是否都為1,如果每個元素都為1,就說明這個值在布隆過濾器中。

當插入的元素越來越多時,當一個不在布隆過濾器中的元素,經過同樣規則的哈希計算之後,得到的值在位數組中查詢,有可能這些位置因為其他的元素先被置1了。

所以布隆過濾器存在誤判的情況,但是如果布隆過濾器判斷某個元素不在布隆過濾器中,那麼這個值就一定不在。

讓我們繼續深入

1、5布谷鳥過濾器

為了解決布隆過濾器不能刪除元素的問題, 論文《Cuckoo Filter:Better Than Bloom》作者提出了布谷鳥過濾器。相比布隆過濾器,布谷鳥過濾器有以下幾點:查詢性能更強、空間利用效率更高、支援反向操作(刪除)以及計數。

布谷鳥過濾器名稱源於採取了一種和布谷鳥一樣的養娃方法,最原始的布谷鳥哈希方法是使用兩個哈希函數對一個key進行哈希,得到桶中的兩個位置。

  • 如果兩個位置都為為空則將key隨機存入其中一個位置
  • 如果只有一個位置為空則存入為空的位置
  • 如果都不為空,則隨機踢出一個元素,踢出的元素再重新計算哈希找到相應的位置

布谷鳥過濾器源於布谷鳥哈希演算法,他巧妙的設計了一個獨特的 hash 函數,使得可以根據 p1 和 元素指紋 直接計算出 p2,而不需要完整的 x 元素。

從下面的公式中可以看出,當我們知道 fp 和 p1,就可以直接算出 p2。同樣如果我們知道 p2 和 fp,也可以直接算出 p1。

fp = fingerprint(x)
p1 = hash(x)
p2 = p1 ^ hash(fp)  // 異或

所以我們根本不需要知道當前的位置是 p1 還是 p2,只需要將當前的位置和 hash(fp) 進行異或計算就可以得到對偶位置。而且只需要確保 hash(fp) != 0 就可以確保 p1 != p2,如此就不會出現自己踢自己導致死循環的問題。

聽完李小庚的介紹後,陳彥宇突然啞然失笑:「原來如此,我以為我的JMeter可以剋制資料庫,所以大數據攻擊可以擊穿你的資料庫,沒想到小丑竟是我自己。」

「其實你不必懊惱,你的想法是沒錯的,剋制資料庫最好的武器就是大量的數據,只是要擊穿我整個redis集群,你這單台伺服器運行的JMeter還是不夠看。」陳彥宇安慰道,作為勝利者自然應該有著勝利者的體面。

「即使我有足夠的JMeter伺服器,你肯定還有後手對吧。」陳彥宇不甘心的問。

「bingo!」李小庚一步一步接近被redis集群鎖住氣息的陳彥宇,輕輕取下失去主人法力支援只能安靜漂浮在空中的盒子:「既然Redis能儲存數據,自然也能實時的刪除多餘的數據。」

二、記憶體淘汰機制

既然Redis能儲存數據,自然也就需要能刪除多餘的數據,不然,空間都被佔滿了,新的內容放在哪裡?聰明的程式設計師提出了兩個個辦法解決Redis的記憶體問題。

  • 1、定時刪除——通過定時器刪除過期的數據
  • 2、惰性刪除——查詢後如果過期就不返回、過期則刪除。這種情況容易出現很多冗餘數據導致佔用大量空間

2、1、定時刪除

創建一個定時器,當key設置有過期時間,且過期時間到達時,由定時器任務立即執行對鍵的刪除操作,默認100ms就隨機抽一些key判斷是否過期,過期的話就刪除,用處理器性能換取存儲空間(拿時間換空間)

  • 優點:節約記憶體,到時就刪除,快速釋放掉不必要的記憶體佔用

  • 缺點:CPU壓力很大,無論CPU此時負載量多高,均佔用CPU,會影響redis伺服器響應時間和指令吞吐量

2、2惰性刪除

當Redis中的數據到了過期時間,我們先不做處理。等下次訪問該數據時進行一次判斷,如果未過期,就正常返回,如果發現數據已過期,立刻刪除,然後返回不存在,用存儲空間換取處理器性能(拿空間換時間)

  • 優點:節約CPU性能,發現必須刪除的時候才刪除

  • 缺點:記憶體壓力很大,出現長期佔用記憶體的數據

不知道大家不知道發現了沒有,大部分的演算法,不是時間換空間,就是空間換時間。剛剛發現這個秘密的我簡直驚呆了,這就是人類的終極奧秘之一了,只要我們知道這個訣竅,就能解決大部分的問題。

2、3淘汰機制

在Redis的redis.config文件中還可通過搜索maxmemory-policy來設置淘汰機制

noeviction:當記憶體使用達到閾值的時候,所有引起申請記憶體的命令會報錯。
allkeys-lru:在主鍵空間中,優先移除最近未使用的key。
volatile-lru:在設置了過期時間的鍵空間中,優先移除最近未使用的key。
allkeys-random:在主鍵空間中,隨機移除某個key。
volatile-random:在設置了過期時間的鍵空間中,隨機移除某個key。
volatile-ttl:在設置了過期時間的鍵空間中,具有更早過期時間的key優先移除。

「你練習過執行緒池神功,所以你也知道,一個適合的淘汰策略能解決許多的問題,而對於redis也一樣,我只需要適當地修改參數,讓最近存儲的數據都快速淘汰掉,便能防止記憶體壓力過大。」李小庚一個響指解除了redis集群對陳彥宇的鎖定,又將JMeter放到他的手中:「說到底,硬體差距太大,再好的策略也沒有用。」

「你要做甚?」陳彥宇很不解的看著李小庚的行為:「你是在羞辱我嗎?」

「你不是要和我正面對決嗎?我給你這個機會!」說罷,redis集群像一群小蜜蜂一樣,回到了李長庚的空間戒指內。

陳彥宇已經被李小庚的才學與氣度所折服,本來想就此認輸,但是為了給對方留下一個好印象,便最大程度運起《Java真經》,全力以赴道:「長庚師兄,雖然我知道無論是否使用法器,你的修為都在我之上,但是你也要小心哦,我不會差你太多的!」

(註:在門派同屆內修為更高者為師兄)

您好,我是南橘,萬法仙門的掌門,剛剛從九州世界穿越到地球,因為時空亂流的影響導致我的法力全失,現在不得不通過這個平台向廣大修真天才們借去力量。你們的每一個點贊,每一個關注都是讓我回到九州世界的助力,兄弟萌來為我注入修為吧!關注WX號:南橘ryc

等我回去以後,大家都是萬法仙門的長老,我會給大家數不盡的天材地寶,人人如龍,全民飛升。