lettuce+pool+redisTemplate实现redis单机和集群的整合

lettuce+pool+redisTemplate实现redis单机和集群的整合

Springboot 整合redis是非常方便的,大致包含如下四部分

  • pom start相关jar的引入
  • properties/yaml 基础配置信息
  • config bean的init
  • bean的注入及使用

如果遇到网上的自动装配的实例直接跳过吧,哪怕再小的公司,密码也会加密处理,不可能自动装配。

1、pom

引入Springboot的redis相关组件

        <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>

2、properties基础配置

这里主要配置数据源,其他配置项没有,暂时简化了配置,一切使用默认

为了适配真实业务,这里采用的是双数据源配置,亦真亦假,一单节点一集群。

redis.biz.alone.host=39.105.198.245:6379
redis.biz.alone.auth=hcgk&2022
redis.biz.cluster.host=10.22.251.21:6379,10.22.251.28:6379,10.22.251.23:6379
redis.biz.cluster.auth=7ujm*IK<
lettuce.pool.max-total=12
# 最大活跃链接数 默认8(使用负值表示没有限制)
lettuce.pool.max-active=12
# 最大空闲连接数 默认8
lettuce.pool.max-idle=12
# 最小空闲连接数 默认0
lettuce.pool.min-idle=0
# 连接池最大阻塞等待时间(使用负值表示没有限制)
lettuce.pool.max-wait=-1

3、config

支持单击和集群

package com.wht.test.config;

import io.lettuce.core.ReadFrom;
import io.lettuce.core.TimeoutOptions;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
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.context.annotation.Scope;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
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.StringRedisTemplate;

import java.time.Duration;
import java.util.HashSet;
import java.util.Set;

/**
 * 支持单机、集群和多实例
 *
 * @Author 红尘过客
 * @DateTime 2023-06-19 22:00:12
 */
@Configuration
public class LettuceRedisConfig {

    @Value("${redis.biz.alone.host}")
    private String bizAloneHost;

    @Value("${redis.biz.alone.auth}")
    private String bizAloneAuth;


    @Value("${redis.biz.cluster.host}")
    private String bizClusterHost;

    @Value("${redis.biz.cluster.auth}")
    private String bizClusterAuth;


    @Bean
    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
    @Scope(value = "prototype")
    public GenericObjectPoolConfig redisPool() {
        return new GenericObjectPoolConfig();
    }

    @Primary
    @Bean("bizAlone")
    public StringRedisTemplate bizAlone(GenericObjectPoolConfig redisPool) {
        return getStringRedisTemplate(bizAloneHost, bizAloneAuth, redisPool);
    }

//    @Primary
//    @Bean("bizCluster")
//    public StringRedisTemplate bizCluster(GenericObjectPoolConfig redisPool) {
//        return getStringRedisTemplate(bizClusterHost, bizClusterAuth,redisPool);
//    }

    /**
     * 封装单例配置
     *
     * @param host
     * @param password
     * @return
     */
    private RedisStandaloneConfiguration getRedisStandaloneConfiguration(String host, String password) {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        String[] redisNode = host.split(":");
        if (redisNode.length == 2) {
            redisStandaloneConfiguration.setHostName(redisNode[0]);
            redisStandaloneConfiguration.setPort(Integer.parseInt(redisNode[1]));
        }
        if (password != null || password.trim().length() > 0) {
            redisStandaloneConfiguration.setPassword(password);
        }
        return redisStandaloneConfiguration;
    }

    /**
     * 把集群连接串拆分为redisNodes
     *
     * @param host
     * @return
     */
    private Set<RedisNode> getClusterNodes(String host) {
        String[] nodesArray = host.split(",");
        Set<RedisNode> clusterNodes = new HashSet<>();
        for (String node : nodesArray) {
            String[] redisNode = node.split(":");
            clusterNodes.add(new RedisNode(redisNode[0], Integer.parseInt(redisNode[1])));
        }
        return clusterNodes;
    }

    /**
     * 封装集群配置
     *
     * @param host
     * @param password
     * @return
     */
    private RedisClusterConfiguration getRedisClusterConfiguration(String host, String password) {
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        redisClusterConfiguration.setClusterNodes(getClusterNodes(host));
        if (password != null || password.trim().length() > 0) {
            redisClusterConfiguration.setPassword(password);
        }
        return redisClusterConfiguration;
    }

    /**
     * 创建alone bean
     * 这里用LettucePoolingClientConfiguration 预留了连接池
     *
     * @param host
     * @param password
     * @return
     */
    private StringRedisTemplate getStringRedisTemplate(String host, String password, GenericObjectPoolConfig redisPool) {
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
        builder.poolConfig(redisPool);
        LettuceConnectionFactory connectionFactory = null;
        // 集群要做拓扑刷新,应对准备切换,摸个节点挂掉等问题
        if (host.contains(",")) {
            ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
                    .enablePeriodicRefresh(Duration.ofSeconds(10))
                    .enableAllAdaptiveRefreshTriggers()
                    .build();
            ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
                    .timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(60)))
                    .topologyRefreshOptions(topologyRefreshOptions)
                    .build();

            LettuceClientConfiguration clientConfiguration = builder.commandTimeout(Duration.ofSeconds(60))
                    .readFrom(ReadFrom.REPLICA_PREFERRED)
                    .clientOptions(clusterClientOptions)
                    .build();
            connectionFactory = new LettuceConnectionFactory(getRedisClusterConfiguration(host, password), clientConfiguration);
        } else {
            connectionFactory = new LettuceConnectionFactory(getRedisStandaloneConfiguration(host, password), builder.build());
        }
        connectionFactory.afterPropertiesSet();
        return getStringRedisTemplate(connectionFactory);
    }

    private StringRedisTemplate getStringRedisTemplate(LettuceConnectionFactory connectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(connectionFactory);
        return stringRedisTemplate;
    }
}

4、使用

这里简单搞个schedule任务

package com.wht.test.schedule;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

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

/**
 * desc
 *
 * @Author 红尘过客
 * @DateTime 2023-06-15 10:15:35
 */
@Component
public class RedisTestJob {
    @Resource(name = "bizAlone")
    private StringRedisTemplate stringRedisTemplate;

    @Scheduled(cron = "* * * * * * ")
    public void test() {
        for (int i = 0; i < 100; i++) {
            String key = "test_" + i;
            stringRedisTemplate.opsForValue().set(key, "test_value_" + i, Duration.ofHours(1));
            String name = (String) stringRedisTemplate.opsForValue().get(key);
            System.out.println("value = " + name);
        }


    }
}

可以正常写入数据到redis了

posted @ 2023-06-19 22:49  红尘过客2022  阅读(426)  评论(0编辑  收藏  举报