在这里插入图片描述

一. 问题背景

前面研究了SpringBoot整合Redis集群(Lettuce客户端),然后尝试玩玩读写分离,客户端使用Lettuce(SpringBoot2.x已经默认支持Lettuce了,就不再研究Jedis客户端了)。虽然最新版的Redis Cluster集群架构不推荐读写分离,但是还是想玩玩。文末提供源码

参考自:

二. 版本说明

技术栈版本
SpringBoot2.3.7
Redis集群Redis是5.0版本,推荐5.x以上版本,推荐集群架构是Redis Cluster(不是以前说的主从架构、哨兵集群。Redis Cluster已经集成了主从、哨兵,是最新版的Redis集群架构),如何搭建Redis Cluster可参考基于Docker搭建Redis集群
Docker19.03.13

三. 前言

后面章节只会列出最核心的内容,如看不懂,可以先阅读SpringBoot整合Redis集群(Lettuce客户端),甚至可以阅读笔者写的Redis系列相关的文章。

四. 如何实现读写分离?

Lettuce客户端如何实现读写分离?去看看Lettuce官方文档的ReadFrom Settings部分的介绍,如下:

在这里插入图片描述

解释:

  • 流程大概就是先获取到集群的节点
  • 然后创建集群客户端
  • 然后创建连接
  • 拿到连接,往连接里面设置ReadFrom.REPLICA
  • 最后拿到命令行对象,通过命令行对象调用它提供的API与Redis交互
  • 其实核心的代码就是connection.setReadFrom(ReadFrom.REPLICA)

五. 动手实现读写分离

使用SpringBoot整合Lettuce客户端实现Redis集群的读写分离

5.1 整合Lettuce

加入依赖

<!-- SpringBoot 整合 Redis -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool 缓存连接池-->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
  <version>2.9.0</version>
</dependency>

配置文件

spring:
  redis:
    database: 0
    cluster:
      timeout: 1000
      max-redirects: 3
      nodes: 192.168.199.130:6379,192.168.199.130:6380,192.168.199.130:6381,192.168.199.130:6382,192.168.199.130:6383,192.168.199.130:6384
    lettuce:
      pool:
        max-idle: 10 # 连接池中的最大空闲连接
        max-wait: 500 # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
        min-idle: 0 # 连接池中的最小空闲连接

解释:spring.redis.cluster.nodes的值就是redis集群各个节点所在的ip地址以及端口

5.1 向Spring注册连接组件

其实就是获取到Redis的连接

/**
 * @Author Androidla
 * @Date 2021/2/14 13:40
 * @Description
 **/
@Configuration
@Slf4j
public class RedisConfig {

    @Value("${spring.redis.cluster.nodes}")
    private String CLUSTER_NODES;

    @Bean
    public StatefulRedisClusterConnection statefulRedisClusterConnection() {
        String[] clusterNodes = CLUSTER_NODES.split(",");
        ArrayList<RedisURI> redisURISList = new ArrayList<>();
        for (String node : clusterNodes) {
            String[] ipAndPort = node.split(":");
            redisURISList.add(new RedisURI(ipAndPort[0], Integer.parseInt(ipAndPort[1]),
                Duration.ofDays(10)));// Duration.ofDays(10)随便设置,关系不大
        }
        RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURISList);
        StatefulRedisClusterConnection<String, String> connection = redisClusterClient.connect();
        connection.setReadFrom(ReadFrom.REPLICA);
        return connection;
    }
}

上面的代码块中最核心的就是下面这三行:

RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURISList);
StatefulRedisClusterConnection<String, String> connection = redisClusterClient.connect();
connection.setReadFrom(ReadFrom.REPLICA);

5.2 测试

可以自行创建一套controller到service的业务代码,然后用postman发送请求试试。下面给出核心的测试代码

 public void readFromReplica() {
        String key = "10010";
        log.info("read from replica...");
        log.info("connection class is: {}", connection.getClass());
        RedisAdvancedClusterCommands sync = connection.sync();

        sync.set(key, "中国联通");
        Object value = sync.get(key);
        log.info("value is: {}", value);

        // 官方文档上是有将connection以及client关闭掉的
        //connection.close();
        //client.close();
    }

注意:官方文档给出的代码,最后是要将connection关闭、client关闭的,这里笔者只是演示读写分离,就不再做过多的优化了

源码:前往Gitee下载源码

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐