导读

目前线上报错如下:

[Finalizer] WARN  [io.lettuce.core.resource.DefaultClientResources 573] -  io.lettuce.core.resource.DefaultClientResources was not shut down properly, shutdown() was not called before it's garbage-collected. Call shutdown() or shutdown(long,long,TimeUnit)  []
ERROR [io.netty.util.ResourceLeakDetector 317] -  LEAK: HashedWheelTimer.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 
Created at:
	io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:284)
	io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:217)
	io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:196)
	io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:178)
	io.netty.util.HashedWheelTimer.<init>(HashedWheelTimer.java:162)
	io.lettuce.core.resource.DefaultClientResources.<init>(DefaultClientResources.java:169)
	io.lettuce.core.resource.DefaultClientResources$Builder.build(DefaultClientResources.java:532)
	io.lettuce.core.resource.DefaultClientResources.create(DefaultClientResources.java:233)
	io.lettuce.core.AbstractRedisClient.<init>(AbstractRedisClient.java:98)
	io.lettuce.core.cluster.RedisClusterClient.<init>(RedisClusterClient.java:175)
	io.lettuce.core.cluster.RedisClusterClient.create(RedisClusterClient.java:243)
	org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.lambda$createClient$5(LettuceConnectionFactory.java:958)
	java.util.Optional.orElseGet(Optional.java:267)
	org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createClient(LettuceConnectionFactory.java:958)
	org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.afterPropertiesSet(LettuceConnectionFactory.java:273)

大致的原因是:redis在重新创建lettuce客户端链接资源的时候,之前的客户端链接资源没有被回收。

解决方案

1、有问题代码

@Bean
    public RedisConnectionFactory lettuceConnectionFactory(GenericObjectPoolConfig poolConfig) {
        String nodesConfig = xxx;
        String[] nodeHosts = nodesConfig.split(",");
        RedisClusterConfiguration configuration = new RedisClusterConfiguration(Arrays.asList(nodeHosts));
        /* ========= lettuce pool ========= */
        LettucePoolingClientConfiguration lpc = LettucePoolingClientConfiguration.builder()
                                                                                 .commandTimeout(Duration.ofSeconds(10))
                                                                                 .poolConfig(poolConfig)
                                                                                 .build();
        LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, lpc);
        // 连接池初始化
        connectionFactory.afterPropertiesSet();
        return connectionFactory;
    }

出现问题的代码主要在 connectionFactory.afterPropertiesSet(),初始化的过程中会创建客户端链接资源,在创建过程中,如果重新启动项目,没有回收资源从而导致。
2、修改后的代码

 @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(ClientResources.class)
    public DefaultClientResources lettuceClientResources() {
        return DefaultClientResources.create();
    }

    @Bean
    public RedisConnectionFactory lettuceConnectionFactory(GenericObjectPoolConfig poolConfig,DefaultClientResources lettuceClientResources) {
        String nodesConfig = xxx;
        String[] nodeHosts = nodesConfig.split(",");
        RedisClusterConfiguration configuration = new RedisClusterConfiguration(Arrays.asList(nodeHosts));
        /* ========= lettuce pool ========= */
        LettucePoolingClientConfiguration lpc = LettucePoolingClientConfiguration.builder()
                                                                                 .clientResources(lettuceClientResources)
                                                                                 .commandTimeout(Duration.ofSeconds(10))
                                                                                 .poolConfig(poolConfig)
                                                                                 .build();

        LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, lpc);

        // 连接池初始化
        connectionFactory.afterPropertiesSet();
        return connectionFactory;
    }

如上:增加了lettuceClientResources 客户端资源由Spring容器管理,并且在销毁的时候调用shutdown方法,然后将Spring管理的客户端资源bean传递给LettucePoolingClientConfiguration,并配置,完美解决问题

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐