1. 程式人生 > >【高併發】高併發環境下構建快取服務需要注意哪些問題?我和阿里P9聊了很久!

【高併發】高併發環境下構建快取服務需要注意哪些問題?我和阿里P9聊了很久!

## 寫在前面 > 週末,跟阿里的一個朋友(去年晉升為P9了)聊了很久,聊的內容幾乎全是技術,當然了,兩個技術男聊得最多的話題當然就是技術了。從基礎到架構,從演算法到AI,無所不談。中間又穿插著不少天馬行空的想象,雖然現在看起來不太實際,但是隨著技術的進步,相信五年、十年之後都會實現的。 > > 不知道是誰提起了在高併發環境下如何構建快取服務,結果一路停不下來了!! ## 快取特徵 (1)命中率:命中數/(命中數+沒有命中數) (2)最大元素(空間):代表快取中可以存放的最大元素的數量,一旦快取中元素的數量超過這個值,或者快取資料所佔的空間超過了最大支援的空間,將會觸發快取清空策略。根據不同的場景,合理設定最大元素(空間)的值,在一定程度上可以提高快取的命中率,從而更有效的使用快取。 (3)清空策略:FINO(先進先出)、LFU(最少使用)、LRU(最近最少使用)、過期時間、隨機等。 * FINO(先進先出):最先進入快取的資料,在快取空間不夠或超出最大元素限制的情況下,會優先被清除掉,以騰出新的空間來接收新的資料。這種策略的演算法主要是比較快取元素的建立時間,在資料實時性較高的場景下,可以選擇這種策略,優先保證最新策略可用。 * LFU(最少使用):無論元素是否過期,根據元素的被使用次數來判斷,清除使用次數最少的元素來釋放空間。演算法主要是比較元素的命中次數,在保證高頻資料有效的場景下,可以選擇這種策略。 * LRU(最近最少使用):無論元素是否過期,根據元素最後一次被使用的時間戳,清除最遠使用時間戳的元素,釋放空間。演算法主要是比較元素最近一次被獲取的時間,在熱點資料場景下,可以選擇這種策略。 過期時間:根據過期時間判斷,清理過期時間最長的元素,或者清理最近要過期的元素。 ## 快取命中率影響因素 **(1)業務場景和業務需求** 快取往往適合讀多寫少的場景。業務需求對實時性的要求,直接會影響到快取的過期時間和更新策略。實時性要求越低,就越適合快取。在相同Key和相同請求數的情況下,快取的時間越長,命中率就會越高。 **(2)快取的設計(粒度和策略)** 通常情況下,快取的粒度越小,命中率越高。快取的更新和命中策略也會影響快取的命中率,當資料發生變化時,直接更新快取的值會比移除快取或使快取過期的命中率更高。 **(3)快取容量和基礎設施** 快取的容量有限,則容易引起快取失效和被淘汰(目前多數的快取框架或中介軟體都採用了LRU演算法)。同時,快取的技術選型也是至關重要的,比如採用應用內建的本地快取就比較容易出現單機瓶頸,而採用分散式快取則畢竟容易擴充套件。所以需要做好系統容量規劃,並考慮是否可擴充套件。此外,不同的快取框架或中介軟體,其效率和穩定性也是存在差異的。 **(4)其他因素** 當快取節點發生故障時,需要避免快取失效並最大程度降低影響,這種特殊情況也是架構師需要考慮的。業內比較典型的做法就是通過一致性Hash演算法,或者通過節點冗餘的方式。 有些朋友可能會有這樣的理解誤區:既然業務需求對資料時效性要求很高,而快取時間又會影響到快取命中率,那麼系統就別使用快取了。其實這忽略了一個重要因素--併發。通常來講,在相同快取時間和key的情況下,併發越高,快取的收益會越高,即便快取時間很短。 ## 提高快取命中率的方法 從架構師的角度,需要應用盡可能的通過快取直接獲取資料,並避免快取失效。這也是比較考驗架構師能力的,需要在業務需求,快取粒度,快取策略,技術選型等各個方面去通盤考慮並做權衡。儘可能的聚焦在高頻訪問且時效性要求不高的熱點業務上,通過快取預載入(預熱)、增加儲存容量、調整快取粒度、更新快取等手段來提高命中率。 對於時效性很高(或快取空間有限),內容跨度很大(或訪問很隨機),並且訪問量不高的應用來說快取命中率可能長期很低,可能預熱後的快取還沒來得被訪問就已經過期了。 ## 快取的分類和應用場景 (1)本地快取:程式設計實現(成員變數、區域性變數、靜態變數)、Guava Cache (2)分散式快取:Memcached、Redis ## 高併發場景下快取常見問題 **(1)快取的一致性** 更新資料庫成功——更新快取失敗 更新快取成功——更新資料庫失敗 更新資料庫成功——淘汰快取失敗 淘汰快取成功——更新資料庫失敗 **(2)快取併發** 併發時請求快取時已過期或者沒有命中或者更新的情況下有大量的請求訪問資料庫。 **解決辦法**:在快取更新或者過期的情況下,先嚐試獲取到lock,當更新完成後,嘗試釋放鎖,其他的請求只需要犧牲一定的等待時間 **(3)快取穿透** 在高併發的場景下,如果某一個key被高併發的訪問沒有被命中,出於對容錯性的考慮會嘗試從後端的資料庫獲取,從而導致大量的請求訪問了資料庫,主要是當key對應的資料為空或者為null的情況下,這就導致資料庫中併發的執行了很多不必要的查詢操作。從而導致了巨大的衝擊和壓力。 **解決方法:** 快取空物件:對查詢結果為空的物件也進行快取,如果是集合可以快取一個空的集合,而不是null,如果是單個物件可以通過欄位標識來區分,需要保證快取資料的時效性(實現相對簡單),適合命中不高但可能會頻繁更新的資料。 單獨過濾處理:對所有可能對應資料為空的key進行統一的存放,並在請求前做攔截(實現相對複雜),適合命中不高更新不頻繁的資料 **(4)快取顛簸問題** 快取的顛簸問題,有些地方可能被稱為“快取抖動”,可以看作是一種比“雪崩”更輕微的故障,但是也會在一段時間內對系統造成衝擊和效能影響。一般是由於快取節點故障導致。業內推薦的做法是通過一致性Hash演算法來解決。 **(5)快取雪崩現象** 快取雪崩就是指由於快取的原因,導致大量請求到達後端資料庫,從而導致資料庫崩潰,整個系統崩潰,發生災難。導致這種現象的原因有很多種,上面提到的“快取併發”,“快取穿透”,“快取顛簸”等問題,其實都可能會導致快取雪崩現象發生。這些問題也可能會被惡意攻擊者所利用。還有一種情況,例如某個時間點內,系統預載入的快取週期性集中失效了,也可能會導致雪崩。為了避免這種週期性失效,可以通過設定不同的過期時間,來錯開快取過期,從而避免快取集中失效。 從應用架構角度,我們可以通過限流、降級、熔斷等手段來降低影響,也可以通過多級快取來避免這種災難。 此外,從整個研發體系流程的角度,應該加強壓力測試,儘量模擬真實場景,儘早的暴露問題從而防範。 **(6)快取無底洞現象** 該問題由 facebook 的工作人員提出的, facebook 在 2010 年左右,memcached 節點就已經達3000 個,快取數千 G 內容。他們發現了一個問題---memcached 連線頻率,效率下降了,於是加 memcached 節點,添加了後,發現因為連線頻率導致的問題,仍然存在,並沒有好轉,稱之為”無底洞現象” ## 重磅福利 關注「 **冰河技術** 」微信公眾號,後臺回覆 “設計模式” 關鍵字領取《深入淺出Java 23種設計模式》PDF文件。回覆“Java8”關鍵字領取《Java8新特性教程》PDF文件。兩本PDF均是由冰河原創並整理的超硬核教程,面試必備!! **好了,今天就聊到這兒吧!別忘了點個贊,給個在看和轉發,讓更多的人看到,一起學習,一起進步!!** ## 寫在最後 > 如果你覺得冰河寫的還不錯,請微信搜尋並關注「 **冰河技術** 」微信公眾號,跟冰河學習高併發、分散式、微服務、大資料、網際網路和雲原生技術,「 **冰河技術** 」微信公眾號更新了大量技術專題,每一篇技術文章乾貨滿滿!不少讀者已經通過閱讀「 **冰河技術** 」微信公眾號文章,吊打面試官,成功跳槽到大廠;也有不少讀者實現了技術上的飛躍,成為公司的技術骨幹!如果你也想像他們一樣提升自己的能力,實現技術能力的飛躍,進大廠,升職加薪,那就關注「 **冰河技術** 」微信公眾號吧,每天更新超硬核技術乾貨,讓你對如何提升技術能力不再迷茫! ![](https://img-blog.csdnimg.cn/202007162204436