7.1育勺、發(fā)現(xiàn)阻塞

Redis是典型的單線程架構(gòu),所有的讀寫操作都是在一條主線程中完成的腹躁。當(dāng)Redis用于高并發(fā)場景時(shí)南蓬,這條線程就變成了它的生命線。如果出現(xiàn)阻塞烧颖,哪怕是很短時(shí)間窄陡,對于我們的應(yīng)用來說都是噩夢。導(dǎo)致阻塞問題的場景大致分為內(nèi)在原因和外在原因:

  • 內(nèi)在原因包括:不合理地使用API或數(shù)據(jù)結(jié)構(gòu)鳖悠、CPU飽和优妙、持久化阻塞等套硼。

  • 外在原因包括:CPU競爭胞皱、內(nèi)存交換、網(wǎng)絡(luò)問題等雾鬼。

本章我們聚焦于Redis阻塞問題宴树,通過學(xué)習(xí)本章可掌握快速定位和解決Redis阻塞的思路和技巧。

發(fā)現(xiàn)阻塞

當(dāng)Redis阻塞時(shí)又憨,線上應(yīng)用服務(wù)應(yīng)該最先感知到,這時(shí)應(yīng)用方會(huì)收到大量Redis超時(shí)異常寒匙,比如Jedis客戶端會(huì)拋出JedisConnectionException異常锄弱。常見的做法是在應(yīng)用方加入異常統(tǒng)計(jì)并通過郵件/短信/微信報(bào)警祸憋,以便及時(shí)發(fā)現(xiàn)通知問題。開發(fā)人員需要處理如何統(tǒng)計(jì)異常以及觸發(fā)報(bào)警的時(shí)機(jī)狈谊。何時(shí)觸發(fā)報(bào)警一般根據(jù)應(yīng)用的并發(fā)量決定沟沙,如1分鐘內(nèi)超過10個(gè)異常觸發(fā)報(bào)警。在實(shí)際異常統(tǒng)計(jì)要注意赎瞎,由于Redis調(diào)用API會(huì)分散在項(xiàng)目的多個(gè)地方颊咬,每個(gè)地方都監(jiān)聽異常并加入監(jiān)控代碼必然難以維護(hù)。這是可以借助于日志系統(tǒng)敞临,如Java語言可以使用logback或log4j。當(dāng)異常發(fā)生時(shí)挺尿,異常信息最終會(huì)被日志系統(tǒng)收集到Appender(輸出目的地)炊邦,默認(rèn)的Appender一般是具體的日志文件,開發(fā)人員可以自定義一個(gè)Appender窄俏,用于專門統(tǒng)計(jì)異常和觸發(fā)報(bào)警邏輯碘菜,如下圖所示:

2019-04-26-20-55-03.png

以Java的logback為例限寞,實(shí)現(xiàn)代碼如下:

public class RedisAppender extends AppenderBase<ILoggingEvent> {
    //使用guava的AtomicLongMap昆烁,用于并發(fā)計(jì)數(shù)
    public static final AtomicLongMap<String> ATOMIC_LONG_MAP = AtomicLongMap.create();
    static{
        //自定義Appender加入到logback的rootLogger中
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
        ErrorStatisticsAppender errorStatisticsAppender = new ErrorStatisticsAppender();
        errorStatisticsAppender.setContext(loggerContext);
        errorStatisticsAppender.start();
        rootLogger.addAppender(errorStatisticsAppender);
    }
}

    //重寫接收日志時(shí)間方法
    protexted void append(ILoggingEvent event) {
        //只監(jiān)控error級別日志
        if(event.getLevel() == Level.ERROR){
            IThrowableProxy throwableProxy = event.getThrowableProxy();
            //確認(rèn)拋出異常
            if (throwableProxy != null) {
                //以每分鐘為key静尼,記錄每分鐘異常數(shù)量
                String key = DateUtil.formatDate(new Date(), "yyyyMMddHHmm");
                long errorCount = ATOMIC_LONG_MAP.increnmentAndGet(key);
                if (errorCount > 10) {
                    //超過10次觸發(fā)報(bào)警代碼
                }
                //清理歷史計(jì)數(shù)統(tǒng)計(jì)传泊,防止極端情況下內(nèi)存泄露
                for (String oldKey : ATOMIC_LONG_MAP.asMap().keySet()) {
                    if (!StringUtils.equals(key, oldKey)) {
                        ATOMIC_LONG_MAP.remove(oldKey);
                    }
                }
            }
        }
    }

開發(fā)提示:借助日志系統(tǒng)統(tǒng)計(jì)異常的前提是,需要項(xiàng)目必須使用日志API進(jìn)行異常統(tǒng)一輸出拦盹,比如所有的一場都通過logger.error打印普舆,這應(yīng)該作為開發(fā)規(guī)范推廣。其他編程語言也可以采用類似的日志系統(tǒng)實(shí)現(xiàn)異常統(tǒng)計(jì)報(bào)警沼侣。

應(yīng)用方加入異常監(jiān)控之后還存在一個(gè)問題歉秫,當(dāng)開發(fā)人員接到異常報(bào)警后,通常會(huì)去線上服務(wù)器查看錯(cuò)誤日志細(xì)節(jié)轧膘。這是如果應(yīng)用操作的是多個(gè)Redis節(jié)點(diǎn)(比如使用Redis集群)兔甘,如何決定是哪一個(gè)節(jié)點(diǎn)超時(shí)還是所有的節(jié)點(diǎn)都有超時(shí)呢?這是線上很常見的需求裂明,但絕大多數(shù)的客戶端類庫并沒有在異常信息中打印ip和port信息,導(dǎo)致無法快速定位是哪個(gè)Redis節(jié)點(diǎn)超時(shí)。不過修改Redis客戶端成本很低提岔,比如Jedis只需要修改Conneciton類下的connect、sendCommand碱蒙、readProtocalWithCheckingBroken方法專門捕獲連接夯巷,發(fā)送命令哀墓,協(xié)議讀取時(shí)間的異常。由于客戶端類庫都會(huì)保存ip和port信息后雷,在異常發(fā)生時(shí)很容易打印出對應(yīng)節(jié)點(diǎn)的ip和port吠各,輔助我們快速定位問題節(jié)點(diǎn)。

除了在應(yīng)用方加入統(tǒng)計(jì)報(bào)警邏輯之外贾漏,還可以借助Redis監(jiān)控系統(tǒng)發(fā)現(xiàn)阻塞問題,當(dāng)監(jiān)控系統(tǒng)監(jiān)測到Redis運(yùn)行期的一些關(guān)鍵指標(biāo)出現(xiàn)不正常時(shí)會(huì)觸發(fā)報(bào)警梳码。Redis相關(guān)的監(jiān)控系統(tǒng)開源的方案有很多掰茶,一些公司內(nèi)部也會(huì)自己開發(fā)監(jiān)控系統(tǒng)硕盹。一個(gè)可靠的Redis監(jiān)控系統(tǒng)首先需要做到對關(guān)鍵指標(biāo)全方位監(jiān)控和異常識(shí)別,輔助開發(fā)運(yùn)維人員發(fā)現(xiàn)定位問題啊胶。如果Redis服務(wù)沒有引入監(jiān)控系統(tǒng)作輔助支撐,對于線上的服務(wù)是非常不負(fù)責(zé)任和危險(xiǎn)的焰坪。這里推薦CacheCloud系統(tǒng)聘惦,它內(nèi)部的統(tǒng)計(jì)監(jiān)控模塊能夠很好地輔助工程師發(fā)現(xiàn)定位問題。

監(jiān)控系統(tǒng)所監(jiān)控的關(guān)鍵指標(biāo)有很多黔漂,如命令消耗晶默、慢查詢、持久化阻塞剂跟、連接拒絕减途、CPU/內(nèi)存/網(wǎng)絡(luò)/磁盤使用過載等。當(dāng)出現(xiàn)阻塞時(shí)如果相關(guān)人員不能深刻理解這些關(guān)鍵指標(biāo)的含義和背后的原理辽剧,會(huì)嚴(yán)重影響解決問題的速度。后面的內(nèi)容將圍繞引起Redis阻塞的原因做重點(diǎn)說明怕轿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砖第,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子放吩,更是在濱河造成了極大的恐慌,老刑警劉巖渡紫,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惕澎,死亡現(xiàn)場離奇詭異唧喉,居然都是意外死亡忍抽,警方通過查閱死者的電腦和手機(jī)干跛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門楼入,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘉熊,“玉大人记舆,你說我怎么就攤上這事泽腮。” “怎么了碧磅?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵鲸郊,是天一觀的道長秆撮。 經(jīng)常有香客問我职辨,道長舒裤,這世上最難降的妖魔是什么腾供? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮黎侈,結(jié)果婚禮上峻汉,老公的妹妹穿的比我還像新娘休吠。我一直安慰自己瘤礁,他們只是感情好柜思,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赡盘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葱淳。 梳的紋絲不亂的頭發(fā)上抛姑,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音皿桑,去河邊找鬼唁毒。 笑死星爪,一個(gè)胖子當(dāng)著我的面吹牛浆西,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顽腾,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼近零,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抄肖?” 一聲冷哼從身側(cè)響起久信,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漓摩,沒想到半個(gè)月后裙士,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡管毙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年腿椎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夭咬。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卓舵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肿嘲,到底是詐尸還是另有隱情睦刃,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站虾宇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏怔接。R本人自食惡果不足惜岸军,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望方妖。 院中可真熱鬧党觅,春花似錦仔役、人聲如沸又兵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秽梅。三九已至,卻和暖如春晒来,著一層夾襖步出監(jiān)牢的瞬間荧降,已是汗流浹背朵诫。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留随夸,地道東北人宾毒。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像幢竹,于是被迫代替她去往敵國和親焕毫。 傳聞我的和親對象是個(gè)殘疾皇子邑飒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容