在 Cloud Foundry 上使用 spring-data-redis 时检测到资源泄漏
Resource leak detected when using spring-data-redis on cloud foundry
我们开发了一个spring-boot服务,它提供了一个休息api(spring-webflux)并通过RabbitMQ(spring-rabbit)发送数据。该服务部署在 cloud foundry 上,我们在 2.1.4 版本中使用 spring-boot。我们添加了 spring-boot-starter-data-redis 以使用 redis 缓存一些数据,我们得到了以下错误:
[io.netty.util.ResourceLeakDetector] [] 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.RedisClient.<init>(RedisClient.java:87)
io.lettuce.core.RedisClient.create(RedisClient.java:124)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.lambda$createClient(LettuceConnectionFactory.java:971)
java.base/java.util.Optional.orElseGet(Unknown Source)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createClient(LettuceConnectionFactory.java:971)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.afterPropertiesSet(LettuceConnectionFactory.java:273)
org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator.create(RedisConnectionFactoryCreator.java:88)
org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator.create(RedisConnectionFactoryCreator.java:31)
org.springframework.cloud.Cloud.getServiceConnector(Cloud.java:288)
org.springframework.cloud.Cloud.getSingletonServiceConnector(Cloud.java:202)
org.springframework.cloud.config.java.CloudServiceConnectionFactory.redisConnectionFactory(CloudServiceConnectionFactory.java:260)
org.springframework.cloud.config.java.CloudServiceConnectionFactory.redisConnectionFactory(CloudServiceConnectionFactory.java:242)
...
只有当我们 运行 Cloud Foundry 上的服务时才会发生此错误,如果我们 运行 在本地,我们不会收到任何错误。
我们不对连接工厂或我们这边的 stringRedisTemplate 进行任何配置,只使用由 spring-autoconfiguration 配置的 stringRedisTemplate。
我们对 cloud foundry 上的 redis 使用以下配置:
@Configuration
@Profile( "cloud" )
public class CloudSpecificConfig extends AbstractCloudConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return connectionFactory().redisConnectionFactory();
}
}
这就是我们使用模板的方式
@Component
@RequiredArgsConstructor
public final class RequestUtil {
private final StringRedisTemplate myRedisTemplate;
public String cacheId(String id, String value) {
myRedisTemplate.opsForValue().set( id, value );
}
}
这些是我们的 spring 依赖项:
<properties>
<spring-boot-version>2.1.4.RELEASE</spring-boot-version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot-version}</version>
</dependency>
我们这边很困惑,因为我们这边没有做任何具体的配置。它看起来像云上的 spring 配置有问题。我们做错了什么吗?我们需要配置不同的东西吗?这是一个错误吗?
这是我必须做的
我看看能不能找到更优雅的方式
@Bean(destroyMethod = "shutdown")
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@SuppressWarnings("unused")
@Bean
public RedisConnectionFactory redisConnectionFactory(DefaultClientResources dependency) {
return connectionFactory().redisConnectionFactory("redis-pcf-service");
}
最后这个问题在我们这边消失了,因为我们把redis客户端从lettuce换成了jedis。
我们在使用 lettuce 时遇到了问题,我们会失去与云基础设施上的 redis 服务的连接。但是由于在我们更换客户端的同时更新了redis服务,所以我们真的不知道它是否与生菜有关。
也许我们的云架构上基于cloudfoundry的redis服务的自动配置也有问题
我们开发了一个spring-boot服务,它提供了一个休息api(spring-webflux)并通过RabbitMQ(spring-rabbit)发送数据。该服务部署在 cloud foundry 上,我们在 2.1.4 版本中使用 spring-boot。我们添加了 spring-boot-starter-data-redis 以使用 redis 缓存一些数据,我们得到了以下错误:
[io.netty.util.ResourceLeakDetector] [] 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.RedisClient.<init>(RedisClient.java:87)
io.lettuce.core.RedisClient.create(RedisClient.java:124)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.lambda$createClient(LettuceConnectionFactory.java:971)
java.base/java.util.Optional.orElseGet(Unknown Source)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createClient(LettuceConnectionFactory.java:971)
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.afterPropertiesSet(LettuceConnectionFactory.java:273)
org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator.create(RedisConnectionFactoryCreator.java:88)
org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator.create(RedisConnectionFactoryCreator.java:31)
org.springframework.cloud.Cloud.getServiceConnector(Cloud.java:288)
org.springframework.cloud.Cloud.getSingletonServiceConnector(Cloud.java:202)
org.springframework.cloud.config.java.CloudServiceConnectionFactory.redisConnectionFactory(CloudServiceConnectionFactory.java:260)
org.springframework.cloud.config.java.CloudServiceConnectionFactory.redisConnectionFactory(CloudServiceConnectionFactory.java:242)
...
只有当我们 运行 Cloud Foundry 上的服务时才会发生此错误,如果我们 运行 在本地,我们不会收到任何错误。
我们不对连接工厂或我们这边的 stringRedisTemplate 进行任何配置,只使用由 spring-autoconfiguration 配置的 stringRedisTemplate。 我们对 cloud foundry 上的 redis 使用以下配置:
@Configuration
@Profile( "cloud" )
public class CloudSpecificConfig extends AbstractCloudConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return connectionFactory().redisConnectionFactory();
}
}
这就是我们使用模板的方式
@Component
@RequiredArgsConstructor
public final class RequestUtil {
private final StringRedisTemplate myRedisTemplate;
public String cacheId(String id, String value) {
myRedisTemplate.opsForValue().set( id, value );
}
}
这些是我们的 spring 依赖项:
<properties>
<spring-boot-version>2.1.4.RELEASE</spring-boot-version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot-version}</version>
</dependency>
我们这边很困惑,因为我们这边没有做任何具体的配置。它看起来像云上的 spring 配置有问题。我们做错了什么吗?我们需要配置不同的东西吗?这是一个错误吗?
这是我必须做的
我看看能不能找到更优雅的方式
@Bean(destroyMethod = "shutdown")
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@SuppressWarnings("unused")
@Bean
public RedisConnectionFactory redisConnectionFactory(DefaultClientResources dependency) {
return connectionFactory().redisConnectionFactory("redis-pcf-service");
}
最后这个问题在我们这边消失了,因为我们把redis客户端从lettuce换成了jedis。
我们在使用 lettuce 时遇到了问题,我们会失去与云基础设施上的 redis 服务的连接。但是由于在我们更换客户端的同时更新了redis服务,所以我们真的不知道它是否与生菜有关。
也许我们的云架构上基于cloudfoundry的redis服务的自动配置也有问题