redis实际项目使用踩坑记录(redis连接池导致connection reset问题)

8,398 阅读2分钟

背景

项目使用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过来的,不然容易导致各种意想不到的问题。