如何設計乙個多級快取系統?

2021-09-30 21:39:49 字數 2993 閱讀 2400

首先我們需要明白,什麼是乙個多級快取系統,它有什麼用。所謂多級快取系統,就是指在乙個系統 的不同的架構層級進行資料快取,以提公升訪問效率。

我們都知道,乙個快取系統,它面臨著許多問題,比如快取擊穿,快取穿透,快取雪崩,快取熱點等等問題,那麼,對於乙個多級快取系統,它有什麼問題呢?

快取熱點:多級快取系統大多應用在高併發場景下,所以我們需要解決熱點key問題,如何探測熱點key?

資料一致性:各層快取之間的資料一致性問題,如應用層快取和分布式快取之前的資料一致性問題。

快取過期:快取資料可以分為兩大類,過期快取和不過期快取?如何設計,如何設計過期快取?

在這之前,我們先看看乙個簡單的多級快取系統的架構圖:

整個多級快取系統被分為三層,應用層nginx快取,分布式redis快取集群,tomcat堆內快取。整個架構流程如下:

當接收到乙個請求時,首先會分發到nginx集群中,這裡可以採用nginx的負載均衡演算法分發給某一台機器,使用輪詢可以降低負載,或者採用一致性hash演算法來提公升快取命中率。

當nginx層沒有快取資料時,會繼續向下請求,在分布式快取集群中查詢資料,如果快取命中,直接返回(並且寫入nginx應用快取中),如果未命中,則回源到tomcat集群中查詢堆內快取。

在分布式快取中查詢不到資料,將會去tomcat集群中查詢堆內快取,查詢成功直接返回(並寫入分redis主集群中),查詢失敗請求資料庫;堆內快取。

如果以上快取中都沒有命中,則直接請求資料庫,返回結果,同步資料到分布式快取中。

在簡單了解了多級快取的基本架構之後,我們就該思考如何解決上面提到的一系列問題。

快取熱點

快取熱點,是乙個很常見的問題,比如「某某明星宣布結婚」等等,都可能產生大量請求訪問的問題,乙個最麻煩也是最容易讓人忽視的事情就是如何探測到熱點key,在快取系統中,除了一些常用的熱點key外,在某些特殊場合下也會出現大量的熱點key,我們該如何發現呢?有以下策略:

資料調研。可以分析歷史資料以及針對不同的場合去**出熱點key,這種方式雖然不能百分百使得快取命中,但是卻是一種最簡單和節省成本的方案。

實時計算。可以使用現有的實時計算框架,比如storm、spark streaming、flink等框架統計乙個時間段內的請求量,從而判斷熱點key。或者也可以自己實現定時任務去統計請求量。

這裡我們著重討論一下第二種解決方案,對於熱點key問題,當快取系統中沒有發現快取時,需要去資料庫中讀取資料,當大量請求來的時候,乙個請求獲取鎖去請求資料庫,其他阻塞,接著全部去訪問快取,這樣可能因為一台伺服器撐不住從而宕機,比如正常一台伺服器併發量為5w左右,產生熱點key的時候達到了10w甚至20w,這樣伺服器肯定會崩。所以我們在發現熱點key之後還需要做到如何自動負載均衡。

結合以上問題我們重新設計架構,如下圖所示:

我們將整個應用架構分為應用層,分布式快取、系統層以及資料層。

在應用層,我們採用nginx集群,並且對接實時計算鏈路,通過flume監控nginx日誌,將資料傳輸到kafka集群中,然後flink集群消費資料進行統計,如果統計 結果為熱點key,則將資料寫入zookeeper的節點中,而應用系統通過監控znode節點,讀取熱點key資料,去資料庫中載入資料到快取中並且做到負載均衡。

實際上,對於應用系統中的每一台伺服器,還需要一層防護機制,限流熔斷,這樣做的目的是為了防止單台機器請求量過高,使得伺服器負載過高,不至於伺服器宕機或者大量請求訪問資料庫。簡單思路就是為每一台伺服器設計乙個閥值,當請求量大於該值就直接返回使用者空白頁面或者提示使用者幾秒後重新整理重新訪問。

資料一致性

資料一致性問題主要體現在快取更新的時候,如何更新快取,保證資料庫與快取以及各層快取層之間的一致性。

對於快取更新問題,先寫快取還是先寫資料庫,這裡省略若干字。之前的文章介紹過,有興趣的讀者可以翻閱。

在單層快取系統中,我們可以先刪除快取然後更新資料庫的方案來解決其資料一致性問題,那麼對於多級快取呢?如果使用這種方案,我們需要考慮,如果先刪除快取,那麼需要逐層去做刪除操作,那麼這一系列操作對系統帶來的耗時也是和可觀的。

如果我們使用分布式事務機制,就需要考慮該不該將寫快取放入事務當中,因為我們更新分布式快取,需要走網路通訊,大量的請求將導致網路抖動甚至阻塞,增加了系統的延遲,導致系統短時間內不可用。如果我們不將寫快取這一操作放入事務當中,那麼可能引起短時間內資料不一致。這也就是分布式系統的cap理論,我們不能同時達到高可用和一致性。那麼該如何抉擇呢?

這裡我們選擇保證系統的可用性,就乙個秒殺系統來講,短暫的不一致性問題對使用者的體驗影響並不大(當然,這裡不涉及支付系統),而可用性對使用者來說卻很重要,乙個活動可能在很短的時間內結束,而使用者需要在這段時間內搶到自己心儀的商品,所以可用性更重要一些(這裡需要根據具體場景進行權衡)。

在保證了系統的可用性的基礎上,我們該如何實現呢?如果實時性要求不是很高,我們可以採用全量+增量同步的方式進行。首先,我們可以按照預計的熱點key對系統進行快取預熱,全量同步資料到快取系統。接著,在需要更新快取的時候,我們可以採用增量同步的方式更新快取。比如我們可以使用阿里canal框架同步binlog的方式進行資料的同步。

快取過期

快取系統中的所有資料,根據資料的使用頻率以及場景,我們可以分為過期key以及不過期key,那麼對齊過期快取我們該如何淘汰呢?下面有常用的幾種方案:

fifo:使用fifo演算法來淘汰過期快取。

lfu:使用lfu演算法來淘汰過期快取。

lru:使用lru演算法來淘汰過期快取。

以上幾種方案是在快取達到最大快取大小的時候的淘汰策略,如果沒有達到最大快取大小,我們有下面幾種方式:

定時刪除策略:設定乙個定時任務,在規定時間內檢查並且刪除過期key。

定期刪除策略:這種策略需要設定刪除的週期以及時長,如何設定,需要根據具體場合來計算。

惰性刪除策略:在使用時檢查是否過期,如果過期直接去更新快取,否則直接返回。

如何設計乙個秒殺系統

秒殺場景一般會在電商 舉行一些活動或者節假日在12306 上搶票時遇到。對於電商 中一些稀缺或者 商品,電商 一般會在約定時間點對其進行限量銷售,因為這些商品的特殊性,會吸引大量使用者前來搶購,並且會在約定的時間點同時在秒殺頁面進行搶購。限流 鑑於只有少部分使用者能夠秒殺成功,所以要限制大部分流量,...

如何設計乙個秒殺系統

秒殺場景一般會在電商 舉行一些活動或者節假日在12306 上搶票時遇到。對於電商 中一些稀缺或者 商品,電商 一般會在約定時間點對其進行限量銷售,因為這些商品的特殊性,會吸引大量使用者前來搶購,並且會在約定的時間點同時在秒殺頁面進行搶購。限流 鑑於只有少部分使用者能夠秒殺成功,所以要限制大部分流量,...

如何設計乙個秒殺系統

秒殺一般是訪問請求數量遠遠大於庫存數量,只有少部分使用者能夠秒殺成功。秒殺業務流程比較簡單,一般就是下訂單減庫存。瀏覽器端 js 服務端控制器層 閘道器層 服務層利用快取應對讀請求 對類似於12306等購票業務,是典型的讀多寫少業務,大部分請求是查詢請求,所以可以利用快取分擔資料庫壓力。利用快取應對...