Spring Boot 连 Redis 主从模式

来自姬鸿昌的知识库
Jihongchang讨论 | 贡献2023年2月19日 (日) 10:28的版本 →‎具体实现机制
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.jihch</groupId>
    <artifactId>spring-boot-redis-master-slave</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.13</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

    </dependencies>
</project>



application.yml

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: vn4sj5kbxdaG



WriteToMasterReadFromReplicaConfiguration.java

package io.github.jihch.config;

import io.lettuce.core.ReadFrom;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
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.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

@Configuration
public class WriteToMasterReadFromReplicaConfiguration {

    @Autowired
    private RedisProperties redisProperties;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {

        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort());
        serverConfig.setPassword(redisProperties.getPassword());

        return new LettuceConnectionFactory(serverConfig, clientConfig);
    }
}



具体实现机制

虽然 application.yml 只进行了 redis master server 的配置,但这确实是一套读写分离的实现,最关键的地方在 WriteToMasterReadFromReplicaConfiguration.java 这个配置类;

经过了这个配置类中对 RedisConnectionFactory 在容器中的 bean 的定义使得 RedisTemplate 的 bean 在底层应用了往 master 上写、从 replica 上读;

这个类的配置让更底层的 Lettuce 在成功连接了 master 之后,通过 info 命令,在 master 上得到了 replica 列表,之后跟 replica 成功建立了 AIO 的 channel 并保存在了内存中;

之后再有的读操作就直接通过这些到 replica 的 AIO channel 交互了。

所以虽然停止了 redis 的 master server 后台会一直报连不上的异常,但读操作仍然可以通过和 replica 的 AIO channel 交互得到数据。


代码

https://github.com/jihch/spring-boot-redis-master-slave


参考

https://docs.spring.io/spring-data/redis/docs/2.5.12/reference/html/#redis:write-to-master-read-from-replica

https://github.com/lettuce-io/lettuce-core/wiki/ReadFrom-Settings#masterreplica-connections-masterslave

https://github.com/lettuce-io/lettuce-core/wiki/ReadFrom-Settings#read-from-settings