【使用jedis时遇到的坑】

这里写自定义目录标题

使用jedis时遇到的坑 Socket closed PONG

最近接手一个项目,前任用的是jedis+连接池,主要用于存储token跟分布式锁用的,配置如下

@Configuration
@Slf4j
public class RedisBaseConfig {
    @Value("${auth.redis.host}")
    protected String host;
    @Value("${auth.redis.password}")
    protected String password;
    @Value("${auth.redis.database}")
    protected Integer database;

    protected static final int PORT = 6379;

    @Bean(name = "authJedisConnectionFactory")
    public JedisConnectionFactory authJedisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setDatabase(database);
        factory.setHostName(host);
        factory.setPassword(password);
        factory.setPort(PORT);
        factory.setTimeout(1000 * 3);
        factory.setPoolConfig(poolConfig());

        log.info("redis config=========" + host);
        return factory;
    }

    private JedisPoolConfig poolConfig() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(1000);
        poolConfig.setMinIdle(100);
        poolConfig.setMaxWaitMillis(1000 * 60 * 3);
        //11.11新增配置,解决空闲时期的连接释放
        poolConfig.setTestWhileIdle(true);
        poolConfig.setMinEvictableIdleTimeMillis(30 * 1000);
        poolConfig.setTimeBetweenEvictionRunsMillis(60 * 1000);
        poolConfig.setNumTestsPerEvictionRun(-1);
        //
        return poolConfig;
    }
}

项目运行过程中,经常会报一个错误redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Socket closed
查了一波资料后,找到一个解决办法在链接池里配两个参数
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);

配置完后确实发现Socket closed的报错少了,但是又出现个新的问题,缓存get数据竟然取到了PONG,而不是存的内容。
导致这个问题的原因是这个配置poolConfig.setTestOnBorrow(true);
这个配置表示的若开启,每一次获取redis实例时会先ping一下redis,才进行命令的发送,并且出现了有get命令直接返回PONG
开启了检查是否可用时在引入每个redis时都会发送ping命令,造成效率较低,在有一定并发量的时候通过看redis监控发现在返回PONG时,redis后台服务器此时接收到两个接连的ping命令,导致将PONG返回给了get命令,并且接口耗时比较高。
去掉该配置后:接口耗时减少一半,不再出现get命令返回PONG的情况,但并发量大时也会出现socket closed的错误(寻找答案中)
目前处理,把jedis升到最高版本

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

并且配置类需要改变下,因为之前的写法一直提示过时了,另外这个配置类目前发现有两种写法,一种是通过工厂类来获取实例的,一种是直接通过连接池获取的

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @program: gw-bff
 * @description:
 * @author: maliang
 * @create: 2022/01/05 15:23
 */
@Configuration
@Slf4j
public class RedisBaseConfig {
    @Value("${auth.redis.host}")
    protected String host;
    @Value("${auth.redis.password}")
    protected String password;
    @Value("${auth.redis.database}")
    protected Integer database;
    protected static final int timeout = 3200;
    protected static final int PORT = 6379;

    @Bean(name = "authJedisConnectionFactory")
    public JedisConnectionFactory authJedisConnectionFactory() {
        RedisStandaloneConfiguration factory = new RedisStandaloneConfiguration();
        factory.setDatabase(database);
        factory.setHostName(host);
        factory.setPassword(password);
        factory.setPort(PORT);
        log.info("redis config=========" + host);
        JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
        JedisClientConfiguration jedisClientConfiguration = jedisClientConfigurationBuilder.usePooling().poolConfig(poolConfig()).build();
        return new JedisConnectionFactory(factory,jedisClientConfiguration);
    }

    private JedisPoolConfig poolConfig() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(1000);
        poolConfig.setMinIdle(100);
        poolConfig.setMaxWaitMillis(1000 * 60 * 3);
        //11.11新增配置,解决空闲时期的连接释放
        poolConfig.setTestWhileIdle(true);
        poolConfig.setMinEvictableIdleTimeMillis(30 * 1000);
        poolConfig.setTimeBetweenEvictionRunsMillis(60 * 1000);
        poolConfig.setNumTestsPerEvictionRun(-1);
        poolConfig.setTestOnReturn(true);
        //
        return poolConfig;
    }

    /**
     * 初始化Redis连接池
     */
//    @Bean
//    public JedisPool generateJedisPoolFactory() {
//        JedisPoolConfig poolConfig = new JedisPoolConfig();
//        poolConfig.setMaxTotal(210);
//        poolConfig.setMaxIdle(20);
//        poolConfig.setMinIdle(5);
//        poolConfig.setMaxWaitMillis(1000 * 60 * 3);
//        // 连接耗尽时是否阻塞, false报异常,true阻塞直到超时, 默认true
//        poolConfig.setBlockWhenExhausted(Boolean.TRUE);
            JedisPool jedisPool = new JedisPool(poolConfig, host, port, timeout);
//        // 若设置了Redis密码,请调用如下构造函数
//        JedisPool jedisPool = new JedisPool(poolConfig, host, PORT, timeout, password);
//        return jedisPool;
//    }


}

先用这个配置在测试环境跑一下,要是还报错的话,就打算不用jedis了。

后续:还是报Socket closed,后来仔细阅读了下代码,发现之前写的redis工具类里是这样引用的
在这里插入图片描述
每次使用的时候都是用的类下的变量jedis去连接池里获取一个实力,但是这个类是个单例,大家都公用这个一个变量,也就是说不同线程都用的一个变量,有线程把他close,那么正在用的是不是就报socket close了。然后我把这个类的变量改到了每个方法里
在这里插入图片描述
目前在测试环境跑了一段时间没有再发现Socket closed的报错了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值