Springboot整合Redis主從實(shí)踐
前言
SpringBoot版本:2.3.2.RELEASE
原配置
原yml配置內(nèi)容:
spring:
# Redis服務(wù)器配置
redis:
host: 127.0.0.1
# Redis服務(wù)器連接端口
port: 6379
# Redis服務(wù)器連接密碼
password: redis@123
#連接超時(shí)時(shí)間(毫秒)
timeout: 30000ms
jedis:
# Redis服務(wù)器連接池
pool:
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
maxIdle: 400
#連接池中的最小空閑連接
minIdle: 100
#連接池中的最大空閑連接
maxActive: 400
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
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é)點(diǎn)
master:
host: 127.0.0.1
port: 6379
password: redis@123
# 副本節(jié)點(diǎn)
replicas:
- host: 127.0.0.1
port: 6380
#連接超時(shí)時(shí)間(毫秒)
timeout: 30000ms
jedis:
# Redis服務(wù)器連接池
pool:
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
maxIdle: 400
#連接池中的最小空閑連接
minIdle: 100
#連接池中的最大空閑連接
maxActive: 400
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
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);
// 斷開連接時(shí)拒絕命令[而不是再等待連接超時(shí)時(shí)間后再報(bào)錯(cuò)]、啟用自動(dòng)重連
builder.clientOptions(ClientOptions.builder()
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.autoReconnect(true)
.build());
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = builder.build();
// 構(gòu)建連接工廠
LettuceConnectionFactory factory = new LettuceConnectionFactory(config, lettucePoolingClientConfiguration);
// 禁用共享連接 默認(rèn)是true
// factory.setShareNativeConnection(false);
// 初始化工廠 否則調(diào)用StringRedisTemplate時(shí)會(huì)空指針 【因?yàn)閞edisConnectionFactory 方法沒有使用@Bean注解將LettuceConnectionFactory交給Spring工廠管理 所以需要手動(dòng)調(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é)點(diǎn)
*/
private Node master;
/**
* 從節(jié)點(diǎn)
*/
private List<Node> replicas = new ArrayList<>();
@Data
public static class Node {
/**
* 主機(jī)地址
*/
private String host;
/**
* 端口
*/
private int port;
/**
* 密碼(主從模式master、slave密碼必須設(shè)置一樣的)
*/
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 方法的作用
代碼中這一行被注釋,保持了原本的默認(rèn)配置true
// 禁用共享連接 默認(rèn)是true // factory.setShareNativeConnection(false);
在 Spring Data Redis 中,LettuceConnectionFactory 是一個(gè)用于管理 Redis 連接的工廠類,而 setShareNativeConnection(boolean shareNativeConnection) 方法用于控制是否 共享底層的 Redis 連接。
true(默認(rèn)):
- 適用于 大多數(shù)應(yīng)用,多個(gè) Redis 操作共享同一個(gè)底層連接,減少資源占用。
- 適用于 Spring Boot + RedisTemplate 場景。
false:
- 適用于 高并發(fā)、多線程環(huán)境,避免多個(gè)線程爭搶同一個(gè) Redis 連接。
- 適用于 WebFlux、Reactive、Pipeline 等場景。
一般來說,除非你的 Redis 操作出現(xiàn) 多線程連接爭用問題,否則 不用手動(dòng)修改 setShareNativeConnection,保持默認(rèn)值即可!??
而:
- shareNativeConnection = true
- (默認(rèn))時(shí),Spring 只會(huì)創(chuàng)建 一個(gè)共享的 StatefulRedisConnection,那么 連接池的 max-active、max-idle、min-idle 這些配置不會(huì)生效。
- shareNativeConnection = false 時(shí),每次請(qǐng)求都會(huì)新建連接,這時(shí)連接池才會(huì)管理多個(gè)連接,此時(shí) max-active 等參數(shù)才會(huì)起作用。
- 也就是說我們在yml配置文件中配置的連接池信息都將不起作用
jedis:
# Redis服務(wù)器連接池
pool:
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
maxIdle: 400
#連接池中的最小空閑連接
minIdle: 100
#連接池中的最大空閑連接
maxActive: 400
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
maxWait: -1ms
lettuce:
pool:
max-idle: 400
min-idle: 100
max-active: 400
max-wait: -1ms總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringCloud?Nacos服務(wù)分級(jí)存儲(chǔ)模型詳解
Nacos服務(wù)分級(jí)存儲(chǔ)模型是Nacos存儲(chǔ)服務(wù)注冊信息和配置信息的核心模型之一,本文將對(duì)?Nacos?服務(wù)分級(jí)存儲(chǔ)模型進(jìn)行深入解析,感興趣的朋友一起看看吧2024-02-02
mybatis初始化SqlSessionFactory失敗的幾個(gè)原因分析
這篇文章主要介紹了mybatis初始化SqlSessionFactory失敗的幾個(gè)原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
springboot植入pagerHelper的超詳細(xì)教程
這篇文章主要介紹了springboot植入pagerHelper的超詳細(xì)教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
SpringBoot+MyBatis-Plus+Dynamic-Datasource讀寫分離完整指南
在SpringBoot項(xiàng)目中,使用MyBatis-Plus和Dynamic-Datasource實(shí)現(xiàn)讀寫分離是一種常見且高效的架構(gòu)選擇,下面就來詳細(xì)介紹一下SpringBoot讀寫分離,感興趣的可以了解一下2025-11-11
SpringBoot全局配置long轉(zhuǎn)String丟失精度問題解決方案
這篇文章主要介紹了SpringBoot全局配置long轉(zhuǎn)String丟失精度問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

