Redis哨兵java实现

@


前言


一、添加依赖

因我的构建 cloud 项目,这里直接把可能会用的依赖都放到一起

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

二、改好 RedisConfig

前提是已经建好 Redis 的 springboot 项目,按网上的操作就行。我的是在这基础上操作

package com.ams.common.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisServer;
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 java.time.Duration;
import java.util.List;

@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {

<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> RedisProperties properties;

<span class="hljs-keyword">public</span> <span class="hljs-title function_">RedisConfig</span><span class="hljs-params">(RedisProperties properties)</span>{
    <span class="hljs-built_in">this</span>.properties = properties;
}

<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> RedisTemplate&lt;String, Object&gt; <span class="hljs-title function_">redisTemplate</span><span class="hljs-params">()</span> {

    RedisTemplate&lt;String, Object&gt; redisTemplate = <span class="hljs-keyword">new</span> <span class="hljs-title class_">RedisTemplate</span>&lt;&gt;();
    redisTemplate.setConnectionFactory(getConnectionFactory());

    <span class="hljs-comment">// 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值</span>
    <span class="hljs-type">StringRedisSerializer</span> <span class="hljs-variable">stringRedisSerializer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringRedisSerializer</span>();
    redisTemplate.setKeySerializer(stringRedisSerializer); <span class="hljs-comment">// key</span>
    <span class="hljs-type">Jackson2JsonRedisSerializer</span> <span class="hljs-variable">jackson2JsonRedisSerializer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Jackson2JsonRedisSerializer</span>(Object.class);
    <span class="hljs-type">ObjectMapper</span> <span class="hljs-variable">objectMapper</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectMapper</span>();
    <span class="hljs-comment">// 指定要序列化的域(field,get,set),访问修饰符(public,private,protected)</span>
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); <span class="hljs-comment">//value</span>

    redisTemplate.setHashKeySerializer(stringRedisSerializer);
    redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

    redisTemplate.afterPropertiesSet();
    <span class="hljs-keyword">return</span> redisTemplate;
}

<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> RedisConnectionFactory <span class="hljs-title function_">getConnectionFactory</span><span class="hljs-params">()</span> {
    <span class="hljs-comment">//哨兵模式</span>
    <span class="hljs-type">RedisSentinelConfiguration</span> <span class="hljs-variable">configuration</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RedisSentinelConfiguration</span>();
    configuration.setMaster(properties.getSentinel().getMaster());
    configuration.setPassword(properties.getPassword());
    configuration.setDatabase(properties.getDatabase());
    List&lt;String&gt; nodes = properties.getSentinel().getNodes();
    nodes.forEach(node -&gt; {
        String[] str = node.split(<span class="hljs-string">":"</span>);
        <span class="hljs-type">RedisNode</span> <span class="hljs-variable">redisServer</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RedisServer</span>(str[<span class="hljs-number">0</span>], Integer.parseInt(str[<span class="hljs-number">1</span>]));
        configuration.sentinel(redisServer);
    });
    <span class="hljs-type">LettuceConnectionFactory</span> <span class="hljs-variable">factory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">LettuceConnectionFactory</span>(configuration, getPool());
    <span class="hljs-comment">//使用前先校验连接,这个最好是要配置:不然会带来connection reset by peer</span>
    factory.setValidateConnection(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">return</span> factory;
}

<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> LettuceClientConfiguration <span class="hljs-title function_">getPool</span><span class="hljs-params">()</span> {
    <span class="hljs-type">GenericObjectPoolConfig</span> <span class="hljs-variable">genericObjectPoolConfig</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">GenericObjectPoolConfig</span>();
    <span class="hljs-comment">//redis客户端配置:超时时间默认</span>
    LettucePoolingClientConfiguration.<span class="hljs-type">LettucePoolingClientConfigurationBuilder</span>
            <span class="hljs-variable">builder</span> <span class="hljs-operator">=</span> LettucePoolingClientConfiguration.builder().
            commandTimeout(Duration.ofMillis(<span class="hljs-number">60000</span>));
    <span class="hljs-comment">//连接池配置</span>
    RedisProperties.<span class="hljs-type">Pool</span> <span class="hljs-variable">pool</span> <span class="hljs-operator">=</span> properties.getLettuce().getPool();
    genericObjectPoolConfig.setMaxIdle(pool.getMaxIdle());
    genericObjectPoolConfig.setMinIdle(pool.getMinIdle());
    genericObjectPoolConfig.setMaxTotal(pool.getMaxActive());
    genericObjectPoolConfig.setMaxWaitMillis(pool.getMaxWait().toMillis());
    builder.shutdownTimeout(Duration.ofMillis(<span class="hljs-number">4000</span>));
    builder.poolConfig(genericObjectPoolConfig);
    <span class="hljs-keyword">return</span> builder.build();
}

三、修改 nacos 中 Redis 的配置

redis:
  sentinel:
    master: master
    nodes: 192.168.2.237:6776,192.168.2.37:6777,192.168.2.37:6778
  password: 123456
  timeout: 1000
  database: 3
  lettuce:
    pool:
      max-active: 8
      max-wait: 1000
      max-idle: 8
      min-idle: 0

四、其他

1. 踩到的坑如下:

java 一直无法连接 sentinel,关闭防火墙也不行
解决方法:因为之前 redis 配置的防火墙打开,开放端口,所以这里也不能关闭防火墙,而是要开放 sentinel 的几个端口。


随心所往,看见未来。Follow your heart,see night!
欢迎点赞、关注、留言,一起学习、交流!