Redis異常測(cè)試盤點(diǎn)分析
Redis測(cè)試中的異常
在測(cè)試工作中,涉及到與 redis 交互的場(chǎng)景變的越來越多了。關(guān)于redis本身就不作贅述了,網(wǎng)上隨便搜,本人也做過一些整理。
今天只來復(fù)盤一下,在測(cè)試過程中與 redis 的二三事兒。其中提到的案例是經(jīng)過抽象化的,用作輔助說明作用,僅供參考。
一、更新 Key 異常
注意點(diǎn):先刪除原 key 再存,還是直接覆蓋原 key?
比如:之前 A 服務(wù)每8小時(shí)去查詢一次數(shù)據(jù)庫,更新到緩存里去。后來需求調(diào)整,變成當(dāng)數(shù)據(jù)庫里有變動(dòng)的時(shí)候就會(huì)發(fā)送MQ消息給服務(wù) A,然后A就去全量拉取庫里數(shù)據(jù),再更新到緩存。
開發(fā)小哥實(shí)現(xiàn)的是先刪除key再更新,那么可能會(huì)導(dǎo)致這個(gè)時(shí)間如果有大量的請(qǐng)求進(jìn)來,就不能命中緩存。于是乎建議,當(dāng)從數(shù)據(jù)庫拉來數(shù)據(jù)之后,可以先和redis中原來的key值進(jìn)行對(duì)比,刪除多余的緩存,其他的覆蓋更新。
二、Key的刪除和丟失
注意點(diǎn):考慮key被刪除,或者key丟失后對(duì)上游的影響。
比如:服務(wù)A 會(huì)同步一類數(shù)據(jù)到 redis,然后發(fā)消息告訴 服務(wù)B。B 收到消息后,拿到 redis 數(shù)據(jù)去找自己那邊 MongoDB里的對(duì)應(yīng) key,做更新操作,若查不到key,就會(huì)刪除數(shù)據(jù)。
此時(shí)如果 redis 里產(chǎn)生了數(shù)據(jù)丟失,key就不存在了,那么同步過后,會(huì)導(dǎo)致 MongoDB 里的數(shù)據(jù)被勿刪。
于是乎這里建議方案是:redis 那邊涉及要?jiǎng)h除key的話,就更新key的值為空[],這時(shí)候 MongoDB 查詢到值為空的key,就去刪除對(duì)應(yīng)數(shù)據(jù)。
另外,如果redis那邊key 丟失了,MongoDB這邊也別就刪數(shù)據(jù)了,去調(diào)用一個(gè)實(shí)時(shí)接口去查詢數(shù)據(jù)然后更新。
三、KEY 過期策略不當(dāng)造成內(nèi)存泄漏
首先回顧一下 redis 中 ttl key指令:
- 當(dāng) key 不存在時(shí),返回 -2
- 當(dāng) key 存在但沒有設(shè)置剩余生存時(shí)間時(shí),返回 -1
- 否則,返回 key 的剩余生存時(shí)間,單位是 s
通常,大多數(shù)業(yè)務(wù)用到redis 都會(huì)設(shè)置過期時(shí)間。接下來,了解一下 key 過期是如何清理的。
定期清理
Redis會(huì)定期主動(dòng)淘汰一批已過期的key(隨機(jī)抽取一批key檢查)。
缺點(diǎn):可能存在很多KEY已過期,仍未清理。
惰性清理
在獲取某個(gè) key 的時(shí)候,redis 會(huì)檢查一下這個(gè) key 如果設(shè)置了過期時(shí)間并且已經(jīng)過期,就會(huì)刪除這個(gè) key,不會(huì)返回任何東西。
缺點(diǎn):如果存在很多未去查詢的過期key,就沒法走到惰性刪除,于是可能會(huì)有大量過期的key堆積在內(nèi)存里,導(dǎo)致內(nèi)存耗盡。
一般來說,業(yè)務(wù)會(huì)惰性和定期清理配合使用。
內(nèi)存淘汰機(jī)制
但是,如果定期清理漏掉了很多過期的key,然后你也沒及時(shí)去查,也就沒走惰性刪除。此時(shí)依舊有可能大量過期的key堆積在內(nèi)存里,導(dǎo)致內(nèi)存耗盡。
這時(shí)候需要內(nèi)存淘汰機(jī)制,有如下幾個(gè):
- noeviction:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),新寫入操作會(huì)報(bào)錯(cuò)。這個(gè)一般很少用。
- allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,移除最近最少使用的key,這個(gè)是最常用的。
- allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,隨機(jī)移除某個(gè)key。
- volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中,移除最近最少使用的key。
- volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中,隨機(jī)移除某個(gè)key。
- volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中,有更早過期時(shí)間的key優(yōu)先移除。
以上可以作個(gè)了解。
四、查詢Redis異常時(shí)處理
很多時(shí)候,redis 只是做一個(gè)緩存機(jī)制,如果redis異常或者未取到數(shù)據(jù),是否有實(shí)時(shí)獲取數(shù)據(jù)的兜底方案(查接口 or 查庫?),需要考慮。
五、redis 穿透、擊穿、雪崩
穿透
用戶想要查詢一個(gè)數(shù)據(jù),發(fā)現(xiàn)redis內(nèi)存數(shù)據(jù)庫中沒有,也就是說沒有命中緩存,也是會(huì)向持久層數(shù)據(jù)庫查詢,發(fā)現(xiàn)也沒有,那么本次查詢失敗。
如果此時(shí),用戶很多,高并發(fā)場(chǎng)景下都去查這個(gè)數(shù)據(jù),由于緩存都沒有命中,于是壓力直接打到持久層數(shù)據(jù)庫那里,這就是緩存穿透。
解決方案可以用布隆過濾器、返回空對(duì)象(設(shè)置過期時(shí)間)。
擊穿
緩存擊穿,是指一個(gè)key非常熱點(diǎn),在不停的扛著高并發(fā),如果這個(gè)key失效了,在失效的瞬間,持續(xù)的并發(fā)量就會(huì)穿破緩存,直接打到持久層數(shù)據(jù)庫,就像一個(gè)防御墻被鑿開一個(gè)洞。
解決方案可以設(shè)置熱點(diǎn)數(shù)據(jù)永不過期、加互斥鎖等。
雪崩
是指在某一個(gè)時(shí)間段,緩存集中過期失效,或者redis宕機(jī)了。
解決方案:
- 事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
- 事中:本地 ehcache 緩存 + hystrix 限流&降級(jí),避免 MySQL 被打死。
- 事后:redis 持久化,一旦重啟,自動(dòng)從磁盤上加載數(shù)據(jù),快速恢復(fù)緩存數(shù)據(jù)。
關(guān)于這3個(gè),之前有過一篇整理:http://www.dbjr.com.cn/article/230997.htm
六、Redis死鎖
Redis鎖,小心使用不當(dāng)造成鎖不能釋放,陷入死鎖。
目前常用的2種鎖:
SET Key UniqId Seconds
僅在單實(shí)例的場(chǎng)景下是安全的。如果不使用setnx+expire+del中間環(huán)節(jié)斷了仍可能造成死鎖;
如果不用SET Key UnixTimestamp Seconds NX,高并發(fā)下可能存在相同時(shí)間戳。
分布式Redis鎖:Redlock
此種方式比原先的單節(jié)點(diǎn)的方法更安全。
- 安全性:在同一時(shí)間不允許多個(gè)Client同時(shí)持有鎖。
- 活性死鎖:鎖最終應(yīng)該能夠被釋放,即使Client端crash或者出現(xiàn)網(wǎng)絡(luò)分區(qū)(通常基于超時(shí)機(jī)制)。
- 容錯(cuò)性:只要超過半數(shù)Redis節(jié)點(diǎn)可用,鎖都能被正確獲取和釋放。
七、Redis持久化
當(dāng)Redis數(shù)據(jù)需要長(zhǎng)久有效時(shí),需要考慮是否做RDB和AOF持久化,一般RDB和AOF配合使用,但做持久化,會(huì)影響性能。
目前接觸到的業(yè)務(wù)做持久化的很少見。比如有個(gè)推薦系統(tǒng)Redis數(shù)據(jù)是長(zhǎng)久有效的,但卻為了響應(yīng)快不影響性能,未做持久化,而采用了其他的降級(jí)方案Hbase,以及業(yè)務(wù)的兜底等。
八、緩存與數(shù)據(jù)庫雙寫時(shí)的數(shù)據(jù)一致性
一般來說,就是如果你的系統(tǒng)不是嚴(yán)格要求緩存+數(shù)據(jù)庫必須一致性的話,允許緩存跟數(shù)據(jù)庫偶爾不一致的情況,那么最后好不要做這個(gè)一致性方案。
如果實(shí)現(xiàn)這個(gè)方案,讀請(qǐng)求和寫請(qǐng)求串行化,串到一個(gè)內(nèi)存隊(duì)列里去,這樣就可以保證一定不會(huì)出現(xiàn)不一致的情況。
但是串行化之后,就會(huì)導(dǎo)致系統(tǒng)的吞吐量會(huì)大幅度的降低,用比正常情況下多幾倍的機(jī)器去支撐線上的一個(gè)請(qǐng)求。
還有一種適中的方式就是,就是先更新數(shù)據(jù)庫,然后再刪除緩存??赡軙?huì)暫時(shí)產(chǎn)生不一致的情況,但是發(fā)生的幾率特別小。這時(shí)候通常并行寫數(shù)據(jù)庫和緩存,可以加個(gè)事務(wù),都寫成功才成功,有一個(gè)環(huán)節(jié)失敗了就回滾事務(wù),全失敗。
關(guān)于雙寫一致性的問題,其實(shí)可以另起一個(gè)篇幅來說了,有興趣的可以網(wǎng)上搜索一下,后續(xù)可能會(huì)再進(jìn)行整理。
以上就是Redis異常測(cè)試盤點(diǎn)分析的詳細(xì)內(nèi)容,更多關(guān)于Redis異常測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Redis緩存三大異常的處理方案梳理總結(jié)
- redis分布式Jedis類型轉(zhuǎn)換的異常深入研究
- dubbo服務(wù)使用redis注冊(cè)中心的系列異常解決
- 在SpringBoot中注入RedisTemplate實(shí)例異常的解決方案
- 關(guān)于Springboot2.x集成lettuce連接redis集群報(bào)超時(shí)異常Command timed out after 6 second(s)
- Redis連接超時(shí)異常的處理方法
- 如何解決redis的NOAUTH Authentication required異常
- Redis?異常?read?error?on?connection?的解決方案
相關(guān)文章
Redis中SDS簡(jiǎn)單動(dòng)態(tài)字符串詳解
Redis中的SDS(Simple?Dynamic?String)是一種自動(dòng)擴(kuò)容的字符串實(shí)現(xiàn)方式,它可以提供高效的字符串操作,并且支持二進(jìn)制安全。SDS的設(shè)計(jì)使得它可以在O(1)時(shí)間內(nèi)實(shí)現(xiàn)字符串長(zhǎng)度的獲取和修改,同時(shí)也可以在O(N)的時(shí)間內(nèi)進(jìn)行字符串的拼接和截取。2023-04-04Redisson分布式限流的實(shí)現(xiàn)原理解析
這篇文章主要為大家介紹了Redisson分布式限流的實(shí)現(xiàn)原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02了解redis中RDB結(jié)構(gòu)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了redis中RDB結(jié)構(gòu),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08Redis和Nginx實(shí)現(xiàn)限制接口請(qǐng)求頻率的示例
限流就是限制API訪問頻率,當(dāng)訪問頻率超過某個(gè)閾值時(shí)進(jìn)行拒絕訪問等操作,本文主要介紹了Redis和Nginx實(shí)現(xiàn)限制接口請(qǐng)求頻率的示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02Redis Sentinel實(shí)現(xiàn)高可用配置的詳細(xì)步驟
這篇文章主要介紹了Redis Sentinel實(shí)現(xiàn)高可用配置的詳細(xì)步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09RedisTemplate常用操作方法總結(jié)(set、hash、list、string等)
本文主要介紹了RedisTemplate常用操作方法總結(jié),主要包括了6種常用方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-055分鐘教你docker安裝啟動(dòng)redis全教程(全新方式)
今天,我來帶大家使用一種全新的方式docker來安裝redis,首先我們來了解一下什么是redis以及我們?yōu)槭裁匆褂胷edis,以及它的優(yōu)缺點(diǎn),感興趣的朋友跟隨小編一起學(xué)習(xí)下吧2021-05-05