Redis之读写分离

1.环境

在Linux服务上实现Redis服务 主从同步

        <!-- RedisTemplate -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
spring:
  redis:
    master:
      host: 192.168.8.128
      port: 6381
      password: 3Q3Q
      database: 0
      timeout: 4000
      pool:
        max-wait: -1
        max-active: -1
        max-idle: 20
        min-idle: 10
    slave:
      host: 192.168.8.128
      port: 6382
      password: 3Q3Q
      database: 0
      timeout: 4000
      pool:
        max-wait: -1
        max-active: -1
        max-idle: 20
        min-idle: 10
    slave2:
      host: 192.168.8.128
      port: 6383
      password: 3Q3Q
      database: 0
      timeout: 4000
      pool:
        max-wait: -1
        max-active: -1
        max-idle: 20
        min-idle: 10

在这里插入图片描述

2.配置

package com.yzm.redis05.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RedisProperties {
    private Integer database;
    private String host;
    private Integer port;
    private String password;
    private Integer timeout;
    private Pool pool;

    @Data
    public static class Pool {
        private Integer maxActive;
        private Integer minIdle;
        private Integer maxIdle;
        private Integer maxWait;
    }
}
package com.yzm.redis05.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Configuration
public class ObjectMapperConfig {

    private static final String PATTERN = "yyyy-MM-dd HH:mm:ss";

    @Bean(name = "myObjectMapper")
    public ObjectMapper objectMapper() {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        return new ObjectMapper()
                // 转换为格式化的json(控制台打印时,自动格式化规范)
                //.enable(SerializationFeature.INDENT_OUTPUT)
                // Include.ALWAYS  是序列化对像所有属性(默认)
                // Include.NON_NULL 只有不为null的字段才被序列化,属性为NULL 不序列化
                // Include.NON_EMPTY 如果为null或者 空字符串和空集合都不会被序列化
                // Include.NON_DEFAULT 属性为默认值不序列化
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                // 如果是空对象的时候,不抛异常
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                // 反序列化的时候如果多了其他属性,不抛出异常
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                // 取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                .setDateFormat(new SimpleDateFormat(PATTERN))
                // 对LocalDateTime序列化跟反序列化
                .registerModule(javaTimeModule)

                .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
                // 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
                .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
                ;
    }

    static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.format(DateTimeFormatter.ofPattern(PATTERN)));
        }
    }

    static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException {
            return LocalDateTime.parse(p.getValueAsString(), DateTimeFormatter.ofPattern(PATTERN));
        }
    }

}
package com.yzm.redis05.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.Resource;
import java.time.Duration;

@Configuration
public class RedisConfig {

    @Resource(name = "myObjectMapper")
    private ObjectMapper objectMapper;

    //=============================================== master =======================================================
    @Bean(name = "masterProperties")
    @ConfigurationProperties(prefix = "spring.redis.master")
    public RedisProperties masterProperties() {
        return new RedisProperties();
    }

    @Primary
    @Bean(name = "masterFactory")
    public RedisConnectionFactory masterFactory(@Qualifier("masterProperties") RedisProperties redisProperties) {
        return this.createRedisConnFactory(redisProperties);
    }

    @Bean(name = "masterRedisTemplate")
    public RedisTemplate<String, Object> masterRedisTemplate(@Qualifier("masterFactory") RedisConnectionFactory redisConnectionFactory) {
        return this.buildRedisTemplate(redisConnectionFactory);
    }

    //=============================================== slave =======================================================
    @Bean(name = "slaveProperties")
    @ConfigurationProperties(prefix = "spring.redis.slave")
    public RedisProperties slaveProperties() {
        return new RedisProperties();
    }

    @Bean(name = "slaveFactory")
    public RedisConnectionFactory slaveFactory(@Qualifier("slaveProperties") RedisProperties redisProperties) {
        return this.createRedisConnFactory(redisProperties);
    }

    @Bean(name = "slaveRedisTemplate")
    public RedisTemplate<String, Object> slaveRedisTemplate(@Qualifier("slaveFactory") RedisConnectionFactory redisConnectionFactory) {
        return this.buildRedisTemplate(redisConnectionFactory);
    }

    //=============================================== slave2 =======================================================
    @Bean(name = "slave2Properties")
    @ConfigurationProperties(prefix = "spring.redis.slave2")
    public RedisProperties slave2Properties() {
        return new RedisProperties();
    }

    @Bean(name = "slave2Factory")
    public RedisConnectionFactory slave2Factory(@Qualifier("slave2Properties") RedisProperties redisProperties) {
        return this.createRedisConnFactory(redisProperties);
    }

    @Bean(name = "slave2RedisTemplate")
    public RedisTemplate<String, Object> slave2RedisTemplate(@Qualifier("slave2Factory") RedisConnectionFactory redisConnectionFactory) {
        return this.buildRedisTemplate(redisConnectionFactory);
    }

    public RedisConnectionFactory createRedisConnFactory(RedisProperties redisProperties) {
        RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
        standaloneConfiguration.setHostName(redisProperties.getHost());
        standaloneConfiguration.setPort(redisProperties.getPort());
        standaloneConfiguration.setDatabase(redisProperties.getDatabase());
        standaloneConfiguration.setPassword(redisProperties.getPassword());

        return lettuceConnectionFactory(redisProperties, standaloneConfiguration);
//        return jedisConnectionFactory(redisProperties, standaloneConfiguration);
    }

    //Lettuce
    private LettuceConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties, RedisStandaloneConfiguration standaloneConfiguration) {
        LettuceClientConfiguration build = LettucePoolingClientConfiguration.builder().
                commandTimeout(Duration.ofMillis(redisProperties.getTimeout()))
                .poolConfig(createPoolConfig(redisProperties, new GenericObjectPoolConfig()))
                .build();

        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(standaloneConfiguration, build);
        lettuceConnectionFactory.afterPropertiesSet();
        return lettuceConnectionFactory;
    }

    //Jedis
    private JedisConnectionFactory jedisConnectionFactory(RedisProperties redisProperties, RedisStandaloneConfiguration standaloneConfiguration) {
        JedisClientConfiguration build = JedisClientConfiguration.builder()
                .connectTimeout(Duration.ofMillis(redisProperties.getTimeout()))
                .usePooling()
                .poolConfig(createPoolConfig(redisProperties, new JedisPoolConfig()))
                .build();

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(standaloneConfiguration, build);
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }

    private GenericObjectPoolConfig createPoolConfig(RedisProperties redisProperties, GenericObjectPoolConfig poolConfig) {
        //最大连接数, 默认8个
        poolConfig.setMaxTotal(redisProperties.getPool().getMaxActive());
        //最大空闲连接数, 默认8个
        poolConfig.setMaxIdle(redisProperties.getPool().getMaxIdle());
        //最小空闲连接数, 默认0个
        poolConfig.setMinIdle(redisProperties.getPool().getMinIdle());
        //获取连接时的最大等待毫秒数,默认-1
        poolConfig.setMaxWaitMillis(redisProperties.getPool().getMaxWait());

        //最小可驱逐空闲时间 毫秒,达到此值后空闲资源将被移除  默认1800000毫秒(30分钟)
        poolConfig.setMinEvictableIdleTimeMillis(1800000);
        //空闲资源的检测周期(单位为毫秒) 如果为负数,则不运行逐出线程, 默认-1
        poolConfig.setTimeBetweenEvictionRunsMillis(-1);

        poolConfig.setTestWhileIdle(false);
        poolConfig.setTestOnCreate(false);
        poolConfig.setTestOnBorrow(false);
        poolConfig.setTestOnReturn(false);
        return poolConfig;
    }

    public RedisTemplate<String, Object> buildRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(redisConnectionFactory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        jacksonSerializer.setObjectMapper(objectMapper);

        //使用StringRedisSerializer来序列化和反序列化redis的key,value采用json序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jacksonSerializer);

        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(jacksonSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

3.接口

package com.yzm.redis05.controller;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class RedisController {

    @Resource(name = "masterRedisTemplate")
    private RedisTemplate<String, Object> writeTemplate;
    @Resource(name = "slaveRedisTemplate")
    private RedisTemplate<String, Object> readTemplate;
    @Resource(name = "slave2RedisTemplate")
    private RedisTemplate<String, Object> read2Template;

    @GetMapping("/set")
    public String set(String key, String value) {
        writeTemplate.opsForValue().set(key, value);
        return "success";
    }

    @GetMapping("/get")
    public String get(String key) {
        System.out.println("readTemplate = " + readTemplate.opsForValue().get(key));
        System.out.println("read2Template = " + read2Template.opsForValue().get(key));
        return "success";
    }
}

4.测试

http://localhost:8080/set?key=name&value=yzm
http://localhost:8080/get?key=name
在这里插入图片描述
在这里插入图片描述

相关链接

首页
上一篇:主从同步
下一篇:哨兵模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值