背景
项目使用springboot 并且配置了redis连接池,用于存储热点数据。
主要代码
pom文件主要内容
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
reids连接池相关配置(当时用的demo,没有抽取到配置文件)
public class CommonRedisConfiguration2 {
@Bean(name = "sysJedisPoolConfig")
public JedisPoolConfig a() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(1000);
jedisPoolConfig.setMaxIdle(10);
jedisPoolConfig.setNumTestsPerEvictionRun(1024);
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);
jedisPoolConfig.setMinEvictableIdleTimeMillis(1800000);
jedisPoolConfig.setSoftMinEvictableIdleTimeMillis(10000);
jedisPoolConfig.setMaxWaitMillis(2000);
jedisPoolConfig.setTestOnBorrow(true);
jedisPoolConfig.setTestWhileIdle(true);
jedisPoolConfig.setBlockWhenExhausted(false);
return jedisPoolConfig;
}
@Bean(name = "sysRedisConnectionFactory")
public RedisConnectionFactory b(@Qualifier("sysJedisPoolConfig") JedisPoolConfig jedisPoolConfig) {
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
redisConfig.setHostName("localhost");
redisConfig.setPort(6379);
redisConfig.setPassword(RedisPassword.of(""));
redisConfig.setDatabase(1);
JedisClientConfiguration.DefaultJedisClientConfigurationBuilder configurationBuilder = (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration
.builder();
configurationBuilder.poolConfig(jedisPoolConfig);
configurationBuilder.readTimeout(Duration.ofMillis(1000));
// configurationBuilder.connectTimeout(Duration.ofMillis(10000));
JedisClientConfiguration clientConfiguration = configurationBuilder.build();
RedisConnectionFactory redisConnectionFacotry = new JedisConnectionFactory(redisConfig, clientConfiguration);
return redisConnectionFacotry;
}
@Bean(name = "sysRedisTemplate")
public RedisTemplate<String, Object> redisTemplate(@Qualifier("sysRedisConnectionFactory") RedisConnectionFactory redisConnectionFacotry) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFacotry);
// 使用fastjson序列化
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
// value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(fastJsonRedisSerializer);
template.setHashValueSerializer(fastJsonRedisSerializer);
// key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// template.afterPropertiesSet();
return template;
}
}
测试类代码
@RestController
public class TestController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@RequestMapping("/test")
public String test() {
try {
String a = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(a,
"this is a good day}");
} catch (Exception e) {
System.out.println(e.getMessage());
}
return "a";
}
}
问题描述
当使用jmiter进行压力测试,线程一大的时候,就发现特别容易出现connection reset的报错。当大到一定的程度,基本上就都是这个错误了。
跟踪
之前这块配置是使用XML配置的,后来由于公司规范修改为@Bean的方式进行加载,上面代码是其他小朋友从网上找的,但是压测就出问题了,总是报connection reset问题,而xml版本在1500并发的时候依旧是正常的。奇怪的是xml配置的poolconfig的属性都是一样的。但是通过@Bean方式就是不对。
原因以及处理
通过百度相关的方案,发现代码中少了一行,即
JedisClientConfiguration.DefaultJedisClientConfigurationBuilder configurationBuilder = (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration
.builder();
configurationBuilder.poolConfig(jedisPoolConfig);
中,还需要设置使用pool。即改成
JedisClientConfiguration.DefaultJedisClientConfigurationBuilder configurationBuilder = (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration
.builder();
configurationBuilder.usePooling();
configurationBuilder.poolConfig(jedisPoolConfig);
总结
写代码还是要仔细,尤其是从别的地方copy过来的,不然容易导致各种意想不到的问题。