一,什么情况下需要使用多个redis数据源?

为了缓存数据,通常我们会在线上使用多个redis的cluster,

每个cluster中缓存不同的数据,以方便管理.

例如:我们缓存了杂志文章/商品信息/分类页面

同时我们又使用一个redis cluster作为分布式session

这里就会有多个redis数据源在项目中

说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

对应的源码可以访问这里获取: https://github.com/liuhongdi/

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,演示项目说明:

1,项目地址:

https://github.com/liuhongdi/multiredissource

2, 项目原理

存储session使用redis集群,

另外使用两个redis实例做缓存

关于redis集群的搭建请参见:

https://www.cnblogs.com/architectforest/p/13196749.html

3, 项目结构:

如图:

三,项目配置文件说明:

application.properties

#default redis,for session
spring.redis.cluster.nodes=172.17.0.2:6379,172.17.0.3:6379,172.17.0.4:6379,172.17.0.5:6379,172.17.0.6:6379,172.17.0.7:6379
spring.redis.cluster.max-redirects=3
spring.redis.password=lhddemo
spring.redis.database=0
spring.session.store-type=redis
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=1
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0 #redis1
spring.redis1.host=127.0.0.1
spring.redis1.port=6379
spring.redis1.password=lhddemo
spring.redis1.database=0
spring.redis1.lettuce.pool.max-active=8
spring.redis1.lettuce.pool.max-wait=1
spring.redis1.lettuce.pool.max-idle=8
spring.redis1.lettuce.pool.min-idle=0 #redis2
spring.redis2.host=127.0.0.1
spring.redis2.port=6380
spring.redis2.password=lhddemo
spring.redis2.database=0
spring.redis2.lettuce.pool.max-active=8
spring.redis2.lettuce.pool.max-wait=1
spring.redis2.lettuce.pool.max-idle=8
spring.redis2.lettuce.pool.min-idle=0

说明:共3个redis,

存储session的集群有6个节点(3主3从):

172.17.0.2:6379,

172.17.0.3:6379,

172.17.0.4:6379,

172.17.0.5:6379,

172.17.0.6:6379,

172.17.0.7:6379

redis1是非集群结点:

127.0.0.1:6379

redis2是非集群结点:

127.0.0.1:6380

四,java代码说明

1,RedisConfig.java

@Configuration
public class RedisConfig {
@Bean
@Primary
public LettuceConnectionFactory redissessionLettuceConnectionFactory(RedisClusterConfiguration redisSessionRedisConfig,
GenericObjectPoolConfig redisSessionPoolConfig) {
LettuceClientConfiguration clientConfig =
LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
.poolConfig(redisSessionPoolConfig).build();
return new LettuceConnectionFactory(redisSessionRedisConfig, clientConfig);
} @Bean
public RedisTemplate<String, String> redisSessionTemplate(
@Qualifier("redissessionLettuceConnectionFactory") LettuceConnectionFactory redissessionLettuceConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
//使用StringRedisSerializer来序列化和反序列化redis的ke
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
//开启事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(redissessionLettuceConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
} @Bean
@ConditionalOnBean(name = "redis1RedisConfig")
public LettuceConnectionFactory redis1LettuceConnectionFactory(RedisStandaloneConfiguration redis1RedisConfig,
GenericObjectPoolConfig redis1PoolConfig) {
LettuceClientConfiguration clientConfig =
LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
.poolConfig(redis1PoolConfig).build();
return new LettuceConnectionFactory(redis1RedisConfig, clientConfig);
} @Bean
public RedisTemplate<String, String> redis1Template(
@Qualifier("redis1LettuceConnectionFactory") LettuceConnectionFactory redis1LettuceConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
//使用StringRedisSerializer来序列化和反序列化redis的ke
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
//开启事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(redis1LettuceConnectionFactory);
redisTemplate.afterPropertiesSet(); return redisTemplate;
} @Bean
@ConditionalOnBean(name = "redis2RedisConfig")
public LettuceConnectionFactory redis2LettuceConnectionFactory(RedisStandaloneConfiguration redis2RedisConfig,
GenericObjectPoolConfig redis2PoolConfig) {
LettuceClientConfiguration clientConfig =
LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
.poolConfig(redis2PoolConfig).build();
return new LettuceConnectionFactory(redis2RedisConfig, clientConfig);
} @Bean
@ConditionalOnBean(name = "redis2LettuceConnectionFactory")
public RedisTemplate<String, String> redis2Template(
@Qualifier("redis2LettuceConnectionFactory") LettuceConnectionFactory redis2LettuceConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
//使用StringRedisSerializer来序列化和反序列化redis的ke
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//开启事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(redis2LettuceConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
} @Configuration
public static class RedisSessionConfig {
@Value("${spring.redis.cluster.nodes}")
private String nodes;
@Value("${spring.redis.cluster.max-redirects}")
private Integer maxRedirects;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.database}")
private Integer database; @Value("${spring.redis.lettuce.pool.max-active}")
private Integer maxActive;
@Value("${spring.redis.lettuce.pool.max-idle}")
private Integer maxIdle;
@Value("${spring.redis.lettuce.pool.max-wait}")
private Long maxWait;
@Value("${spring.redis.lettuce.pool.min-idle}")
private Integer minIdle; @Bean
public GenericObjectPoolConfig redisSessionPoolConfig() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxActive);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setMaxWaitMillis(maxWait);
return config;
} @Bean
public RedisClusterConfiguration redisSessionRedisConfig() {
RedisClusterConfiguration config = new RedisClusterConfiguration();
String[] sub = nodes.split(",");
List<RedisNode> nodeList = new ArrayList<>(sub.length);
String[] tmp;
for (String s : sub) {
tmp = s.split(":");
nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
}
config.setClusterNodes(nodeList);
config.setMaxRedirects(maxRedirects);
config.setPassword(RedisPassword.of(password));
return config;
}
} @Configuration
public static class Redis1Config {
@Value("${spring.redis1.host}")
private String host;
@Value("${spring.redis1.port}")
private Integer port;
@Value("${spring.redis1.password}")
private String password;
@Value("${spring.redis1.database}")
private Integer database;
@Value("${spring.redis1.lettuce.pool.max-active}")
private Integer maxActive;
@Value("${spring.redis1.lettuce.pool.max-idle}")
private Integer maxIdle;
@Value("${spring.redis1.lettuce.pool.max-wait}")
private Long maxWait;
@Value("${spring.redis1.lettuce.pool.min-idle}")
private Integer minIdle; @Bean
public GenericObjectPoolConfig redis1PoolConfig() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxActive);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setMaxWaitMillis(maxWait);
return config;
} @Bean
public RedisStandaloneConfiguration redis1RedisConfig() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPassword(RedisPassword.of(password));
config.setPort(port);
config.setDatabase(database);
return config;
}
} @Configuration
@ConditionalOnProperty(name = "host", prefix = "spring.redis2")
public static class Redis2Config {
@Value("${spring.redis2.host}")
private String host;
@Value("${spring.redis2.port}")
private Integer port;
@Value("${spring.redis2.password}")
private String password;
@Value("${spring.redis2.database}")
private Integer database; @Value("${spring.redis2.lettuce.pool.max-active}")
private Integer maxActive;
@Value("${spring.redis2.lettuce.pool.max-idle}")
private Integer maxIdle;
@Value("${spring.redis2.lettuce.pool.max-wait}")
private Long maxWait;
@Value("${spring.redis2.lettuce.pool.min-idle}")
private Integer minIdle; @Bean
public GenericObjectPoolConfig redis2PoolConfig() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxActive);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setMaxWaitMillis(maxWait);
return config;
} @Bean
public RedisStandaloneConfiguration redis2RedisConfig() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPassword(RedisPassword.of(password));
config.setPort(port);
config.setDatabase(database);
return config;
}
}
}

说明:

分别构造了三个redisTemplate:

redisSessionTemplate:访问redis session cluster

redis1Template:访问redis1

redis2Template:访问redis2

因为要供session默认使用,
所以给第一个LettuceConnectionFactory加上@Primary注解

cluster的配置要使用RedisClusterConfiguration类,

注意与:RedisStandaloneConfiguration区分

2,CacheController.java

@RestController
@RequestMapping("/cache")
public class CacheController { @Resource
RedisTemplate<String, String> redis1Template;
@Resource
RedisTemplate<String, String> redis2Template; /*
* get redis1 cache
*/
@RequestMapping("/redis1get")
public String redis1Get(HttpServletRequest request){
String goodsname = redis1Template.opsForValue().get("goodsname1");
return goodsname;
} /*
* write redis1 cache
*/
@RequestMapping("/redis1set/{name}")
public String redis1Set(@PathVariable String name) {
//request.getSession().setAttribute("goods", name);
redis1Template.opsForValue().set("goodsname1",name);
return "ok";
} /*
* get redis2 cache
* */
@RequestMapping("/redis2get")
public String redis2Get(HttpServletRequest request){
String goodsname2 = redis2Template.opsForValue().get("goodsname2");
return goodsname2;
} /*
* write redis2 cache
* */
@RequestMapping("/redis2set/{name}")
public String redis2Set(@PathVariable String name) {
//request.getSession().setAttribute("goods", name);
redis2Template.opsForValue().set("goodsname2",name);
return "ok";
}
}

说明:对redis1和redis2分别读取和写入

3,SessionController.java

@RestController
@RequestMapping("/session")
public class SessionController {
/*
* read session
* */
@RequestMapping("/get")
public Object getSession(HttpServletRequest request){ Map<String, Object> map = new HashMap<>();
map.put("sessionId", request.getSession().getId());
map.put("user", request.getSession().getAttribute("user"));
map.put("maxInactiveInterval", request.getSession().getMaxInactiveInterval());
//map.put("ttl", request.getSession().);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(new Date(request.getSession().getCreationTime()));
map.put("creationTime", time);
return map;
} /*
* write session
* */
@RequestMapping("/set/{name}")
public String setSession(@PathVariable String name, HttpServletRequest request) {
request.getSession().setAttribute("user", name);
return "ok";
}
}

说明:对session的读取和写入

五,多redis数据源效果测试

1,查看三个redis的数据:

redissession

[root@redis4 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -a lhddemo -c --cluster call 172.17.0.2:6379 keys \*
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Calling keys *
172.17.0.2:6379:
172.17.0.4:6379:
172.17.0.3:6379:
172.17.0.6:6379:
172.17.0.7:6379:
172.17.0.5:6379:

redis1:

127.0.0.1:6379> keys *
(empty list or set)

redis2:

127.0.0.1:6380> keys *
(empty list or set)

2,测试session:

访问:http://127.0.0.1:8080/session/set/thislaoliu

设置一个session值为thislaoliu:

访问:http://127.0.0.1:8080/session/get

查询我们设置的session值是否生效?

从redis的控制台检查写入情况:

[root@redis4 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -a lhddemo -c --cluster call 172.17.0.2:6379 keys \*
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Calling keys *
172.17.0.2:6379: spring:session:sessions:expires:97a889f8-7122-4248-a5fc-4e559cb429e5
172.17.0.4:6379: spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
172.17.0.3:6379: spring:session:expirations:1593321720000
172.17.0.6:6379: spring:session:sessions:expires:97a889f8-7122-4248-a5fc-4e559cb429e5
172.17.0.7:6379: spring:session:expirations:1593321720000
172.17.0.5:6379: spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5

我们连接到172.17.0.4,查询session的值:

[root@redis3 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -c -h 172.17.0.4

看session的内容:

172.17.0.4:6379> hgetall spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
1) "sessionAttr:user"
2) "\xac\xed\x00\x05t\x00\nthislaoliu"
3) "creationTime"
4) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01r\xf9CW\xb7"
5) "maxInactiveInterval"
6) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b"
7) "lastAccessedTime"
8) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01r\xf9D)n"

可以看到user的值是我们所设置的:thislaoliu

3,测试redis1

访问:http://127.0.0.1:8080/cache/redis1set/cup1

设置一个key,值为:cup1

访问:http://127.0.0.1:8080/cache/redis1get

返回我们设置的值:

连接到redis控制台:

[liuhongdi@localhost ~]$ /usr/local/soft/redis/bin/redis-cli

从redis控制台查看kv

127.0.0.1:6379> get goodsname1
"cup1"

4,测试redis2

访问:http://127.0.0.1:8080/cache/redis2set/phone1

设置一个key,值为:phone1

访问:http://127.0.0.1:8080/cache/redis2get

返回我们设置的值:

连接到redis控制台

[root@localhost etc]# /usr/local/soft/redis/bin/redis-cli -p 6380

从控制台查看值

127.0.0.1:6380> get goodsname2
"phone1"

六,查看spring boot的版本

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.1.RELEASE)

spring boot:使用多个redis数据源(spring boot 2.3.1)的更多相关文章

  1. Spring boot配置多个Redis数据源操作实例

    原文:https://www.jianshu.com/p/c79b65b253fa Spring boot配置多个Redis数据源操作实例 在SpringBoot是项目中整合了两个Redis的操作实例 ...

  2. Spring Boot 集成Mybatis实现多数据源

    静态的方式 我们以两套配置方式为例,在项目中有两套配置文件,两套mapper,两套SqlSessionFactory,各自处理各自的业务,这个两套mapper都可以进行增删改查的操作,在这两个主MYS ...

  3. spring boot 基础篇 -- 阿里多数据源

    这块是比较基础的配置,阿里数据库配置还是比较好用的,并且可以用来监控数据源的情况.废话不多说,下面看代码. 基于maven项目,在pom.xml中添加引用: <dependency> &l ...

  4. Spring Boot WebFlux-06——WebFlux 整合 Redis

    第06课:WebFlux 整合 Redis 前言 上一篇内容讲了如何整合 MongoDB,这里继续讲如何操作 Redis 这个数据源,那什么是 Reids? Redis 是一个高性能的 key-val ...

  5. Spring Boot 学习笔记--整合Redis

    1.新建Spring Boot项目 添加spring-boot-starter-data-redis依赖 <dependency> <groupId>org.springfra ...

  6. spring boot 中 Mybatis plus 多数据源的配置方法

    最近在学习spring boot,发现在jar包依赖方面做很少的工作量就可以了,对于数据库操作,我用的比较多的是mybatis plus,在中央仓库已经有mybatis-plus的插件了,对于单数据源 ...

  7. Spring Boot 2.x整合Redis

    最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...

  8. Spring Boot HikariCP 一 ——集成多数据源

    其实这里介绍的东西主要是参考的另外一篇文章,数据库读写分离的. 参考文章就把链接贴出来,里面有那位的代码,简单明了https://gitee.com/comven/dynamic-datasource ...

  9. Spring Boot + Mybatis多数据源和动态数据源配置

    文章转自 https://blog.csdn.net/neosmith/article/details/61202084 网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种 ...

随机推荐

  1. 使用wireshark分析MQTT协议

    网络上搜索到两种用wireshark工具分析MQTT协议的方法,都是使用wireshark插件,一种是Wireshark Generic Dissector:另一种是使用lua脚本插件(推荐使用这种方 ...

  2. python 手把手教你基于搜索引擎实现文章查重

    前言 文章抄袭在互联网中普遍存在,很多博主都收受其烦.近几年随着互联网的发展,抄袭等不道德行为在互联网上愈演愈烈,甚至复制.黏贴后发布标原创屡见不鲜,部分抄袭后的文章甚至标记了一些联系方式从而使读者获 ...

  3. LG P2389 电脑班的裁员

    Description ZZY有独特的裁员技巧:每个同学都有一个考试得分$a_i(-1000 \leq a_i \leq 1000)$,在$n$个同学$(n \leq 500)$中选出不大于$k$段$ ...

  4. Java成神之路:第一帖---- Vue的组件属性components用法

    Vue的组件属性:components 使用场景 一般在项目的使用过程中,某个需要多次使用的模块,会将整个模块抽取出来,写一个组件,供给其他页面进行调用或者是在一个页面中,多次使用到一个重复的代码样式 ...

  5. [06] 优化C#服务器的思路和工具的使用

    优化C#服务器的思路和工具的使用 优化服务器之前, 需要先对问题的规模做合理的预估, 然后对关键的数据做采样, 做对比, 看和自己的预估是否一致, 误差大在什么地方, 是预估的不对, 还是系统实现有问 ...

  6. 部署Go语言程序的N种方式

    部署Go语言项目 本文以部署 Go Web 程序为例,介绍了在 CentOS7 服务器上部署 Go 语言程序的若干方法. 独立部署 Go 语言支持跨平台交叉编译,也就是说我们可以在 Windows 或 ...

  7. Spring Boot学习(二)搭建一个简易的Spring Boot工程

    第一步:新建项目 新建一个SpringBoot工程 修改项目信息 勾选项目依赖和工具 选择好项目的位置,点击[Finish] 第二步:项目结构分析 新建好项目之后的结构如下图所示,少了很多配置文件: ...

  8. subDomainsBrute安装(windows系统)

    step1:  安装python2.7(省略) step2:  下载subDomainsBrute 地址: https://github.com/lijiejie/subDomainsBrute 下载 ...

  9. MySQL分区 (分区介绍与实际使用)

    分区介绍: 一.什么是分区? 所谓分区,就是将一个表分成多个区块进行操作和保存,从而降低每次操作的数据,提高性能.而对于应用来说则是透明的,从逻辑上看只有一张表,但在物理上这个表可能是由多个物理分区组 ...

  10. MySQL: 2、SQL语言

    一.SQL的简介: 1.SQL的概念: SQL就是结构化查询语言,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询.更新和管理关系数据库系统 2.SQL的作用:   - ...