1. 现象
Spring Cloud项目,使用的JRedis连接池,日志里面经常会发现报错信息如下:
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset
at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:202)
at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)
at redis.clients.jedis.Protocol.process(Protocol.java:153)
at redis.clients.jedis.Protocol.read(Protocol.java:218)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:341)
at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:240)
at redis.clients.jedis.BinaryJedis.quit(BinaryJedis.java:256)
at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:298)
... 38 common frames omitted
Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:196)
Connection reset表示连接被重置,具体含义是服务器端因为某些原因关闭了Connection,这肯定是跟连接的数量、超时时间等相关。
2. 思路
网上查询相关资料,了解到JRedis在多线程情况下共享一个实例是不安全的,所以是一个很大的隐患。而且JRedis也不能较好的支持较多的连接数。
所以问题应该是出在连接池上,JRedis在多线程高并发的情况下,是一个定时炸弹,竟然如此,换掉就是了。
继续查询资料,找到了基于Netty的Lettuce,看到Netty就放心了,有点资历的程序猿都知道是高性能高并发的绝佳带盐。
3. 实现
首先引入相关依赖:
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool 缓存连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
然后配置连接参数:
spring:
# redis配置信息
redis:
# redis数据库索引(默认为0)
database: 0
# redis服务器地址
host: 192.168.20.214
# redis服务器连接端口
port: 6379
password:
lettuce:
pool:
max-total: 100
max-active: 100
max-wait: 1000
max-idle: 20
min-idle: 0
最后使用配置类:
/**
* redis配置类
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 连接工厂
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
// 使用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
// 设置hash序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
}
4. 实验
修改后重新启动项目,发现比较稳定,后续有问题再反馈吧。