Redis是一個開源高性能的Key-Value存儲系統(tǒng),雖然Redis本身具備了非常高的可用性,但是在實際應(yīng)用中也會隨著系統(tǒng)業(yè)務(wù)的復(fù)雜性以及不合理的使用,而導(dǎo)致很多的問題。本文將講述如何通過混沌工程來暴露可能存在的使用風(fēng)險,提升緩存問題的應(yīng)急能力。
緩存重要性
Redis是一個開源高性能的Key-Value存儲系統(tǒng),因為其極高的讀寫性能,豐富的數(shù)據(jù)類型,原子性的操作以及其他特性而被廣發(fā)運用。
Redis的應(yīng)用場景包括且不限于以下場景:
- 用來做分布式緩存。
- 用來做分布式鎖。
- 用來處理某些特定高并發(fā)業(yè)務(wù),例如秒殺等。
示例架構(gòu)
在實施混沌工程之前,先了解業(yè)務(wù)是如何使用Redis的。由于Redis最常用來做分布式緩存,本文以簡單的商品查詢場景為例,涉及的基本信息如下:
- 業(yè)務(wù)場景是查詢商品信息,首先查詢緩存;如果沒有查詢到,則查詢數(shù)據(jù)庫。
- 使用Jedis連接Redis,并且使用了Jedis-pool的技術(shù)。
- Redis是自建的集群(當(dāng)然也可以使用云服務(wù)),并且使用Sentinel技術(shù)來提升集群的高可用性。更多信息,請參見Redis Sentinel文檔。
示例架構(gòu)圖如下:
從架構(gòu)圖可以看出,在Jedis配置、緩存查詢、網(wǎng)絡(luò)傳輸、服務(wù)端處理這條鏈路上,每個環(huán)節(jié)都有可能出現(xiàn)問題。借助混沌工程可以了解到問題發(fā)生時對系統(tǒng)、業(yè)務(wù)的影響面是否符合預(yù)期。
梳理演練場景
對于示例應(yīng)用,可以按照以下思路來梳理演練場景:
- 明確緩存監(jiān)控的指標。
- 分析影響這些指標可能的因素、故障場景、參數(shù)等。
- 因為客戶端層面的影響面可控,所以可以嘗試從客戶端層面去制造故障。
- 因為服務(wù)端出現(xiàn)故障更加真實,所以可以從服務(wù)端層面去制造故障,但對于問題定位和排查的要求會更高。
- 注入故障,觀察指標的變化。
緩存監(jiān)控指標
目前支持的可監(jiān)控的緩存指標如下:
指標 | 說明 |
---|---|
緩存QPS | QPS是最通用也是最易觀察的指標。 |
緩存命中率 | 緩存未命中可能會在大流量下引發(fā)穿透、擊穿、雪崩等問題,如果業(yè)務(wù)沒有做好應(yīng)急處理,很容易壓垮數(shù)據(jù)庫。
|
緩存RT | 緩存響應(yīng)時間。緩存RT對業(yè)務(wù)的影響分成多個方面。如果RT變化較少,對于業(yè)務(wù)訪問緩存很少次數(shù)的情況下影響可控。但是如果一條請求需要多次訪問緩存,那么哪怕RT只是幾毫秒的增長,也會因為訪問次數(shù)過多引起總的RT增長過多,引發(fā)蝴蝶效應(yīng),造成業(yè)務(wù)異常。 |
緩存成功率 | 緩存的請求成功率過低也會造成和命中率一樣的后果。 |
業(yè)務(wù)成功率 | 在對業(yè)務(wù)成功率要求較高的業(yè)務(wù)當(dāng)中,緩存必定是作為一個弱依賴存在。當(dāng)緩存出現(xiàn)問題,系統(tǒng)應(yīng)該有其他兜底策略。但是隨著系統(tǒng)越來越復(fù)雜,改造的越來越頻繁,原本預(yù)計的緩存弱依賴也會不經(jīng)意間被改造成強依賴,一旦出現(xiàn)這種情況,就會導(dǎo)致業(yè)務(wù)受損。 |
影響因素
由于影響系統(tǒng)的因素有很多,例如機房、電源、集群服務(wù)、操作系統(tǒng)、應(yīng)用配置等。
本文主要梳理操作系統(tǒng)層面和應(yīng)用層面的影響因素:
- 系統(tǒng)層面的影響因素有網(wǎng)絡(luò)、磁盤、IO、內(nèi)存、CPU等因素。
- 應(yīng)用層面的影響有超時配置、連接池配置、查詢不合理等因素。
結(jié)合緩存監(jiān)控指標、操作系統(tǒng)層面和應(yīng)用層面的影響因素,本文從客戶端和服務(wù)端兩個角度來分析最終影響系統(tǒng)的因素和后果(假設(shè)業(yè)務(wù)請求QPS保持穩(wěn)定)。
因素 | 模擬手段 | 可能后果 | 可能影響指標 |
---|---|---|---|
網(wǎng)絡(luò)延遲 | 6379端口網(wǎng)絡(luò)延遲 |
|
|
網(wǎng)絡(luò)中斷 | 6379端口網(wǎng)絡(luò)丟包 |
|
|
單次查詢耗時過長 | 如果Key過多,可以模擬Keys*查詢 |
|
|
連接池設(shè)置不合理(連接池過小或者過高) | Jedis連接池占滿 | 無法建立連接 |
|
緩存未命中 | Jedis返回值攔截 |
|
命中率 |
緩存異常 | Jedis拋異常 | 緩存強依賴,業(yè)務(wù)失敗。 | 成功率 |
因素 | 模擬手段 | 可能后果 | 可能影響指標 | 如何改進 |
---|---|---|---|---|
磁盤空間不足 | 磁盤填充 |
|
|
|
網(wǎng)絡(luò)異常 |
|
指定客戶端請求超時。 |
|
|
連接池滿 | 建立網(wǎng)絡(luò)連接 | 無法分配新連接,客戶端建連失敗。 | 無 |
|
單次查詢耗時過長 | 如果Key過多,可以模擬Keys*查詢。 |
|
|
|
IO讀寫過高 | 磁盤讀寫IO過高 | 讀寫變慢,響應(yīng)超時。 |
|
|
內(nèi)存不足 | Jedis返回值攔截 |
|
|
|
CPU過高 | CPU滿載 | 讀寫RT變長。 |
|
系統(tǒng)監(jiān)控。 |
實戰(zhàn)演練
下面通過Chaos故障演練平臺從客戶端層面來評測業(yè)務(wù)對Redis的合理使用。
演練價值
通過對不同網(wǎng)絡(luò)延遲的演練,可以了解到緩存RT變化對系統(tǒng)造成的影響,以及防護策略有效性。隨著業(yè)務(wù)規(guī)模的不斷增長,這個簡單的業(yè)務(wù)系統(tǒng)也會面臨新的問題:
- 在某次重構(gòu)中,又新增加了緩存查詢,結(jié)果導(dǎo)致20 ms的延遲使得接口整體超時。
- 業(yè)務(wù)邏輯簡單的時候,能夠很好地分析強弱依賴。但是隨著微服務(wù)的膨脹,以及代碼多次重構(gòu),可能原有的弱依賴在某次變更中變成了強依賴,這種通過功能測試是無法發(fā)現(xiàn)的。
- 本示例Jedis設(shè)置的超時時間是100 ms,不同業(yè)務(wù)對RT的要求不同,您可以根據(jù)實際情況設(shè)置合理的超時時間。
上述的一些問題都要通過故障演練來發(fā)現(xiàn)。在日常的發(fā)布、架構(gòu)升級中除了功能測試、性能測試的回歸,還需要進行常態(tài)化的故障演練,同時演練的形態(tài)和場景復(fù)雜性也要不斷擴充。對于故障演練來說,難的不是注入手段,而是對業(yè)務(wù)架構(gòu)、業(yè)務(wù)場景的理解。故障注入不是目的,演練的目的是加深對系統(tǒng)的理解,這樣當(dāng)真實的問題來臨時候,才能更加有信心地去處理。