目录
一、必看前言
对于整篇文章要解决的问题要有一个基础的认知
对于lettuce-pool你使用的到底是不是pool
了解springboot2.x.x各个版本存在的问题
二、springboot2.x.x - lettuce连接Redis配置方式
0.公共的配置文件
1.springboot2.3.x-lettuce
2.springboot2.2.x-lettuce
3.springboot2.1.x-lettuce
三、springboot2.x.x - jedis连接Redis配置方式
0.公共的配置文件
1.springboot2.3.x-jedis & springboot2.2.x-jedis
2.springboot2.1.x-jedis
1.Redis分成 单实例连接 和 集群连接 两种方式,连接方式是不一样的
2.对于两种连接方式通用的配置就是 资源池设置 和 客户端名称设置
资源池设置: 为了统一管理客户端的连接数及合理调度资源使用
客户端名称设置:
a.当不同的项目使用同一个redis的时候,一旦redis出现了业务上的tps增长,客户端连接数增长,bigkey阻塞,如果设置了clientName可以快速的定位到是哪个连接的客户端引起的
b.对于云部署的容器可能存在获取不到客户端的真实ip的情况,所以设置clientName是最好区分的方式
3.对于集群来说,客户端除了要维护资源池的配置还要考虑到服务端集群如果做出了更改,
客户端要及时响应刷新本地的集群信息,这就涉及到了客户端要设置redis集群的拓扑刷新问题,springboot2.x的不同版本有不同的变化刷新
4.对于使用lettuce pool配置时,你的配置是否真的生效,测试之后再说结论,这么说了肯定是不生效,需要进行配置才会生效,下边也会提到
5.除了以上不同springboot版本对应的redis的配置不同之外,还有一个问题就是序列化的问题,string类型的序列化就是使用string序列化的方式,
但是对于其余类型来说使用的是jdk的序列化方式,所以无论对于哪种版本我们都需要重写一下序列化方式
我们在设置lettuce-pool的时候,对比jedis会有两个问题,对这两个问题提出解决方案
1.min-idle不生效
2.线程数一直不增长,pool的配置不生效
min-idle不生效 | 添加time-between-eviction-runs: 1000此参数为正值,min-idle生效 |
pool参数不生效,只有一个连接 | 配置shareNativeConnection=false,关闭共享本地连接,pool参数生效 |
redis集群的拓扑刷新问题,只存在于lettuce的连接方式,jedis是将集群信息放入缓存中的,找不到对应的节点信息的时候会去重新获取刷新缓存,
在springboot2.3.x以后的版本添加了拓扑刷新的配置,在2.3.x之前的版本需要自己在config文件中去开启刷新
客户端名称配置,在springboot2.2.x以后的版本已经添加了配置,不需要重写配置,2.2.x之前的版本需要重写配置
版本 | 2.1.x-lettuce | 2.2.x-lettuce | 2.3.x-lettuce | 2.3.x-jedis |
重写拓扑 | 需要 | 需要 | 不需要 | 不需要 |
版本 | springboot2.1.x | springboot2.2.x | springboot2.3.x | |
clientName | 需要 | 不需要 | 不需要 |
连接需要两个文件, application.yml 配置文件和 RedisConfig.java类,下面描述的springboot2.x.x各个版本的RedisConfig.java类的内容都是以当前的RedisConfig.java类内容为基础的.
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* lettuce pool springboot2.x.x 获取pool的工具类
*/
public GenericObjectPoolConfig getGenericObjectLettucePoolConfig(RedisProperties redisProperties){
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
genericObjectPoolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().toMillis());
//默认值为false,在获取连接之前检测是否为有效连接,tps很高的应用可以使用默认值
genericObjectPoolConfig.setTestOnBorrow(false);
genericObjectPoolConfig.setTestOnReturn(false);
//使用lettuce pool的配置的,需要打开此配置,用于检测控线连接并回收
genericObjectPoolConfig.setTestWhileIdle(true);
return genericObjectPoolConfig;
}
/**
* 自定义序列化方式
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 初始化string的序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
redisTemplate.setValueSerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
application.yml
#springboot2.3.x已经添加了对于lettuce拓扑刷新的配置,也添加了对于客户端的配置
#--------------------------------springboot2.3.x lettuce配置-----------------------------------------------
spring:
redis:
#单实例连接打开此配置,关闭cluster配置即可
# host: 127.0.0.1
# port: 8510
cluster:
nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379
max-redirects: 3
password: 123456
timeout: 50000
ssl: false
database: 0
lettuce:
pool:
max-active: 10
max-idle: 8
min-idle: 1
max-wait: 5000
time-between-eviction-runs: 1000 # 配置空闲连接回收间隔时间,min-idle才会生效,否则不生效
cluster:
refresh: #拓扑刷新开关
adaptive: true #自适应刷新集群 默认false关闭
period: 30000 #定时刷新集群
client-name: AppName #配置客户端名称
RedisConfig.java
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* 此配置添加到上边的RedisConfig.java类中
* springboot2.3.x 使用 lettuce 连接redis单机或集群,需要添加以下的选项
*/
@Bean
public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) {
//添加额外属性
LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.commandTimeout(redisProperties.getTimeout())
.poolConfig(getGenericObjectJedisPoolConfig(redisProperties))
.clientName(redisProperties.getClientName())
.build();
//单机连接配置,单实例redis连接放开下边注释,同时注释掉RedisClusterConfiguration的配置
// RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort());
// configuration.setPassword(redisProperties.getPassword());
//集群连接配置
RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
configuration.setPassword(RedisPassword.of(redisProperties.getPassword()));
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, clientConfig);
//如果要使pool参数生效,一定要关闭shareNativeConnection
lettuceConnectionFactory.setShareNativeConnection(false);
return lettuceConnectionFactory;
}
}
application.yml
#springboot2.2.x没有添加lettuce的拓扑刷新功能,需要通过配置文件手动添加,clientName的配置功能存在
#--------------------------------springboot2.2.x lettuce配置-----------------------------------------------
spring:
redis:
#单实例连接打开此配置,关闭cluster配置即可
# host: 127.0.0.1
# port: 8510
cluster:
nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379
max-redirects: 3
password: 123456
timeout: 50000
ssl: false
database: 0
lettuce:
pool:
max-active: 10
max-idle: 8
min-idle: 1
max-wait: 5000
time-between-eviction-runs: 1000 # 配置空闲连接回收间隔时间,min-idle才会生效,否则不生效
client-name: AppName #配置客户端名称
RedisConfig.java类
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* 此配置添加到上边的RedisConfig.java类中
* springboot2.2.x使用 lettuce 连接redis单实例或集群,需要添加以下的选项
*
* 在构建LettuceConnectionFactory时,如果不使用内置的destroyMethod,可能会导致Redis连接早于其它Bean被销毁
*/
@Bean(destroyMethod = "destroy")
public LettuceConnectionFactory newLettuceConnectionFactory(RedisProperties redisProperties) {
// 配置用于开启自适应刷新和定时刷新。如自适应刷新不开启,Redis集群变更时将会导致连接异常
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofMinutes(10))
.enableAllAdaptiveRefreshTriggers()
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(10))
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions)
.build();
LettucePoolingClientConfiguration poolConfiguration = LettucePoolingClientConfiguration.builder()
.clientOptions(clusterClientOptions)
.clientName(redisProperties.getClientName())
.commandTimeout(redisProperties.getTimeout())
.poolConfig(getGenericObjectLettucePoolConfig(redisProperties))
.build();
//单实例连接时打开此配置,并注释下边的RedisClusterConfiguration配置
// RedisConfiguration configuration = new
// RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort());
// ((RedisStandaloneConfiguration) configuration).setPassword(redisProperties.getPassword());
RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
configuration.setPassword(RedisPassword.of(redisProperties.getPassword()));
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, poolConfiguration);
//关闭shareNativeConnection,才能让lettuce.pool的配置生效,如果共享本地连接已经够使用了,完全可以不用配置
lettuceConnectionFactory.setShareNativeConnection(false);
return lettuceConnectionFactory;
}
}
application.yml
#springboot2.1.x没有添加lettuce的拓扑刷新功能,需要通过配置文件手动添加,也没有clientName的配置功能
#--------------------------------springboot2.2.x lettuce配置-----------------------------------------------
spring:
redis:
#单实例连接打开此配置,关闭cluster配置即可
# host: 127.0.0.1
# port: 8510
cluster:
nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379
max-redirects: 3
password: 123456
timeout: 50000
ssl: false
database: 0
lettuce:
pool:
max-active: 10
max-idle: 8
min-idle: 1
max-wait: 5000
time-between-eviction-runs: 1000 # 配置空闲连接回收间隔时间,min-idle才会生效,否则不生效
RedisConfig.java类
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* 此配置添加到上边的RedisConfig.java类中
* springboot2.1.x使用 lettuce 连接redis单实例或集群,需要添加以下的选项
*
* 在构建LettuceConnectionFactory时,如果不使用内置的destroyMethod,可能会导致Redis连接早于其它Bean被销毁
*/
@Bean(destroyMethod = "destroy")
public LettuceConnectionFactory newLettuceConnectionFactory(RedisProperties redisProperties) {
// 配置用于开启自适应刷新和定时刷新。如自适应刷新不开启,Redis集群变更时将会导致连接异常
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofMinutes(10))
.enableAllAdaptiveRefreshTriggers()
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(10))
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions)
.build();
LettucePoolingClientConfiguration poolConfiguration = LettucePoolingClientConfiguration.builder()
.clientOptions(clusterClientOptions)
//客户端名称需要在这里写死
.clientName("AppName")
.commandTimeout(redisProperties.getTimeout())
.poolConfig(getGenericObjectLettucePoolConfig(redisProperties))
.build();
//单实例连接时打开此配置,并注释下边的RedisClusterConfiguration配置
// RedisConfiguration configuration = new
// RedisStandaloneConfiguration(redisProperties.getHost(),redisProperties.getPort());
// ((RedisStandaloneConfiguration) configuration).setPassword(redisProperties.getPassword());
RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
configuration.setPassword(RedisPassword.of(redisProperties.getPassword()));
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, poolConfiguration);
//关闭shareNativeConnection,才能让lettuce.pool的配置生效,如果共享本地连接够实用完全可以不配置
lettuceConnectionFactory.setShareNativeConnection(false);
return lettuceConnectionFactory;
}
}
连接需要两个文件, application.yml 配置文件和 RedisConfig.java类,对于jedis而言,不存在redis集群的拓扑刷新问题,只是一些额外的配置随着springboot的版本不同需要添加配置文件(RedisConfig.java类)进行重写
RedisConfig.java类
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* jedis pool springboot2.x.x 获取pool的工具类
* @param redisProperties
* @return
*/
public JedisPoolConfig getGenericObjectJedisPoolConfig(RedisProperties redisProperties){
//JedisPoolConfig 继承 GenericObjectPoolConfig类,并将testWhileIdle设置为true
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMaxIdle());
jedisPoolConfig.setMinIdle(redisProperties.getJedis().getPool().getMinIdle());
jedisPoolConfig.setMaxTotal(redisProperties.getJedis().getPool().getMaxActive());
jedisPoolConfig.setMaxWaitMillis(redisProperties.getJedis().getPool().getMaxWait().toMillis());
//此处可以设置testOnBorrow,默认值为false,网络良好的情况下建议使用默认值
return jedisPoolConfig;
}
/**
* 自定义序列化方式
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 初始化string的序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
redisTemplate.setValueSerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
application.yml
#----------------------------------------springboot2.x.x jedis配置-------------------------------------
spring:
redis:
# host: 127.0.0.1
# port: 6379
clientName: AppName #springboot2.1.x版本没有此配置需要再RedisConfig.java类中重新写入
cluster:
nodes: 127.0.0.1:6379,127.0.0.2:6379,127.0.0.3:6379,127.0.0.4:6379,127.0.0.5:6379,127.0.0.6:6379
max-redirects: 3
password: 123456
timeout: 50000
ssl: false
database: 0
jedis:
pool:
max-active: 10
max-idle: 8
min-idle: 1
max-wait: 5000
RedisConfig.java类
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* springboot2.3.x springboot2.2.x 使用 jedis 连接redis单实例或集群,需要添加以下的选项
* 目的:为当前应用添加连接redis的标识,方便多应用连接同一个redis的问题查找
*/
@Bean
public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) {
//添加额外属性
JedisClientConfiguration clientConfig = JedisClientConfiguration.builder()
.clientName(redisProperties.getClientName())
.usePooling().poolConfig(getGenericObjectJedisPoolConfig(redisProperties)).and().readTimeout(redisProperties.getTimeout())
.build();
//单实例连接配置
// RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost());
// configuration.setPort(redisProperties.getPort());
// configuration.setPassword(redisProperties.getPassword());
//集群连接配置
RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
configuration.setPassword(RedisPassword.of(redisProperties.getPassword()));
return new JedisConnectionFactory(configuration, clientConfig);
}
}
RedisConfig.java类
/**
* @author zcx
*/
@Configuration
public class RedisConfig {
/**
* springboot2.1.x 使用 jedis 连接redis单实例或集群,需要添加以下的选项
* 目的:为当前应用添加连接redis的标识,方便多应用连接同一个redis的问题查找
*/
@Bean
public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) {
//添加额外属性
JedisClientConfiguration clientConfig = JedisClientConfiguration.builder()
//客户端名称需要再这里写死
.clientName("AppName")
.usePooling().poolConfig(getGenericObjectJedisPoolConfig(redisProperties)).and().readTimeout(redisProperties.getTimeout())
.build();
//单实例连接配置
// RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost());
// configuration.setPort(redisProperties.getPort());
// configuration.setPassword(redisProperties.getPassword());
//集群连接配置
RedisClusterConfiguration configuration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
configuration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
configuration.setPassword(RedisPassword.of(redisProperties.getPassword()));
return new JedisConnectionFactory(configuration, clientConfig);
}
}