首页 > 数据库 >Redis-12-SpringBoot集成Redis哨兵模式

Redis-12-SpringBoot集成Redis哨兵模式

时间:2024-06-07 17:36:22浏览次数:23  
标签:12 SpringBoot redis Redis springframework private org import 节点

Redis哨兵的配置,参考我这篇文章:

Redis-5-高可用

1.背景

网上搜半天没搜到份好用的,自己整理了下方便以后复制,基于springboot 2.6.13。

  • lettuce
  • commons-pool2

2.集成

2.1 导入pom

        <!-- spring-redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- commons-pool2 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

2.2 编写配置文件

结合自己的项目更新,此处直接写在了application.yml中。

spring:
  redis:
    password: 主节点密码
    lettuce:
      pool:
        # 最大连接数
        max-active: 20
        # 连接池中获取连接时最大等待时间ms
        max-wait: 300
        # 最大空闲连接数
        max-idle: 5
        # 最小空闲连接数
        min-idle: 1
    sentinel:
      master: 要监控的主节点
      password: 哨兵密码
      # 哨兵集群
      nodes:
        - ip1:26379
        - ip2:26380
        - ip3:26381

2.3 编写配置实体类

RedisProperties:映射配置文件

package cn.yang37.za.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.Set;

/**
 * @description:
 * @class: RedisProperties
 * @author: [email protected]
 * @date: 2024/6/7 16:07
 * @version: 1.0
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

    private String password;
    private Lettuce lettuce;
    private Sentinel sentinel;

    @Data
    public static class Lettuce {
        private Pool pool;

        @Data
        public static class Pool {
            private int maxActive;
            private int maxWait;
            private int maxIdle;
            private int minIdle;
        }
    }

    @Data
    public static class Sentinel {
        private String master;
        private String password;
        private Set<String> nodes;
    }
}

2.4 编写哨兵配置类

RedisSentinelConfig:哨兵配置信息加载、commonsPool配置信息加载、lettuce连接池构建

package cn.yang37.za.config;

import cn.yang37.za.properties.RedisProperties;
import io.lettuce.core.ReadFrom;
import io.lettuce.core.resource.DefaultClientResources;
import lombok.extern.slf4j.Slf4j;
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.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @class: RedisSentinelConfig
 * @author: [email protected]
 * @date: 2024/6/7 15:11
 * @version: 1.0
 */
@Slf4j
@Configuration
public class RedisSentinelConfig {

    @Resource
    private RedisProperties redisProperties;

    private DefaultClientResources clientResources;

    /**
     * 构建commonsPool配置
     *
     * @return .
     */
    @Bean
    public GenericObjectPoolConfig<?> genericObjectPoolConfig() {
        GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
        config.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
        config.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
        config.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
        config.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait());
        return config;
    }

    /**
     * 构建RedisSentinel配置
     *
     * @return .
     */
    @Bean
    public RedisSentinelConfiguration sentinelConfiguration() {
        RedisSentinelConfiguration redisSentinelConfiguration =
                new RedisSentinelConfiguration(redisProperties.getSentinel().getMaster(), redisProperties.getSentinel().getNodes());
        // 主节点密码
        redisSentinelConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
        // 哨兵密码
        redisSentinelConfiguration.setSentinelPassword(RedisPassword.of(redisProperties.getSentinel().getPassword().toCharArray()));
        return redisSentinelConfiguration;
    }

    /**
     * 构建lettuce连接池
     *
     * @param genericObjectPoolConfig .
     * @param sentinelConfiguration   .
     * @return .
     */
    @Bean
    public RedisConnectionFactory lettuceConnectionFactory(GenericObjectPoolConfig<?> genericObjectPoolConfig,
                                                           RedisSentinelConfiguration sentinelConfiguration) {
        // 声明资源
        this.clientResources = DefaultClientResources.create();

        // 构建lettuce配置
        LettucePoolingClientConfiguration lettuceClientConfiguration =
                LettucePoolingClientConfiguration.builder()
                        .poolConfig(genericObjectPoolConfig)
                        .readFrom(ReadFrom.REPLICA)
                        .clientResources(clientResources)
                        .build();

        // 构建lettuce连接池
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(sentinelConfiguration, lettuceClientConfiguration);
        // 每次获取连接时验证连接的有效性(注意性能影响)
        lettuceConnectionFactory.setValidateConnection(true);
        // 手动触发连接池初始化
        lettuceConnectionFactory.afterPropertiesSet();

        log.info("connected to redis sentinel,node info: {}", sentinelConfiguration.getSentinels());
        return lettuceConnectionFactory;
    }

    /**
     * 应用关闭时触发
     */
    @PreDestroy
    public void shutdown() {
        if (null != clientResources) {
            clientResources.shutdown(100, 100, TimeUnit.MILLISECONDS);
        }
    }
}

注意,读取的策略根据ReadFrom来配置。

        // 构建lettuce配置
        LettucePoolingClientConfiguration lettuceClientConfiguration =
                LettucePoolingClientConfiguration.builder()
                        .poolConfig(genericObjectPoolConfig)
                        // 确定从哪个节点读取数据
                        .readFrom(ReadFrom.REPLICA)
                        .clientResources(clientResources)
                        .build();
策略 用途
MASTER / UPSTREAM 从主节点读取数据。主节点通常处理所有写操作。
MASTER_PREFERRED / UPSTREAM_PREFERRED 优先从主节点读取数据,但如果主节点不可用,则从从节点读取数据。
REPLICA_PREFERRED 优先从从节点读取数据,但如果所有从节点不可用,则从主节点读取数据。
REPLICA 仅从从节点读取数据。
SLAVE (Deprecated) 仅从从节点读取数据。已废弃,用 REPLICA 替代。
LOWEST_LATENCY 从具有最低延迟的节点读取数据,可能是主节点或从节点。
NEAREST (Deprecated) 从最近的节点读取数据。已废弃,通常 LOWEST_LATENCY 替代。
ANY 从任意节点读取数据。通常用于负载均衡。
ANY_REPLICA 从任意从节点读取数据。用于从节点负载均衡,但不包括主节点。

2.5 编写Redis配置类

RedisConfig:自定义RedisTemplate、StringRedisTemplate

package cn.yang37.za.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
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.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @description:
 * @class: RedisConfig
 * @author: [email protected]
 * @date: 2024/5/27 11:40
 * @version: 1.0
 */
@Configuration
public class RedisConfig {

    /**
     * 1.使用自定义lettuce连接池
     * 2.声明序列化方式
     *
     * @param connectionFactory .
     * @return .
     */
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(@Qualifier("lettuceConnectionFactory") RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);

        // 配置String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // 配置Json的序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // Key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        // Hash的key也采用String的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        // Value序列化方式采用jackson
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // Hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 1.使用自定义lettuce连接池
     * 2.声明序列化方式
     *
     * @param connectionFactory .
     * @return .
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(@Qualifier("lettuceConnectionFactory") RedisConnectionFactory connectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        stringRedisTemplate.setConnectionFactory(connectionFactory);
        stringRedisTemplate.setKeySerializer(stringRedisSerializer);
        stringRedisTemplate.setValueSerializer(stringRedisSerializer);

        stringRedisTemplate.afterPropertiesSet();
        return stringRedisTemplate;
    }

}

3.测试

导入test组件

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

编写RedisControl的测试用例

package cn.yang37.za.controller;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Slf4j
@SpringBootTest
class RedisControllerTest {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void name1() {
        final String key = "yang37";

        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "123", 600, TimeUnit.SECONDS);
        log.info("flag: {}", flag);

        String value = stringRedisTemplate.opsForValue().get(key);
        log.info("value: {}", value);

        Long expire = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
        log.info("expire: {}", expire);
    }

}

运行

image-20240607165600653

4.注意

哨兵的配置文件中,填写你程序能访问到的ip,似乎Redis是根据这里填写的ip值返回的节点地址。

image-20240607170803957

截图中,哨兵配置文件不是redis自动追加了几行嘛,我框起来的那里。

sentinel known-replica mymaster xx

这个配置文件,估计就是哨兵服务自己为了持久化信息保存的,它内存里面估计就是读取known-replica的ip值来返回。

我服务器上自己做测试用的,开始一直写的127.0.0.1,SpringBoot中就一直跑去访问127.0.0.1,改成实际的就好了。

标签:12,SpringBoot,redis,Redis,springframework,private,org,import,节点
From: https://www.cnblogs.com/yang37/p/18237581

相关文章

  • Tita的OKR : 每次审查 OKR时,团队要讨论的12个启发性问题
     你使用OKRs(目标和关键结果)吗?它们是一种在企业内部集中精力的好方法。当生活繁忙时,很容易迷失在“嘈杂的工作“中,从而无法推动你的业务发展。一个能够帮助你深入了解重要事情的工具是有益的。OKRs提供了这个框架,使你保持在正确的轨道上。写好OKR是一门艺术,我们在以前的博客......
  • 基于SpringBoot+Vue的网上花店系统设计与实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示项目运行截图技术框架后端采用SpringBoot框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • 基于SpringBoot+Vue的校园驿站管理系统设计与实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示项目运行截图技术框架后端采用SpringBoot框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • 基于SpringBoot+Vue的二手手机交易平台的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示项目运行截图技术框架后端采用SpringBoot框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • 使用Redis优化Java应用的性能——高效的缓存实践
    引言:在现代应用开发中,高效的缓存策略是提升性能和用户体验的关键。Redis作为一个高性能的键值存储系统,提供了一种快速存取数据的方式,帮助Java应用处理大量动态信息而无需频繁查询数据库。什么是Redis?Redis是一个开源的键值存储系统,它支持多种类型的数据结构如字符串、哈希、......
  • Docker 下载redis
    docker拉取redis镜像dockerpullredis:对应的版本号(不写默认为最新版) 查看镜像是否拉取成功dockerimages 创建redis配置文件启动前需要先创建reids的外部挂载的配置文件(/opt/docker/redis/conf/redis.conf)(因为redis本身容器只存在/etc/redis目录,本身就不创建redis......
  • 高并发下使用Redis分布式锁确保接口执行唯一性【重点】
    摘要:本文将介绍如何使用Redis分布式锁来确保在高并发环境下,确保某个接口只有一个线程能够执行。通过使用Redis的SETNX命令,我们可以实现一个简单的分布式锁,从而避免多个线程同时访问共享资源。一、背景在高并发的系统中,为了保证数据的一致性和完整性,我们经常需要对某些接口......
  • SpringBoot 启动方法
    SpringBoot启动方法入口通常一个简单的SpringBoot基础项目我们会有如下代码@SpringBootApplication@RestController@RequestMapping("/")publicclassApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(Application.class,args......
  • springboot-异步使用
    创建配置类,开启异步和创建线程packagecom.chulx.demo1.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.scheduling.annotation.EnableAsync;importorg.springframe......
  • 谈谈Redis缓存中MySQL的数据如何与Redis同步
    在现代应用程序中,性能和响应速度是至关重要的。为了提高数据访问速度,常常会使用缓存技术。Redis作为一种高性能的内存数据库,常被用作缓存层,而MySQL则作为持久化存储层。如何有效地将MySQL数据与Redis缓存进行同步,是一个关键问题。本文将详细探讨Redis作为缓存时,http://ww......