SpringBoot集成Redis环境搭建及配置详解_springboot redis 配置-CSDN博客
redis读写分离之lettuce_lettuce readfrom-CSDN博客
reids常用配置_clientconfigurationbuilder.readfrom-CSDN博客
连接池选择及Jedis连接池参数配置建议_分布式缓存服务 DCS
官网 Drivers :: Spring Data Redis
1 总结
1:默认整合了两种连接池,lettuce 和 jedis ,默认使用 lettuce连接池(因为支持的功能多)
2:如果配置了自定义的RedisConnectionFactory ,Spring Boot就不会自动配置 RedisConnectionFactory
2:不配置序列化器,我们是无法看懂的
2 pom
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
配置jedis连接池时用
redis.clients
jedis
3 简单使用(单机版)
配置文件
spring:
application:
name: redis
redis:
port: 6379
database: 0
# host: 192.168.135.10
host: localhost
slaves: 127.0.0.1,127.0.0.1
jedis:
pool:
max-active: 300
max-idle: 300
min-idle: 100
max-wait: 5s
lettuce:
pool:
max-active: 300
max-idle: 300
min-idle: 100
max-wait: 5s
shutdown-timeout: 100ms
直接使用,设置值
@Autowired
RedisTemplate redisTemplate;
@Test
void contextLoads1() {
//設置字符串 新值
redisTemplate.opsForValue().set("ok","测试ok1");
String ok = (String)redisTemplate.opsForValue().get("ok");
System.out.println(ok);
}
因为未配置序列化器
默认加载哪个连接池
结论:不自定义连接池情况下,默认只会加载lettuce连接池
1:当我们配置文件配置了lettuce时,会加在配置单连接池中。
配置文件不会因为你配置 jedis 默认使用jedis连接池。
序列化器
1:redis类型:plain text 是字符串 对应序列化器 StringRedisSerializer
2:jedis默认序列化器就是 StringRedisSerializer
3:注册bean时方法名 不能随便起
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
/**
* 可以注入方式设置连接
*/
/* @Autowired
private RedisConnectionFactory factory;*/
/**
* RedisTemplate配置 改成json序列化模式用keys方法可取到值 否则取不到
*
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(factory);
FastJsonRedisSerializer
方式二
测试成功
4 自定义LettuceConnectionFactory
1:场景:配置文件中用户,密码是加密的,需要解密后 设置到连接池中。
2: 可以发现自定义配置参数会 覆盖配置文件的配置参数
4.1 单机版
import com.alibaba.fastjson.parser.ParserConfig;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
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.serializer.StringRedisSerializer;
@Configuration // 配置类
public class RedisConfig {
/**
* 配置 Redis 连接工厂
* 意义: LettuceConnectionFactory 是连接 Redis 服务器的入口,它使用了 Lettuce 客户端,并且配置了连接池来提高性能和资源管理
* @return
*/
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
// 配置 Redis 服务器的连接信息 可以读取配置文件获取
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName("localhost");
redisStandaloneConfiguration.setPort(6379);
// redisStandaloneConfiguration.setPassword("password"); // 取消注释以设置密码
// 配置连接池
GenericObjectPoolConfig
最终加载的是代码中自定义配置的连接池参数,而不是配置文件中配置。
4.2 写主读从配置(readFrom属性配置)
1:读从库,写到主库
2:实时性高的,必须读主库,写主库
3:默认读从库只会读最后一个从库(加载的最后一条从库ip)
redis版本低 会报 ERR unknown command ‘ROLE’
配置读从库
import io.lettuce.core.ReadFrom;
import org.springframework.boot.autoconfigure.data.redis.LettuceClientConfigurationBuilderCustomizer;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.stereotype.Component;
/**
* 1)MASTER:从主节点读取。
* (2)MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica。
* (3)REPLICA:从slave(replica)节点读取。
* (4)REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master
*/
@Component
public class LuttuceReadFromConfig implements LettuceClientConfigurationBuilderCustomizer {
@Override
public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {
//设置读优先读从机
clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
}
配置读从库 –自定义连接池
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
// 配置 Redis 服务器的连接信息 可以读取配置文件获取
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName("localhost");
redisStandaloneConfiguration.setPort(6379);
// redisStandaloneConfiguration.setPassword("password"); // 取消注释以设置密码
// 配置连接池
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(10); // 连接池中的最大连接数
poolConfig.setMaxIdle(5); // 连接池中的最大空闲连接数
poolConfig.setMinIdle(1); // 连接池中的最小空闲连接数
poolConfig.setMaxWaitMillis(2000); // 连接池获取连接的最大等待时间
// 创建一个带有连接池配置的 Lettuce 客户端配置
LettucePoolingClientConfiguration lettucePoolingClientConfiguration =
LettucePoolingClientConfiguration.builder()
//读时的策略
/**
* 1)MASTER:从主节点读取。
* (2)MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica。
* (3)REPLICA:从slave(replica)节点读取。
* (4)REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master
*/
.readFrom(ReadFrom.SLAVE_PREFERRED)
.poolConfig(poolConfig)
.build();
// 返回带有连接池配置的 Redis 连接工厂
return new LettuceConnectionFactory(redisStandaloneConfiguration, lettucePoolingClientConfiguration);
}
自定义配置轮训读从库方式(线程安全)
读取redis时,默认是将主库连接也加上的,如果从库地址是两个,
import io.lettuce.core.ReadFrom;
import io.lettuce.core.models.role.RedisNodeDescription;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@Slf4j
@Configuration // 配置类
public class LettuceMSConfig {
@Value("${spring.redis.slaves}")
private String slaves;
private final AtomicInteger index = new AtomicInteger(-1);
/**
* 配置 Redis 连接工厂
* @return
*/
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
String mastHostName = "localhost";
int mastPort = 6379;
RedisStaticMasterReplicaConfiguration configuration =
new RedisStaticMasterReplicaConfiguration(mastHostName,mastPort);
//configuration.setPassword();
if(StringUtils.isNotBlank(slaves)){
String[] slaveHosts=slaves.split(",");
for (int i=0;i poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(10); // 连接池中的最大连接数
poolConfig.setMaxIdle(5); // 连接池中的最大空闲连接数
poolConfig.setMinIdle(1); // 连接池中的最小空闲连接数
poolConfig.setMaxWaitMillis(2000); // 连接池获取连接的最大等待时间
// 创建一个带有连接池配置的 Lettuce 客户端配置
LettucePoolingClientConfiguration lettucePoolingClientConfiguration =
LettucePoolingClientConfiguration.builder()
//配置读redis时,获取哪个链接
.readFrom(new ReadFrom() {
@Override
public List select(Nodes nodes) {
List allNodes = nodes.getNodes();
int ind = Math.abs(index.incrementAndGet() % allNodes.size());
RedisNodeDescription selected = allNodes.get(ind);
log.info("Selected random node {} with uri {}", ind, selected.getUri());
List remaining = IntStream.range(0, allNodes.size())
.filter(i -> i != ind)
.mapToObj(allNodes::get).collect(Collectors.toList());
return Stream.concat(
Stream.of(selected),
remaining.stream()
).collect(Collectors.toList());
}
}).commandTimeout(Duration.ofMillis(2000))
.poolConfig(poolConfig)
.build();
// 返回带有连接池配置的 Redis 连接工厂
return new LettuceConnectionFactory(configuration, lettucePoolingClientConfiguration);
}
}
4.3 写主 读(主或从) 配置
默认轮训读,可以强制读主库
进程缓存/去设置变量让其强制获取第一个主库连接即可。
com.github.ben-manes.caffeine
caffeine
Caffeine缓存
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@Slf4j
public class CaffeineCacheConfig {
@Bean
public Cache caffeineCache() {
log.info("缓存配置 Cache 初始化");
return Caffeine.newBuilder()
// 设置最后一次写入或访问后经过固定时间过期
.expireAfterWrite(600, TimeUnit.SECONDS)
// 初始的缓存空间大小
.initialCapacity(1000)
// 缓存的最大条数
.maximumSize(100).build();
}
}
import io.lettuce.core.ReadFrom;
import io.lettuce.core.models.role.RedisNodeDescription;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* 配置自定义连接池,
* 1:读 写分离
* 2: 实时性高的强制读主库
* 3:读从库时 轮训从库
*/
@Slf4j
@Configuration // 配置类
public class LettuceMSConfig {
@Autowired
com.github.benmanes.caffeine.cache.Cache cache;
@Value("${spring.redis.slaves}")
private String slaves;
private final AtomicInteger index = new AtomicInteger(-1);
/**
* 配置 Redis 连接工厂
* @return
*/
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
String mastHostName = "localhost";
int mastPort = 6379;
RedisStaticMasterReplicaConfiguration configuration =
new RedisStaticMasterReplicaConfiguration(mastHostName,mastPort);
//configuration.setPassword();
if(StringUtils.isNotBlank(slaves)){
String[] slaveHosts=slaves.split(",");
for (int i=0;i poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxTotal(10); // 连接池中的最大连接数
poolConfig.setMaxIdle(5); // 连接池中的最大空闲连接数
poolConfig.setMinIdle(1); // 连接池中的最小空闲连接数
poolConfig.setMaxWaitMillis(2000); // 连接池获取连接的最大等待时间
// 创建一个带有连接池配置的 Lettuce 客户端配置
LettucePoolingClientConfiguration lettucePoolingClientConfiguration =
LettucePoolingClientConfiguration.builder()
//配置读redis时,获取哪个链接
.readFrom(new ReadFrom() {
@Override
public List select(Nodes nodes) {
// allNodes 默认会将主redis连接放到第一个
List allNodes = nodes.getNodes();
int ind = Math.abs(index.incrementAndGet() % allNodes.size());
//如果让读主库,获取第一个主库连接
Object readMastNow = cache.getIfPresent("readMastNow");
if(null !=readMastNow){
if ((Boolean)readMastNow) {
ind = 0;
}
}
RedisNodeDescription selected = allNodes.get(ind);
log.info("Selected random node {} with uri {}", ind, selected.getUri());
int finalInd = ind;
List remaining = IntStream.range(0, allNodes.size())
.filter(i -> i != finalInd)
.mapToObj(allNodes::get).collect(Collectors.toList());
return Stream.concat(
Stream.of(selected),
remaining.stream()
).collect(Collectors.toList());
}
}).commandTimeout(Duration.ofMillis(2000))
.poolConfig(poolConfig)
.build();
// 返回带有连接池配置的 Redis 连接工厂
return new LettuceConnectionFactory(configuration, lettucePoolingClientConfiguration);
}
}
调用
@Autowired
RedisTemplate redisTemplate;
@Autowired
com.github.benmanes.caffeine.cache.Cache cache;
@Test
void contextLoads1() {
//設置字符串 新值
cache.put("readMastNow",true);
redisTemplate.opsForValue().set("ok","测试ok1");
String ok = (String)redisTemplate.opsForValue().get("ok");
System.out.println(ok);
}
4.4 哨兵模式配置
4.4 集群版
5 自定义JedisConnectionFactory
1:配置了Jedis连接池后,用的就是Jedis了。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class JedisConnectionConfig {
@Autowired
private Environment env;
@Bean
public JedisConnectionFactory redisConnectionFactory() {
Integer port = Integer.valueOf(env.getProperty("spring.redis.port"));
String host = env.getProperty("spring.redis.host");
String password = env.getProperty("spring.redis.password");
Integer database = Integer.valueOf(env.getProperty("spring.redis.database"));
Integer maxActive = Integer.valueOf(env.getProperty("spring.redis.jedis.pool.max-active"));
Integer maxIdle = Integer.valueOf(env.getProperty("spring.redis.jedis.pool.max-idle"));
Integer minIdle = Integer.valueOf(env.getProperty("spring.redis.jedis.pool.min-idle"));
JedisPoolConfig poolConfig = new JedisPoolConfig();
//最大空闲数
poolConfig.setMaxIdle(maxIdle);
//最大连接数
poolConfig.setMaxTotal(maxActive);
//最大等待毫秒数
poolConfig.setMaxWaitMillis(20000);
poolConfig.setMinIdle(minIdle);
poolConfig.setTestOnBorrow(true);
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("server", 6379);
config.setPort(port);
config.setDatabase(database);
config.setHostName(host);
if (null != password) {
config.setPassword(password);
}
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(config);
jedisConnectionFactory.setPoolConfig(poolConfig);
return jedisConnectionFactory;
}
}