Quellcode durchsuchen

admin 添加 redis sentinel 集群的连接和测试

reghao vor 1 Monat
Ursprung
Commit
9b6850651e

+ 6 - 3
admin/pom.xml

@@ -62,9 +62,12 @@
         </dependency>
 
         <dependency>
-            <groupId>io.lettuce</groupId>
-            <artifactId>lettuce-core</artifactId>
-            <version>6.1.10.RELEASE</version>
+            <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>

+ 170 - 0
admin/src/main/java/cn/reghao/tnb/admin/config/RedisConfig.java

@@ -0,0 +1,170 @@
+package cn.reghao.tnb.admin.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.lettuce.core.ReadFrom;
+import io.lettuce.core.resource.DefaultClientResources;
+import jakarta.annotation.PreDestroy;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.springframework.beans.factory.annotation.Qualifier;
+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.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 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;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author reghao
+ * @date 2026-01-23 14:25:52
+ */
+@Slf4j
+//@Configuration
+public class RedisConfig {
+    @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.setMaxWait(redisProperties.getLettuce().getPool().getMaxWait());
+        return config;
+    }
+
+    /**
+     * 构建RedisSentinel配置
+     *
+     * @return .
+     */
+    @Bean
+    public RedisSentinelConfiguration sentinelConfiguration() {
+        List<String> nodeList = redisProperties.getSentinel().getNodes();
+        RedisSentinelConfiguration redisSentinelConfiguration =
+                new RedisSentinelConfiguration(redisProperties.getSentinel().getMaster(), new HashSet<>(nodeList));
+        // 主节点密码
+        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);
+        }
+    }
+
+    /**
+     * 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;
+    }
+}

+ 17 - 2
admin/src/main/resources/application-cluster.yml

@@ -9,9 +9,24 @@ spring:
   data:
     redis:
       database: 0
-      host: 192.168.0.211
-      port: 6379
       password: Test@123456
+      lettuce:
+        pool:
+          # 最大连接数
+          max-active: 20
+          # 连接池中获取连接时最大等待时间ms
+          max-wait: 300
+          # 最大空闲连接数
+          max-idle: 5
+          # 最小空闲连接数
+          min-idle: 1
+      sentinel:
+        master: mymaster
+        password: Test@123456
+        nodes:
+          - 192.168.0.214:26379
+          - 192.168.0.215:26379
+          - 192.168.0.216:26379
   rabbitmq:
     addresses: 192.168.0.211:5672,192.168.0.212:5672,192.168.0.213:5672
     virtual-host: /

+ 90 - 0
admin/src/test/java/RedisTest.java

@@ -0,0 +1,90 @@
+import cn.reghao.tnb.admin.AdminApplication;
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.RedisURI;
+import io.lettuce.core.api.StatefulRedisConnection;
+import io.lettuce.core.api.sync.RedisCommands;
+import io.lettuce.core.sentinel.api.StatefulRedisSentinelConnection;
+import io.lettuce.core.sentinel.api.sync.RedisSentinelCommands;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.env.Environment;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisSentinelConnection;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author reghao
+ * @date 2026-01-23 14:31:47
+ */
+@Slf4j
+@ActiveProfiles("dev")
+@SpringBootTest(classes = AdminApplication.class)
+public class RedisTest {
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+    @Qualifier("lettuceConnectionFactory")
+    RedisConnectionFactory connectionFactory;
+
+    @Test
+    void test() throws InterruptedException {
+        final String key = "hao";
+        String value0 = "1234567890";
+        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, value0, 600, TimeUnit.SECONDS);
+        log.info("flag: {}", flag);
+
+        while (!Thread.interrupted()) {
+            String value = stringRedisTemplate.opsForValue().get(key);
+            log.info("value: {}", value);
+
+            Long expire = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
+            log.info("expire: {}", expire);
+
+            Thread.sleep(3000);
+        }
+    }
+
+    @Test
+    public void connTest() {
+        String masterId = "mymaster";
+        RedisURI redisUri = RedisURI.Builder
+                .sentinel("192.168.0.214", 26379, masterId, "Test@123456")
+                .withSentinel("192.168.0.215")
+                .withSentinel("192.168.0.216")
+                .withPassword("Test@123456".toCharArray())
+                .build();
+        RedisClient redisClient = RedisClient.create(redisUri);
+
+        StatefulRedisConnection<String, String> redisConn = redisClient.connect();
+        System.out.println("Connected to Redis using Redis Sentinel");
+        RedisCommands<String, String> redisCommands = redisConn.sync();
+
+        // 包括 Replication 信息
+        String redisInfo = redisCommands.info();
+
+        StatefulRedisSentinelConnection<String, String> sentinelConn =  redisClient.connectSentinel();
+        RedisSentinelCommands<String, String> sentinelCommands = sentinelConn.sync();
+        // 包括 sentinel 的所有 master
+        List<Map<String, String>> allMastersInfo = sentinelCommands.masters();
+        Map<String, String> masterInfo = sentinelCommands.master(masterId);
+
+        //connection.close();
+        redisClient.shutdown();
+    }
+
+    @Autowired
+    Environment environment;
+    @Test
+    public void zkTest() {
+        String address = environment.getProperty("dubbo.registry.address");
+        String connectString = address.replace("zookeeper://", "").replace("?backup=", ",");
+    }
+}