生产-已解决-Redis资源池耗尽 报错JedisConnectionException: Could not get a resource from the pool

背景交代:

公司某个项目,生产环境用的自建在服务器内的redis ,由于访问量不大,redis用的是单机的
针对自建的redis ,我一直是持有不看好意见的。自建redis 容易宕机,宕机后数据全无,且监控难做,虽然有普米修斯这种监控工具面板,但粒度、报警等还是达不到实际需求。当然 如果你们公司有能力,有专门的团队开发运维监控工具当我没说。

线上大促期间发生了几次,redis 报错问题,排查日志后,原因大多为报错:JedisConnectionException: Could not get a resource from the pool

因为自建redis,无法细粒度看到过去时间的连接数、连接池资源,排查问题难上加南。

一、迁移前

redis 连接池 逻辑代码

@Data
@Configuration
public class JedisConfig {

    @Value("${spring.jedis.config.db}")
    private Integer db;
    @Value("${spring.jedis.config.maxTotal}")
    private Integer maxTotal;
    @Value("${spring.jedis.config.maxIdle}")
    private Integer maxIdle;
    @Value("${spring.jedis.config.minIdle}")
    private Integer minIdle;
    @Value("${spring.jedis.config.maxWaitMillis}")
    private Long maxWaitMillis;
    @Value("${spring.jedis.config.testOnBorrow}")
    private Boolean testOnBorrow;
    @Value("${spring.jedis.host}")
    private String host;
    @Value("${spring.jedis.port}")
    private Integer port;
    @Value("${spring.jedis.password}")
    private String password;

    @Bean
    public JedisPoolConfig getJedisPoolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setMaxWaitMillis(maxWaitMillis);
        config.setTestOnBorrow(testOnBorrow);
        return config;
    }
    @Bean
    public JedisPool getJedisPool(@Autowired JedisPoolConfig config) {
        JedisPool pool = null;
        if (StringUtils.isNotBlank(password)) {
            pool = new JedisPool(config, host, port, 1000, password, db);
        } else {
            // 该模式一般用户测试,没有选择数据库
            pool = new JedisPool(config, host, port, 1000);
        }
        return pool;
    }
}

配置文件application.properties

spring.jedis.host=127.0.0.1
spring.jedis.port=6379
spring.jedis.password=xxxxxxxxx
spring.jedis.config.db=0
spring.jedis.config.maxTotal=500
spring.jedis.config.maxIdle=500
spring.jedis.config.minIdle=50
spring.jedis.config.maxWaitMillis=15000
spring.jedis.config.testOnBorrow=true
spring.jedis.timeout.default=1800000
spring.jedis.timeout.user=172800000

似乎没什么问题

既然是redis 连接池报资源不足,那就往这个方向排查

阿里云JedisPool优化建议

在这里插入图片描述
在这里插入图片描述
看到具体参数:
maxTotal:资源池中的最大连接数

关键参数设置建议 maxTotal(最大连接数)

想合理设置maxTotal(最大连接数)需要考虑的因素较多,如:

业务希望的Redis并发量;

客户端执行命令时间;

Redis资源,例如nodes (如应用ECS个数等) * maxTotal不能超过Redis的最大连接数(可在实例详情页面查看);

资源开销,例如虽然希望控制空闲连接,但又不希望因为连接池中频繁地释放和创建连接造成不必要的开销。

假设一次命令时间,即borrow|return resource加上Jedis执行命令 (
含网络耗时)的平均耗时约为1ms,一个连接的QPS大约是1s/1ms =
1000,而业务期望的单个Redis的QPS是50000(业务总的QPS/Redis分片个数),那么理论上需要的资源池大小(即MaxTotal)是50000
/ 1000 = 50。

但事实上这只是个理论值,除此之外还要预留一些资源,所以maxTotal可以比理论值大一些。这个值不是越大越好,一方面连接太多会占用客户端和服务端资源,另一方面对于Redis这种高QPS的服务器,如果出现大命令的阻塞,即使设置再大的资源池也无济于事。

maxIdle与minIdle

maxIdle实际上才是业务需要的最大连接数,maxTotal 是为了给出余量,所以 maxIdle 不要设置得过小,否则会有new
Jedis(新连接)开销,而minIdle是为了控制空闲资源检测。

连接池的最佳性能是maxTotal=maxIdle,这样就避免了连接池伸缩带来的性能干扰。如果您的业务存在突峰访问,建议设置这两个参数的值相等;如果并发量不大或者maxIdle设置过高,则会导致不必要的连接资源浪费。

您可以根据实际总QPS和调用Redis的客户端规模整体评估每个节点所使用的连接池大小。

使用监控获取合理值

在实际环境中,比较可靠的方法是通过监控来尝试获取参数的最佳值。可以考虑通过JMX等方式实现监控,从而找到合理值

maxIdle:资源池允许的最大空闲连接数

minIdle:资源池确保的最少空闲连接数

maxIdle实际上才是业务需要的最大连接数,maxTotal 是为了给出余量,所以 maxIdle 不要设置得过小,否则会有new
Jedis(新连接)开销,而minIdle是为了控制空闲资源检测。
连接池的最佳性能是maxTotal=maxIdle,这样就避免了连接池伸缩带来的性能干扰。如果您的业务存在突峰访问,建议设置这两个参数的值相等;如果并发量不大或者maxIdle设置过高,则会导致不必要的连接资源浪费。
您可以根据实际总QPS和调用Redis的客户端规模整体评估每个节点所使用的连接池大小。


二、迁移后

利用阿里云DTS 迁移工具,将旧数据实施同步至线上TairDB。
有了强大的、细粒度监控视图。
在这里插入图片描述

调优了redis配置参数:

# Redis服务器地址
spring.jedis.host=r-wz9yl4yc6d6lij33zq.redis.rds.aliyuncs.com
# Redis服务器连接端口
spring.jedis.port=6379
# Redis服务器连接密码(默认为空)
spring.jedis.password=xxxxxxx
# Redis数据库索引(默认为0
spring.jedis.config.db=0
#资源池中的最大连接数
spring.jedis.config.maxTotal=2000
#资源池允许的最大空闲连接数
spring.jedis.config.maxIdle=2000
#资源池确保的最少空闲连接数
spring.jedis.config.minIdle=100
#当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)。-1(表示永不超时)不建议使用默认值。
spring.jedis.config.maxWaitMillis=15000
#向资源池归还连接时是否做连接有效性检测(ping)。检测到无效连接将会被移除。默认:false  业务量很大时候建议设置为false,减少一次ping的开销。
spring.jedis.config.testOnBorrow=true
# Redis服务器连接超时时间(毫秒)
spring.jedis.timeout=10000
spring.jedis.timeout.default=1800000
spring.jedis.timeout.user=172800000
#建议开启,请注意应用本身也需要开启。
spring.jedis.config.jmxEnabled=true

增加了资源池中的最大连接数、将最大连接数与最大空闲连接数调大,并设置成一致,减少因为伸缩扩容,浪费资源。

增加调用者最大等待时间maxWaitMillis=15000。

将这些配置设置后,没有出现过,资源不足报错情况。
记录此文。

2024.05.25 于广州

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真香号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值