lettuce+pool+redisTemplate实现redis单机和集群的整合
lettuce+pool+redisTemplate实现redis单机和集群的整合
Springboot 整合redis是非常方便的,大致包含如下四部分
- pom start相关jar的引入
- properties/yaml 基础配置信息
- config bean的init
- bean的注入及使用
如果遇到网上的自动装配的实例直接跳过吧,哪怕再小的公司,密码也会加密处理,不可能自动装配。
1、pom
引入Springboot的redis相关组件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2、properties基础配置
这里主要配置数据源,其他配置项没有,暂时简化了配置,一切使用默认
为了适配真实业务,这里采用的是双数据源配置,亦真亦假,一单节点一集群。
redis.biz.alone.host=39.105.198.245:6379
redis.biz.alone.auth=hcgk&2022
redis.biz.cluster.host=10.22.251.21:6379,10.22.251.28:6379,10.22.251.23:6379
redis.biz.cluster.auth=7ujm*IK<
lettuce.pool.max-total=12
# 最大活跃链接数 默认8(使用负值表示没有限制)
lettuce.pool.max-active=12
# 最大空闲连接数 默认8
lettuce.pool.max-idle=12
# 最小空闲连接数 默认0
lettuce.pool.min-idle=0
# 连接池最大阻塞等待时间(使用负值表示没有限制)
lettuce.pool.max-wait=-1
3、config
支持单击和集群
package com.wht.test.config;
import io.lettuce.core.ReadFrom;
import io.lettuce.core.TimeoutOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
/**
* 支持单机、集群和多实例
*
* @Author 红尘过客
* @DateTime 2023-06-19 22:00:12
*/
@Configuration
public class LettuceRedisConfig {
@Value("${redis.biz.alone.host}")
private String bizAloneHost;
@Value("${redis.biz.alone.auth}")
private String bizAloneAuth;
@Value("${redis.biz.cluster.host}")
private String bizClusterHost;
@Value("${redis.biz.cluster.auth}")
private String bizClusterAuth;
@Bean
@ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
@Scope(value = "prototype")
public GenericObjectPoolConfig redisPool() {
return new GenericObjectPoolConfig();
}
@Primary
@Bean("bizAlone")
public StringRedisTemplate bizAlone(GenericObjectPoolConfig redisPool) {
return getStringRedisTemplate(bizAloneHost, bizAloneAuth, redisPool);
}
// @Primary
// @Bean("bizCluster")
// public StringRedisTemplate bizCluster(GenericObjectPoolConfig redisPool) {
// return getStringRedisTemplate(bizClusterHost, bizClusterAuth,redisPool);
// }
/**
* 封装单例配置
*
* @param host
* @param password
* @return
*/
private RedisStandaloneConfiguration getRedisStandaloneConfiguration(String host, String password) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
String[] redisNode = host.split(":");
if (redisNode.length == 2) {
redisStandaloneConfiguration.setHostName(redisNode[0]);
redisStandaloneConfiguration.setPort(Integer.parseInt(redisNode[1]));
}
if (password != null || password.trim().length() > 0) {
redisStandaloneConfiguration.setPassword(password);
}
return redisStandaloneConfiguration;
}
/**
* 把集群连接串拆分为redisNodes
*
* @param host
* @return
*/
private Set<RedisNode> getClusterNodes(String host) {
String[] nodesArray = host.split(",");
Set<RedisNode> clusterNodes = new HashSet<>();
for (String node : nodesArray) {
String[] redisNode = node.split(":");
clusterNodes.add(new RedisNode(redisNode[0], Integer.parseInt(redisNode[1])));
}
return clusterNodes;
}
/**
* 封装集群配置
*
* @param host
* @param password
* @return
*/
private RedisClusterConfiguration getRedisClusterConfiguration(String host, String password) {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
redisClusterConfiguration.setClusterNodes(getClusterNodes(host));
if (password != null || password.trim().length() > 0) {
redisClusterConfiguration.setPassword(password);
}
return redisClusterConfiguration;
}
/**
* 创建alone bean
* 这里用LettucePoolingClientConfiguration 预留了连接池
*
* @param host
* @param password
* @return
*/
private StringRedisTemplate getStringRedisTemplate(String host, String password, GenericObjectPoolConfig redisPool) {
LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
builder.poolConfig(redisPool);
LettuceConnectionFactory connectionFactory = null;
// 集群要做拓扑刷新,应对准备切换,摸个节点挂掉等问题
if (host.contains(",")) {
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(10))
.enableAllAdaptiveRefreshTriggers()
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(60)))
.topologyRefreshOptions(topologyRefreshOptions)
.build();
LettuceClientConfiguration clientConfiguration = builder.commandTimeout(Duration.ofSeconds(60))
.readFrom(ReadFrom.REPLICA_PREFERRED)
.clientOptions(clusterClientOptions)
.build();
connectionFactory = new LettuceConnectionFactory(getRedisClusterConfiguration(host, password), clientConfiguration);
} else {
connectionFactory = new LettuceConnectionFactory(getRedisStandaloneConfiguration(host, password), builder.build());
}
connectionFactory.afterPropertiesSet();
return getStringRedisTemplate(connectionFactory);
}
private StringRedisTemplate getStringRedisTemplate(LettuceConnectionFactory connectionFactory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(connectionFactory);
return stringRedisTemplate;
}
}
4、使用
这里简单搞个schedule任务
package com.wht.test.schedule;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.Duration;
/**
* desc
*
* @Author 红尘过客
* @DateTime 2023-06-15 10:15:35
*/
@Component
public class RedisTestJob {
@Resource(name = "bizAlone")
private StringRedisTemplate stringRedisTemplate;
@Scheduled(cron = "* * * * * * ")
public void test() {
for (int i = 0; i < 100; i++) {
String key = "test_" + i;
stringRedisTemplate.opsForValue().set(key, "test_value_" + i, Duration.ofHours(1));
String name = (String) stringRedisTemplate.opsForValue().get(key);
System.out.println("value = " + name);
}
}
}
可以正常写入数据到redis了