欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

記錄一次并發(fā)情況下的redis導(dǎo)致服務(wù)假死的問(wèn)題解決

 更新時(shí)間:2023年09月26日 14:46:29   作者:簡(jiǎn)單簡(jiǎn)單小白  
由于Redis需要依賴于操作系統(tǒng)環(huán)境,如果系統(tǒng)資源受限,比如過(guò)量的進(jìn)程在擠占系統(tǒng)資源、系統(tǒng)死鎖等情況,本文主要介紹了記錄一次并發(fā)情況下的redis導(dǎo)致服務(wù)假死的問(wèn)題解決,感興趣的可以了解一下

問(wèn)題描述

最近項(xiàng)目在做性能壓測(cè),框架使用的是 spring boot 2.1.2 + jedis 2.9.1,80個(gè)并發(fā)持續(xù)壓測(cè)4-5分鐘服務(wù)就假死,所有的請(qǐng)求就pending,查看服務(wù)日志沒有任何異常,查看其它沒有使用redis的接口都能正常請(qǐng)求。

查找問(wèn)題思路

  • 查看了一下redis的連接配置,都是正常夠用的

  • 再使用jstack看一下堆棧信息

在這里插入圖片描述

發(fā)現(xiàn)很多WAITING的線程,再往下看都是redis的getResource方法導(dǎo)致的等待。

  • 查看redis的源碼Jedis.java

    @Override
    public void close() {
        if (dataSource != null) {//1
            if (client.isBroken()) {
                this.dataSource.returnBrokenResource(this);
            } else {
                this.dataSource.
                        returnResource(this); // 2
            }
            this.dataSource = null;   // 3
        } else {
            super.close();
        }
    }
  • 分析一下這個(gè)代碼,client.isBroken()這里默認(rèn)值是false,連接釋放的時(shí)候先釋放resource 然后再將dataSource置為null,那如果是并發(fā)的情況下話,那有可能再下一個(gè)線程進(jìn)來(lái)的時(shí)候dataSource已經(jīng)就是null了,在執(zhí)行第2步的時(shí)候dataSource剛好被置為null,那這個(gè)時(shí)候就無(wú)法釋放連接了。這個(gè)時(shí)候我們?cè)倏聪芦@取連接的方法。JedisSentinelPool.java

    @Override
    public Jedis getResource() {
        while (true) {
            Jedis jedis = super.getResource();
            jedis.setDataSource(this);  // <-- This line 
            // get a reference because it can change concurrently
            final HostAndPort master = currentHostMaster;
            final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient()
                    .getPort());
            if (master.equals(connection)) {
                // connected to the correct master
                return jedis;
            } else {
                returnBrokenResource(jedis);
            }
        }
    }

    這里jedis.setDataSource(this);設(shè)置的則為null。

問(wèn)題解決方案

我查看了一下jedis的github,在issue上有找到有人曾經(jīng)提出過(guò)這樣的問(wèn)題,https://github.com/redis/jedis/issues/1920 ,給出的解決方案是升級(jí)jedis的jar包到2.10.2版本以上,換成高版本的以后問(wèn)題果然就解決了。

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.10.2</version>
</dependency>

這里要注意一下的是jedis的版本跟spring-data-redis的版本是有一個(gè)對(duì)應(yīng)關(guān)系的。

  • spring-data-redis 2.1.x 對(duì)應(yīng)的jedis版本是2.x.x 版本

  • spring-data-redis 2.2.x 對(duì)應(yīng)的jedis 版本就是3.x版本了

分析升級(jí)版本以后的改動(dòng)

還是看那兩個(gè)類,看看新版本做了什么改動(dòng)

    public void close() {
        if (this.dataSource != null) {
            Pool<Jedis> pool = this.dataSource;
            this.dataSource = null;
            if (this.client.isBroken()) {
                pool.returnBrokenResource(this);
            } else {
                pool.returnResource(this);
            }
        } else {
            super.close();
        }
    }

這里很明顯的處理方式就是講dataSource復(fù)制給pool,然后用pool去釋放資源,這個(gè)時(shí)候設(shè)置dataSource與這個(gè)就沒有關(guān)系了,就不存在釋放資源釋放不了的情況了。

到此這篇關(guān)于記錄一次并發(fā)情況下的redis導(dǎo)致服務(wù)假死的問(wèn)題解決的文章就介紹到這了,更多相關(guān)redis導(dǎo)致服務(wù)假死內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論