Springboot整合Redis主从实践
作者:xiaomu_a
这篇文章主要介绍了Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
前言
SpringBoot版本:2.3.2.RELEASE
原配置
原yml配置内容:
spring:
# Redis服务器配置
redis:
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码
password: redis@123
#连接超时时间(毫秒)
timeout: 30000ms
jedis:
# Redis服务器连接池
pool:
# 连接池最大连接数(使用负值表示没有限制)
maxIdle: 400
#连接池中的最小空闲连接
minIdle: 100
#连接池中的最大空闲连接
maxActive: 400
# 连接池最大阻塞等待时间(使用负值表示没有限制)
maxWait: -1ms
lettuce:
pool:
max-idle: 400
min-idle: 100
max-active: 400
max-wait: -1ms原RedisConfig配置类:
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
@Bean
@ConditionalOnMissingBean(value = StringRedisTemplate.class, name = "stringRedisTemplate")
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(factory);
return template;
}
}
现配置
现yml配置内容:
spring:
redis:
# 主节点
master:
host: 127.0.0.1
port: 6379
password: redis@123
# 副本节点
replicas:
- host: 127.0.0.1
port: 6380
#连接超时时间(毫秒)
timeout: 30000ms
jedis:
# Redis服务器连接池
pool:
# 连接池最大连接数(使用负值表示没有限制)
maxIdle: 400
#连接池中的最小空闲连接
minIdle: 100
#连接池中的最大空闲连接
maxActive: 400
# 连接池最大阻塞等待时间(使用负值表示没有限制)
maxWait: -1ms
lettuce:
pool:
max-idle: 400
min-idle: 100
max-active: 400
max-wait: -1ms现RedisConfig配置类:
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import com.juxiao.xchat.manager.cache.properties.RedisMasterReplicaProperties;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.ReadFrom;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
@AutoConfigureAfter(RedisAutoConfiguration.class)
@EnableConfigurationProperties({RedisMasterReplicaProperties.class, RedisProperties.class})
public class RedisConfig {
private final RedisMasterReplicaProperties properties;
private final RedisProperties redisProperties;
public RedisConfig(RedisMasterReplicaProperties redisMasterReplicaProperties, RedisProperties redisProperties) {
this.properties = redisMasterReplicaProperties;
this.redisProperties = redisProperties;
}
public LettuceConnectionFactory redisConnectionFactory(boolean readFromMaster) {
RedisStaticMasterReplicaConfiguration config = new RedisStaticMasterReplicaConfiguration(
properties.getMaster().getHost(), properties.getMaster().getPort()
);
String password = properties.getMaster().getPassword();
if (StringUtils.isNotBlank(password)) {
config.setPassword(RedisPassword.of(password));
}
for (RedisMasterReplicaProperties.Node replica : properties.getReplicas()) {
config.addNode(replica.getHost(), replica.getPort());
}
// 连接池配置
LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder =
LettucePoolingClientConfiguration.builder().commandTimeout(redisProperties.getTimeout());
// 使用 application.yml 中的 lettuce.pool 参数
RedisProperties.Pool poolProps = redisProperties.getLettuce().getPool();
if (poolProps != null) {
builder.poolConfig(poolConfig(poolProps));
}
// 优先从副本读取
builder.readFrom(readFromMaster ? ReadFrom.MASTER : ReadFrom.REPLICA_PREFERRED);
// 断开连接时拒绝命令[而不是再等待连接超时时间后再报错]、启用自动重连
builder.clientOptions(ClientOptions.builder()
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.autoReconnect(true)
.build());
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = builder.build();
// 构建连接工厂
LettuceConnectionFactory factory = new LettuceConnectionFactory(config, lettucePoolingClientConfiguration);
// 禁用共享连接 默认是true
// factory.setShareNativeConnection(false);
// 初始化工厂 否则调用StringRedisTemplate时会空指针 【因为redisConnectionFactory 方法没有使用@Bean注解将LettuceConnectionFactory交给Spring工厂管理 所以需要手动调用afterPropertiesSet方法初始化连接工厂】
factory.afterPropertiesSet();
return factory;
}
// 连接池参数绑定
private GenericObjectPoolConfig<?> poolConfig(RedisProperties.Pool poolProps) {
GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(poolProps.getMaxActive());
config.setMaxIdle(poolProps.getMaxIdle());
config.setMinIdle(poolProps.getMinIdle());
config.setMaxWaitMillis(poolProps.getMaxWait().toMillis());
return config;
}
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
redisConnectionFactory.setShareNativeConnection(false);
RedisTemplate<Object, Object> template = new RedisTemplate<>();
//使用fastjson序列化
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);
// value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(serializer);
template.setHashValueSerializer(serializer);
// key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean("masterStringRedisTemplate")
@ConditionalOnMissingBean(name = "masterStringRedisTemplate")
public StringRedisTemplate masterStringRedisTemplate() {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory(true));
return template;
}
@Bean("replicaStringRedisTemplate")
@ConditionalOnMissingBean(name = "replicaStringRedisTemplate")
public StringRedisTemplate replicaStringRedisTemplate() {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory(false));
return template;
}
}
新增RedisMasterReplicaProperties配置类:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
@Data
@ConfigurationProperties(prefix = "spring.redis")
public class RedisMasterReplicaProperties {
/**
* 主节点
*/
private Node master;
/**
* 从节点
*/
private List<Node> replicas = new ArrayList<>();
@Data
public static class Node {
/**
* 主机地址
*/
private String host;
/**
* 端口
*/
private int port;
/**
* 密码(主从模式master、slave密码必须设置一样的)
*/
private String password;
}
}测试
@Resource(name = "masterStringRedisTemplate")
private StringRedisTemplate masterStringRedisTemplate;
@Resource(name = "replicaStringRedisTemplate")
private StringRedisTemplate replicaStringRedisTemplate;
@GetMapping("/test")
public String test() {
masterStringRedisTemplate.opsForValue().set("imu:test", "Hello6");
String value = replicaStringRedisTemplate.opsForValue().get("imu:test");
return value;
}
LettuceConnectionFactory.setShareNativeConnection 方法的作用
代码中这一行被注释,保持了原本的默认配置true
// 禁用共享连接 默认是true // factory.setShareNativeConnection(false);
在 Spring Data Redis 中,LettuceConnectionFactory 是一个用于管理 Redis 连接的工厂类,而 setShareNativeConnection(boolean shareNativeConnection) 方法用于控制是否 共享底层的 Redis 连接。
true(默认):
- 适用于 大多数应用,多个 Redis 操作共享同一个底层连接,减少资源占用。
- 适用于 Spring Boot + RedisTemplate 场景。
false:
- 适用于 高并发、多线程环境,避免多个线程争抢同一个 Redis 连接。
- 适用于 WebFlux、Reactive、Pipeline 等场景。
一般来说,除非你的 Redis 操作出现 多线程连接争用问题,否则 不用手动修改 setShareNativeConnection,保持默认值即可!🚀
而:
- shareNativeConnection = true
- (默认)时,Spring 只会创建 一个共享的 StatefulRedisConnection,那么 连接池的 max-active、max-idle、min-idle 这些配置不会生效。
- shareNativeConnection = false 时,每次请求都会新建连接,这时连接池才会管理多个连接,此时 max-active 等参数才会起作用。
- 也就是说我们在yml配置文件中配置的连接池信息都将不起作用
jedis:
# Redis服务器连接池
pool:
# 连接池最大连接数(使用负值表示没有限制)
maxIdle: 400
#连接池中的最小空闲连接
minIdle: 100
#连接池中的最大空闲连接
maxActive: 400
# 连接池最大阻塞等待时间(使用负值表示没有限制)
maxWait: -1ms
lettuce:
pool:
max-idle: 400
min-idle: 100
max-active: 400
max-wait: -1ms总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
