国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

這篇具有很好參考價值的文章主要介紹了記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

開心一刻

  昨晚和一個朋友聊天

  我:處對象嗎,咱倆試試?

  朋友:我有對象

  我:我不信,有對象不公開?

  朋友:不好公開,我當?shù)男∪?/p>

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

問題背景

  程序在生產(chǎn)環(huán)境穩(wěn)定的跑著

  直到有一天,公司執(zhí)行組件漏洞掃描,有漏洞的?jar?要進行升級修復(fù)

  然后我就按著掃描報告將有漏洞的?jar?修復(fù)到指定的版本

  自己在開發(fā)環(huán)境也做了主流業(yè)務(wù)的測試,沒有任何異常,穩(wěn)如老狗

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  提測之后,測試小姐姐也沒測出問題,一切都是這么美好

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  結(jié)果升級到生產(chǎn)后,生產(chǎn)日志瘋狂報錯:?org.redisson.client.RedisException: ERR unknown command 'WAIT'?

  完整的異常堆棧信息類似如下

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析
org.redisson.client.RedisException: ERR unknown command 'WAIT'. channel: [id: 0x84149c6e, L:/192.168.2.40:3592 - R:/47.98.21.100:6379] command: (WAIT), params: [1, 1000]

    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:346)
    at org.redisson.client.handler.CommandDecoder.decodeCommandBatch(CommandDecoder.java:247)
    at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:189)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:117)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:102)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
    at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)
View Code

  突然來個這個鬼玩意,腦闊有點疼

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  先讓運維同事回滾,然后就開始了我的問題排查之旅

問題排查與處理

  項目搭建

  示例代碼:redisson-spring-boot-demo,執(zhí)行如下?test?方法即可進行測試

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  項目很簡單,通過?redisson-spring-boot-starter?引入?redisson?

  扯點題外的東西,關(guān)于?redisson-spring-boot-starter?的配置方式

  配置方式有很多種,官網(wǎng)文檔做了說明,有 4 種配置方式:README.md

  方式 1:

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  方式 2:

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  方式 3:

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  方式 4:

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  如果 4 種方式都配置,最終生效的是哪一種?

  樓主我此刻只想給你個大嘴巴子,怎么這么多問題?

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  既然你們都提出來了,那我就不能不管,誰讓我太愛你們了,盤它!

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  從哪盤,怎么盤?

  源碼之下無密碼,我們就從源碼去盤,找到自動配置類

 ?。P(guān)于?spring-boot?的自動配置,參考:springboot2.0.3源碼篇 - 自動配置的實現(xiàn),發(fā)現(xiàn)也不是那么復(fù)雜)

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  ?RedissonAutoConfiguration?中有如下代碼

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redisson() throws IOException {
    Config config = null;
    Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
    Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
    Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
    int timeout;
    if(null == timeoutValue){
        timeout = 10000;
    }else if (!(timeoutValue instanceof Integer)) {
        Method millisMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
        timeout = ((Long) ReflectionUtils.invokeMethod(millisMethod, timeoutValue)).intValue();
    } else {
        timeout = (Integer)timeoutValue;
    }

    if (redissonProperties.getConfig() != null) {
        try {
            config = Config.fromYAML(redissonProperties.getConfig());
        } catch (IOException e) {
            try {
                config = Config.fromJSON(redissonProperties.getConfig());
            } catch (IOException e1) {
                throw new IllegalArgumentException("Can't parse config", e1);
            }
        }
    } else if (redissonProperties.getFile() != null) {
        try {
            InputStream is = getConfigStream();
            config = Config.fromYAML(is);
        } catch (IOException e) {
            // trying next format
            try {
                InputStream is = getConfigStream();
                config = Config.fromJSON(is);
            } catch (IOException e1) {
                throw new IllegalArgumentException("Can't parse config", e1);
            }
        }
    } else if (redisProperties.getSentinel() != null) {
        Method nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
        Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());

        String[] nodes;
        if (nodesValue instanceof String) {
            nodes = convert(Arrays.asList(((String)nodesValue).split(",")));
        } else {
            nodes = convert((List<String>)nodesValue);
        }

        config = new Config();
        config.useSentinelServers()
            .setMasterName(redisProperties.getSentinel().getMaster())
            .addSentinelAddress(nodes)
            .setDatabase(redisProperties.getDatabase())
            .setConnectTimeout(timeout)
            .setPassword(redisProperties.getPassword());
    } else if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
        Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties);
        Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
        List<String> nodesObject = (List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject);

        String[] nodes = convert(nodesObject);

        config = new Config();
        config.useClusterServers()
            .addNodeAddress(nodes)
            .setConnectTimeout(timeout)
            .setPassword(redisProperties.getPassword());
    } else {
        config = new Config();
        String prefix = REDIS_PROTOCOL_PREFIX;
        Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
        if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, redisProperties)) {
            prefix = REDISS_PROTOCOL_PREFIX;
        }

        config.useSingleServer()
            .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
            .setConnectTimeout(timeout)
            .setDatabase(redisProperties.getDatabase())
            .setPassword(redisProperties.getPassword());
    }
    if (redissonAutoConfigurationCustomizers != null) {
        for (RedissonAutoConfigurationCustomizer customizer : redissonAutoConfigurationCustomizers) {
            customizer.customize(config);
        }
    }
    return Redisson.create(config);
}
View Code

  誰先生效,一目了然!

  問題分析

  有點扯遠了,我們再回到主題

  ?jar?未升級之前,?redisson-spring-boot-starter?的版本是?3.13.6?,此版本在開發(fā)、測試、生產(chǎn)環(huán)境都是能正常跑的

  把?redisson-spring-boot-starter?升級到?3.15.0?之后,在開發(fā)、測試環(huán)境運行正常,上生產(chǎn)后則報錯:?org.redisson.client.RedisException: ERR unknown command 'WAIT'?

  因為沒做任何的業(yè)務(wù)代碼修改,所以問題肯定出在升級后的?redisson-spring-boot-starter?,你說是不是?

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  那這個問題肯定有前輩碰到過,我們?nèi)?redisson?的issues看看

  直接搜索關(guān)鍵字:?WAIT?

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  點進去你就會發(fā)現(xiàn)

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  這不就是我們的生產(chǎn)異常?

  我立馬找運維確認,生產(chǎn)確實用的是阿里云?redis?,并且是代理模式!

  出于嚴謹,我們還需要對:?3.14.0?是正常的,?3.14.1?有異常 這個結(jié)論進行驗證

  因為公司未提供測試環(huán)境的阿里云?redis?,所以樓主只能自掏腰包購買一套最低配的阿里云?redis?

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  就沖樓主這認真負責的態(tài)度,你們不得一鍵三連?

  我們來看下驗證結(jié)果

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  結(jié)論確實是對的

  樓主又去阿里云翻了一下手冊

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  我們是不是可以把問題范圍縮小了

  ?redisson??3.14.0?未引入?wait?命令,而?3.14.1?引入了,所以問題產(chǎn)生了!

  但這只是我們的猜想,我們需要強有力的支撐,找誰了?肯定還得是源碼!

  WAIT 源碼分析

  我們先跟?3.14.0?

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  我們可以看到,真正發(fā)送給?redis-server?執(zhí)行的命令不只是加鎖的腳本,還有?WAIT?命令!

  只是因為異步執(zhí)行命令,只關(guān)注了加鎖腳本的執(zhí)行結(jié)果,而并沒有關(guān)注?WAIT?命令的執(zhí)行結(jié)果

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  也就是說?3.14.0?也有?WAIT?命令,并且在阿里云?redis?的代理模式下執(zhí)行是失敗的,只是?redisson?并沒有去管?WAIT?命令的執(zhí)行結(jié)果

  所以只要加鎖命令執(zhí)行是成功的,那么?Redisson?就認為執(zhí)行結(jié)果是成功的

  這也就是?3.14.0?執(zhí)行成功,沒有報異常的原因

  我們再來看看?3.14.1?

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  真正發(fā)送給?redis-server?執(zhí)行的命令有加鎖腳本,也有?WAIT?命令

  兩個命令的執(zhí)行結(jié)果都有關(guān)注

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析

  加鎖腳本執(zhí)行是成功的,?redis?已經(jīng)有對應(yīng)的記錄

  而阿里云?redis?的代理模式是不支持?WAIT?命令,所以?WAIT?命令是執(zhí)行失敗的

  而最終的執(zhí)行結(jié)果是所有命令的執(zhí)行結(jié)果,所以最終執(zhí)行結(jié)果是失敗的!

  問題處理

  那么如何正確的升級到生產(chǎn)環(huán)境了?

  1、將?redisson?版本降到?3.14.0?

    不去關(guān)注?WAIT?命令的執(zhí)行結(jié)果,相當于沒有?WAIT?命令

    這個可能產(chǎn)生什么問題(?redisson?引入?WAIT?命令的意圖),轉(zhuǎn)動你們智慧的頭腦,評論區(qū)告訴我答案

  2、阿里云?redis?改成直連模式

總結(jié)

  1、環(huán)境一致的重要性

    測試環(huán)境一定要保證和生產(chǎn)環(huán)境一致

    否則就會出現(xiàn)和樓主一樣的問題,其他環(huán)境都沒問題,就生產(chǎn)有問題

    環(huán)境不一致,排查問題也很棘手

  2、?Redisson?很早就會附加?WAIT?命令,只是從?3.14.1?開始才關(guān)注?WAIT?命令的執(zhí)行結(jié)果

  3、對于維護中的老項目,代碼能不動就不動,配置能不動就不動

記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析文章來源地址http://www.zghlxwxcb.cn/news/detail-705823.html

到了這里,關(guān)于記一次 Redisson 線上問題 → ERR unknown command 'WAIT' 的排查與分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 記一次線上問題引發(fā)的對 Mysql 鎖機制分析

    最近雙十一開門紅期間組內(nèi)出現(xiàn)了一次因 Mysql 死鎖導(dǎo)致的線上問題,當時從監(jiān)控可以看到數(shù)據(jù)庫活躍連接數(shù)飆升,導(dǎo)致應(yīng)用層數(shù)據(jù)庫連接池被打滿,后續(xù)所有請求都因獲取不到連接而失敗 整體業(yè)務(wù)代碼精簡邏輯如下: 數(shù)據(jù)庫實例監(jiān)控: 當時通過分析上游問題流量限流解決后

    2024年02月05日
    瀏覽(29)
  • 記一次Redisson連接k8s環(huán)境Redis報UnknownHostException-域名解析錯誤問題解決

    記一次Redisson連接k8s環(huán)境Redis報UnknownHostException-域名解析錯誤問題解決

    一直聽說Redisson分布式鎖好用,終于在項目上使用了!在本地測試完畢,一上測試環(huán)境,運維就反饋服務(wù)沒起來,拉日志一看,是以下報錯 主要報錯信息是 于是乎,上github看了一下,發(fā)現(xiàn)這還是一個比較熱門dns解析失敗的問題,好多人都遇到了同樣的問題。想著開源項目,這

    2024年02月04日
    瀏覽(26)
  • gitlab 16.x - ERR unknown command ‘HELLO‘

    gitlab 16.x - ERR unknown command ‘HELLO‘

    gitlab部分操作報錯500。通過Rails日志發(fā)現(xiàn)以下報錯: 報錯: RedisClient::CommandError ERR unknown command \\\'HELLO\\\' 日志報錯是Redis執(zhí)行HELLO命令報錯,這個命令適用于指定RESP版本。 Gitlab官方文檔要求16.0以上版本,需要使用Redis 6.x or 7.x Redis 6.x 開始支持RESP3 連接到Redis,執(zhí)行Hello 2成功;執(zhí)

    2024年04月26日
    瀏覽(22)
  • 記一次線上BUG排查過程

    記一次線上BUG排查過程

    1. 線上遇到一個非常奇怪的bug,為一個用戶分配業(yè)務(wù)線類型后,該用戶登錄時,提示502,但其它的用戶登錄完全是正常的 2. 問題現(xiàn)象 3. 排查思路 先去看線上日志,看是否有error,但日志里邊這個接口200正常返回 本地debug,也復(fù)現(xiàn)一樣問題,在分配角色類型超過22個總數(shù)時就報

    2024年02月09日
    瀏覽(30)
  • 記一次線上kafka造成的事故

    背景:所有的原始數(shù)據(jù)均存儲在mysql,mysql會通過binlog將數(shù)據(jù)同步至kafka消息隊列,但是有人將mysql中的數(shù)據(jù)進行刪除(大概有2、3年的數(shù)據(jù)),被刪除的數(shù)據(jù)也通過binlog被同步至消息隊列里導(dǎo)致大量消息積壓,且該消息隊列只有3個分區(qū),最多3個線程消費,消費方即使過濾也遠

    2024年02月13日
    瀏覽(19)
  • Caused by: io.lettuce.core.RedisCommandExecutionException: ERR unknown command `CONFIG`

    Caused by: io.lettuce.core.RedisCommandExecutionException: ERR unknown command `CONFIG`

    項目本機啟動運行正常,打成jar包發(fā)布測試環(huán)境–公司測試服務(wù)器正常啟動運行,項目上線前需要發(fā)布在客戶購買的亞馬遜的K8S服務(wù)器,同時客戶在亞馬遜購買了Redis服務(wù)器,PostgreSQL服務(wù)器,所以新建了配置文件,將代碼構(gòu)建為鏡像推送至客戶服務(wù)器,然后進行啟動編譯,連接數(shù)據(jù)庫一

    2024年02月15日
    瀏覽(22)
  • 得物-Golang-記一次線上服務(wù)的內(nèi)存泄露排查

    得物-Golang-記一次線上服務(wù)的內(nèi)存泄露排查

    在風和日麗的一天,本人正看著需求、敲著代碼,展望美好的未來。突然收到一條內(nèi)存使用率過高的告警。 告警的這個項目,老代碼是python的,最近一直在go化。隨著go化率不斷上升,發(fā)現(xiàn)內(nèi)存的RSS使用率越飆越高。最終達到容器內(nèi)存限制后,進程會自動重啟。RSS如下圖所示

    2024年02月04日
    瀏覽(20)
  • npm ERR! code 128npm ERR! An unknown git error occurrednpm ERR! command git --no-replace-objects l

    npm ERR! code 128npm ERR! An unknown git error occurrednpm ERR! command git --no-replace-objects l

    在安裝vue-element-admin 項目所需依賴時,出現(xiàn)了如下報錯信息 1、使用下面的命令,達到,把地址里的 ssh://git@ 換成 https:// 的目的 2、然后重新通過 npm install 安裝項目依賴 效果圖: ? ? ?

    2024年02月12日
    瀏覽(24)
  • npm ERR code 128 npm ERR An unknown git error occurred npm ERR command git --no-replace-objects l

    npm ERR code 128 npm ERR An unknown git error occurred npm ERR command git --no-replace-objects l

    在git上下載以來的vue-element-admin 安裝依賴的時候報錯。 以上這個報錯是我最頭疼的,弄了很久,網(wǎng)上查閱了各種文章,還是沒有找到解決的辦法,最后我通過自己解決了問題。 這個問題是ssh的報錯,我們需要想辦法把ssh改成https,這樣就可以解決啦,那么下面我來介紹一下如

    2024年02月16日
    瀏覽(23)
  • 記一次pdjs時安裝glob出現(xiàn),npm ERR! code ETARGET和npm ERR! code ELIFECYCLE

    記一次pdjs時安裝glob出現(xiàn),npm ERR! code ETARGET和npm ERR! code ELIFECYCLE

    如往常一樣,我使用pdjs來編譯proto文件,但出現(xiàn)了以下報錯: 大致就是pdjs的util在嘗試執(zhí)行` npm install glob@^7.2.1 escodegen@^1.13.0 `時出錯了 嘗試手動執(zhí)行安裝,` escodegen `被正確安裝,但` glob@^7.2.1 `出錯 也就是找不到符合條件的版本為7.2.1的包 執(zhí)行` npm view glob versions `,出來了很

    2024年02月05日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包