Redis的三個必知必會的問題
導讀 | 快取的作用主要有兩個:一來提升訪問速度;二來保護資料庫。在業務量不大的時候,通常沒什麼大問題。但當業務量起來以後,如果快取使用不合理,三兄弟一定會如約而至,讓你體驗一下現實的殘酷。 |
快取是網際網路應用中不可或缺的一部分。而提到快取,就不得不提它的三個經典問題——快取穿透、快取擊穿和快取雪崩,我稱它們為快取問題三兄弟。
快取的作用主要有兩個:一來提升訪問速度;二來保護資料庫。在業務量不大的時候,通常沒什麼大問題。但當業務量起來以後,如果快取使用不合理,三兄弟一定會如約而至,讓你體驗一下現實的殘酷。
三兄弟不來則已,一來輕則影響系統效能,重則直接拖垮資料庫,導致系統癱瘓。因此,我們不可掉以輕心,要防患於未然。
一個請求到達伺服器時,正常情況下是按照如下流程進行的。
沒遇到過這三個問題都不好意思說用過Redis
即按照如下步驟:
1.查詢快取,如果命中則返回。
2.快取未命中,則查詢資料庫。
3.將從資料庫中查詢到的資料寫入快取並返回。
如果每次都是這樣按部就班的處理,倒也相安無事。但是,凡事就怕但是。但是總會有例外,假如請求方對一個(資料庫中)根本不存在的資料進行訪問,那麼按照上面的流程,快取就形同虛設了。因為不存在,所以不會被寫入快取,這樣請求每次都會打到資料庫,這個現象就是所謂的「快取穿透」了。
如果只是因為個別請求去查詢不存在的資料,那其實也沒什麼大事。但快取穿透通常是伴隨一些「惡意請求」而來,通常是在短時間內湧入大量請求。如果放任不管,就等著資料庫當機吧。
瞭解了導致快取穿透的原因,那麼解決方案也就明瞭了。可以從兩個方面下手:
- 快取不存在的記錄。
- 過濾不存在的請求。
啥?不存在的記錄咋快取?其實很簡單,如果資料庫中也查不到,那就將快取的 value 設定成 null 即可(注意要根據業務特性設定合理的過期時間)。
過濾不存在的請求,當一個請求到達伺服器,比如:
GET /api/user/1
過濾器會先判斷該資源是否存在,如果存在則放行,不存在則直接返回,從而起到保護系統的作用。
這種方式也有比較成熟的方案。比如布隆過濾器和布穀鳥過濾器(升級版布隆布隆過濾器)。
不管請求不存在的資源是有意還是無意,都不是我們想要的。所以,我們可以設定一個訪問頻率,一定時間內頻繁(超出正常使用者的極限)訪問,可以對請求方加以限制(如 IP 限制)。另外,一些介面可以加入認證,必須登入才能訪問。
通常情況,我們會為快取設定一個過期時間。而如果在一個資源的快取過期以後(或者還未來得及快取),瞬間湧入大量查詢該資源的請求,那麼這些請求就都會一股腦的奔向資料庫,這時,我們的資料庫可就慘了,可能秒秒鐘掛掉。這種情況我們稱之為快取擊穿。
要解決快取擊穿也有兩種思路:
先看第一種,短時間內被大量訪問的通常是熱點資源,針對這類資源我們可以不設定過期時間(永不過期),當資源有變化時透過程式去更新快取。
再來看第二種,我們可以使用加鎖的方式(一般 JVM 級別的鎖即可)來避免擊穿。當快取過期之後,進來的請求,先要獲得一把鎖(也就是去資料庫查詢的資格),然後再去查詢資料庫,最後將資料新增到快取。這樣就可以保證同一時刻(一個服務例項)只會有一個請求去查庫了,其他執行緒等快取有值以後,再去快取取。
加鎖虛擬碼示例:
public String getData() throws InterruptedException { // 從快取取值 String result = getFromCache(); // 取到直接返回 if (Objects.nonNull(result)) { return result; } // 嘗試獲取鎖 if (!lock.tryLock()) { // 加鎖失敗則休息一會 Thread.sleep(10); return getData(); } // 加鎖成功則去資料庫取值 result = getFromDB(); // 取回後放入快取 setFromCache(); return result; }
快取雪崩指的是,快取中大量的 key 在同一時刻集體過期,導致大量請求湧入到資料庫。
有人把快取服務由於一些原因不可用稱為快取雪崩,我覺得這麼叫不太合適。
你想象一下什麼是雪崩,大量的雪花集體從山上往下跳就是雪崩。那麼對應到快取的場景,我們可以把 Redis 看做是山,而 Redis 裡的 key 就是雪花。Redis 中大量的 key 同時失效,就好比是山上大量的雪花同時往下掉是一樣的。所以雪崩用來比喻大量 key 集中失效的情況明顯更貼切。而快取服務掛掉應該屬於快取服務故障,可以採取快取叢集的方式來提高可用性。
要解決快取雪崩的問題,有兩種思路:
分散過期時間很容易想到,既然雪崩是因為 key 集體過期導致的,那麼把它們過期的時間分散開就可以避免這種問題了。
另一種思路,跟解決快取擊穿一樣,將快取設定為永不過期。
永不過期的方案有一定的侷限性,要看具體的業務,不能粗暴的將所有快取都設定成不過期。
每種技術方案都有其適用的業務場景,也都有其侷限性。沒有一個方案能夠應對所有問題,合適即是好。但從上面的方案中還是能看到一些通用的思想的,比如:儘早返回。咋理解呢?就是讓呼叫鏈儘量的短,能攔在應用服務之前的絕不放行(布隆過濾);能從快取取到的絕不再去查庫。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2906857/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 面試:Redis必知必會20問面試Redis
- Redis 必知必會Redis
- 24 個必知必會的系統管理員面試問題面試
- Redis 必知必會之 APIRedisAPI
- Redis 必知必會之持久化Redis持久化
- 必知必會的8個Python列表技巧Python
- 6 個必知必會的關於容器的概念
- HTTP 必知必會的那些HTTP
- 15 張圖,瞭解一下 TCP/IP 必知也必會的 10 個問題TCP
- leetcode我們必知必會的SQL面試題LeetCodeSQL面試題
- 【必知必會的MySQL知識】①初探MySQLMySql
- 【必知必會的MySQL知識】②使用MySQLMySql
- MYSQL中的鎖必知必會MySql
- SQL 必知必會 50 題(1 - 5)SQL
- MySQL 必知必會MySql
- Linux必會必知Linux
- git必會必知Git
- ThreadLocal必知必會thread
- Activity 必知必會
- JSON 必知必會JSON
- HashMap必知必會HashMap
- 【必知必會的MySQL知識】④DCL語言MySql
- 【必知必會的MySQL知識】⑤DQL語言MySql
- 【必知必會的MySQL知識】③DML語言MySql
- 大廠必問的Redis面試題Redis面試題
- Redis 必知概念Redis
- notion database 必知必會Database
- Linux shell必知必會Linux
- Linux 程式必知必會Linux
- 前端必知必會--操作URL的黑科技前端
- 優秀程式碼的必知必會(一)?
- Linux運維必知必會的命令列:find 的 26 個用法示例!Linux運維命令列
- 必知必會Java命令-jpsJava
- mysql必知必會筆記MySql筆記
- Mysql必知必會練習MySql
- 01-mysql必知必會MySql
- 常用技術必知必會
- 一名合格測試的必知必會