1. 程式人生 > >白盒測試 Redis 叢集快取測試要點--關於 線上 token 失效 BUG 的總結

白盒測試 Redis 叢集快取測試要點--關於 線上 token 失效 BUG 的總結

在測試xx系統過程中遇到了線上大面積使用者登入態失效的嚴重問題,事後對於其原因及測試盲點做了一些總結記錄以便以後查閱,總結分為以下7點,其中原理性的解釋有些摘自網路。

1.xx系統token失效問題覆盤 2.Redis 經典流程 3.Redis分片部署方式 4.Redis擴容導致快取資料失效 5.Redis Sharding一致性hash演算法 6.快取失效,快取擊穿,快取穿透 7.Redis快取測試總結

xx系統token失效問題覆盤現象:redis擴容後線上大量使用者登入態失效,需要重新登入。由於登入態可以持續保持,部分使用者忘記密碼,需要修改密碼後再次登入。在測試驗證中,由於切換環境、登入登出導致這個問題難以發現和注意。

原因:sharded-redis-pool分片規則中有域名因子(框架原始碼中),擴容修改了redis域名,導致redis中資料雖然存在,概率性獲取不到。PS:失效問題覆盤中有較多關於BUG修復前後程式碼差異的片段由於保密未貼出,一般來說測試覆盤過程中對於程式碼的解析是很重要的一環。

Redis經典流程

前端測試盲點: 1.有些應用臨時資料都儲存在redis裡,不儲存在DB裡 2.上面流程中redis的資料不管有沒有生效,程式都可以正常進行,且功能正常 3.redis如果是叢集的方式,快取資料的讀取和寫入有沒有進入正確的分片

Redis分片部署方式 (1)在客戶端(jedis)做分片(Redis Sharding);這種方式在客戶端確定要連線的redis例項,然後直接訪問相應的redis例項。 (2)在代理中做分片;這種方式中,客戶端並不直接訪問redis例項,它也不知道自己要訪問的具體是哪個redis例項,而是由代理轉發請求和結果;其工作過程為:客戶端先將請求傳送給代理,代理通過分片演算法確定要訪問的是哪個redis例項,然後將請求傳送給相應的redis例項,redis例項將結果返回給代理,代理最後將結果返回給客戶端。 (3)在redis伺服器端做分片(Redis Cluster);這種方式被稱為“查詢路由”,在這種方式中客戶端隨機選擇一個redis例項傳送請求,如果所請求的內容不再當前redis例項中它會負責將請求轉交給正確的redis例項,也有的實現中,redis例項不會轉發請求,而是將正確redis的資訊發給客戶端,由客戶端再去向正確的redis例項傳送請求。

Redis擴容導致快取資料失效 假設有三臺快取伺服器,快取hotkey,希望hotkey被均勻的快取到這三臺伺服器上,原始的做法是對快取項的鍵進行雜湊,將雜湊後的結果對快取伺服器的數量進行取模操作。

假設三臺快取伺服器已經不能滿足業務快取需求,需要增加機器,就會出現一些缺陷。假設增加一臺伺服器,快取伺服器的數量由三臺變為四臺,此時,如果仍用取模的方法對同一hotkey進行快取,那麼這個hotkey所在的伺服器編號就肯定與原來三臺伺服器時所在的編號不同。這就導致了快取在一定時間內是失效的,當應用無法從快取中獲取資料,則會向後端服務請求資料,由於大量快取同一時間失效,造成快取的雪崩,可能導致系統被壓垮。

Redis Sharding一致性hash演算法 一致性hash:一致性雜湊演算法也是使用取模的方法,只是一致性雜湊演算法是對2^32取模。 我們有ABC三臺伺服器,使用各自的IP地址進行雜湊計算,使用雜湊後的結果對2^32取模,計算結果對映到一個由2^32個點組成的雜湊圓環上,可以得到如下的示意圖:

假設有4個hotkey,1234需要快取,根據hash(hotkey)% 2^32得到的對映圖如下,hotkey1、2儲存到A中,hotkey3儲存到B中,hotkey4儲存到C中。

假設機器B出現故障,需要移除伺服器B,那麼移除後的示意圖如下。

當伺服器移除以後,按照之前的一致性雜湊演算法的規則,hotkey3應該被快取到伺服器C中,hotkey3的快取位置發生了改變。但是hotkey1、2仍被快取到伺服器A中,hotkey4仍被快取到伺服器C中,這就是一致性雜湊演算法的優點,當伺服器數量發生改變,並不是快取都會失效,而是隻有部分快取會失效,前端的快取仍能分擔整個系統的壓力,不至於所有壓力在同一時間集中到後端伺服器上。

Hash環的偏斜及虛擬結點:

在實際的對映中,伺服器可能會被對映成如下圖:

虛擬節點是實際節點在hash環上的複製品,一個實際節點可以對應多個虛擬節點。虛擬節點可以解決hash環的偏斜以及快取雪崩的問題。

快取失效、快取擊穿、快取穿透快取穿透 快取穿透是指查詢一個一定不存在的資料,由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應用,這就是漏洞。解決方案 有很多種方法可以有效地解決快取穿透問題,最常見的則是採用布隆過濾器,將所有可能存在的資料雜湊到一個足夠大的bitmap中,一個一定不存在的資料會被 這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力。另外也有一個更為簡單粗暴的方法(我們採用的就是這種),如果一個查詢返回的資料為空(不管是數 據不存在,還是系統故障),我們仍然把這個空結果進行快取,但它的過期時間會很短,最長不超過五分鐘。

快取雪崩 快取雪崩是指在我們設定快取時採用了相同的過期時間或者其他情況,導致快取在某一時刻同時失效,請求全部轉發到DB,DB瞬時壓力過重雪崩。解決方案 快取失效時的雪崩效應對底層系統的衝擊非常可怕。大多數系統設計者考慮用加鎖或者佇列的方式保證快取的單線 程(程序)寫,從而避免失效時大量的併發請求落到底層儲存系統上。這裡分享一個簡單方案就時講快取失效時間分散開,比如我們可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個快取的過期時間的重複率就會降低,就很難引發集體失效的事件。

快取擊穿 對於一些設定了過期時間的key,如果這些key可能會在某些時間點被超高併發地訪問,是一種非常“熱點”的資料。這個時候,需要考慮一個問題:快取被“擊穿”的問題,這個和快取雪崩的區別在於這裡針對某一key快取,前者則是很多key。 快取在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的併發請求過來,這些請求發現快取過期一般都會從後端DB載入資料並回設到快取,這個時候大併發的請求可能會瞬間把後端DB壓垮。解決方案 使用互斥鎖(mutex key) 簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用快取工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作並回設快取;否則,就重試整個get快取的方法。

Redis叢集快取測試總結 功能: 1.系統執行過程中,redis快取資料生效。快取的資料讀取正確、資料寫入落地正確,資料有效期設定合理。 2.redis叢集分片策略驗證正確。 3.快取與資料庫的資料一致性檢測。 4.DB事務性導致回滾,快取是否回滾,有沒有產生髒資料。 5.注意測試環境與線上環境的區別,尤其是單例與叢集分片、讀寫分離。儘量保持測試環境與線上一致或者是其縮小版。

自動化: 1.自動化用例中斷言部分設計快取層斷言並且自動化框架本身對於斷層層次可配置。

效能及穩定性: 1.關注業務本身應用場景及快取結構,是否使用快取。 2.預防快取穿透、快取雪崩、快取擊穿引發的系統風險。

擴容: 1.關注擴容方案設計、老資料備份策略、回滾方案 2.關注擴容後分片策略的變化 3.擴容後熱點資料失效率或命中率以及對後端DB帶來的壓力