Springboot整合Redis主從實踐
前言
SpringBoot版本:2.3.2.RELEASE
原配置
原yml配置內(nèi)容:
spring:
# Redis服務器配置
redis:
host: 127.0.0.1
# Redis服務器連接端口
port: 6379
# Redis服務器連接密碼
password: redis@123
#連接超時時間(毫秒)
timeout: 30000ms
jedis:
# Redis服務器連接池
pool:
# 連接池最大連接數(shù)(使用負值表示沒有限制)
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;
}
}
現(xiàn)配置
現(xiàn)yml配置內(nèi)容:
spring:
redis:
# 主節(jié)點
master:
host: 127.0.0.1
port: 6379
password: redis@123
# 副本節(jié)點
replicas:
- host: 127.0.0.1
port: 6380
#連接超時時間(毫秒)
timeout: 30000ms
jedis:
# Redis服務器連接池
pool:
# 連接池最大連接數(shù)(使用負值表示沒有限制)
maxIdle: 400
#連接池中的最小空閑連接
minIdle: 100
#連接池中的最大空閑連接
maxActive: 400
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
maxWait: -1ms
lettuce:
pool:
max-idle: 400
min-idle: 100
max-active: 400
max-wait: -1ms現(xiàn)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 參數(shù)
RedisProperties.Pool poolProps = redisProperties.getLettuce().getPool();
if (poolProps != null) {
builder.poolConfig(poolConfig(poolProps));
}
// 優(yōu)先從副本讀取
builder.readFrom(readFromMaster ? ReadFrom.MASTER : ReadFrom.REPLICA_PREFERRED);
// 斷開連接時拒絕命令[而不是再等待連接超時時間后再報錯]、啟用自動重連
builder.clientOptions(ClientOptions.builder()
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.autoReconnect(true)
.build());
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = builder.build();
// 構(gòu)建連接工廠
LettuceConnectionFactory factory = new LettuceConnectionFactory(config, lettucePoolingClientConfiguration);
// 禁用共享連接 默認是true
// factory.setShareNativeConnection(false);
// 初始化工廠 否則調(diào)用StringRedisTemplate時會空指針 【因為redisConnectionFactory 方法沒有使用@Bean注解將LettuceConnectionFactory交給Spring工廠管理 所以需要手動調(diào)用afterPropertiesSet方法初始化連接工廠】
factory.afterPropertiesSet();
return factory;
}
// 連接池參數(shù)綁定
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 {
/**
* 主節(jié)點
*/
private Node master;
/**
* 從節(jié)點
*/
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(默認):
- 適用于 大多數(shù)應用,多個 Redis 操作共享同一個底層連接,減少資源占用。
- 適用于 Spring Boot + RedisTemplate 場景。
false:
- 適用于 高并發(fā)、多線程環(huán)境,避免多個線程爭搶同一個 Redis 連接。
- 適用于 WebFlux、Reactive、Pipeline 等場景。
一般來說,除非你的 Redis 操作出現(xiàn) 多線程連接爭用問題,否則 不用手動修改 setShareNativeConnection,保持默認值即可!??
而:
- shareNativeConnection = true
- (默認)時,Spring 只會創(chuàng)建 一個共享的 StatefulRedisConnection,那么 連接池的 max-active、max-idle、min-idle 這些配置不會生效。
- shareNativeConnection = false 時,每次請求都會新建連接,這時連接池才會管理多個連接,此時 max-active 等參數(shù)才會起作用。
- 也就是說我們在yml配置文件中配置的連接池信息都將不起作用
jedis:
# Redis服務器連接池
pool:
# 連接池最大連接數(shù)(使用負值表示沒有限制)
maxIdle: 400
#連接池中的最小空閑連接
minIdle: 100
#連接池中的最大空閑連接
maxActive: 400
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
maxWait: -1ms
lettuce:
pool:
max-idle: 400
min-idle: 100
max-active: 400
max-wait: -1ms總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
java實現(xiàn)二維數(shù)組轉(zhuǎn)置的方法示例
這篇文章主要介紹了java實現(xiàn)二維數(shù)組轉(zhuǎn)置的方法,結(jié)合實例形式詳細分析了java二維數(shù)組轉(zhuǎn)置的原理、實現(xiàn)步驟與相關操作技巧,需要的朋友可以參考下2017-10-10
Java 8 動態(tài)類型語言Lambda表達式實現(xiàn)原理解析
Java 8支持動態(tài)語言,看到了很酷的Lambda表達式,對一直以靜態(tài)類型語言自居的Java,讓人看到了Java虛擬機可以支持動態(tài)語言的目標。接下來通過本文給大家介紹Java 8 動態(tài)類型語言Lambda表達式實現(xiàn)原理分析,需要的朋友可以參考下2017-02-02
java如何根據(jù)提供word模板導出word文檔詳解
在日常的開發(fā)工作中,我們時常會遇到導出Word文檔報表的需求,比如公司的財務報表、醫(yī)院的患者統(tǒng)計報表、電商平臺的銷售報表等等,這篇文章主要給大家介紹了關于java如何根據(jù)提供word模板導出word文檔的相關資料,需要的朋友可以參考下2023-09-09
Java實現(xiàn)數(shù)據(jù)庫連接池簡易教程
這篇文章主要為大家介紹了Java實現(xiàn)數(shù)據(jù)庫連接池簡易教程,感興趣的小伙伴們可以參考一下2016-01-01

