This comes immediately after the previous Redis6.09 cluster installation (Docker-Compose) was considered for integration with SpringBoot.

Problem 1.

The previous version because of the use of Docker Intranet, resulting in native SpringBoot application; Unable to connect error occurred

1.1 Solutions

How to unify the Redis cluster Docker network segment and SpringBoot.

2. Optimize and enhance docker cluster

Assume the root directory is docker-redis

2.1. Create subdirectory Redis-cluster

2.2. Configuration files

redis-cluster/redis-cluster.tmpl

Port 6379 # Container port requirePass 1234 # Password Masterauth 1234 # Authentication password protected-mode no # Disable protected mode daemonize no # Enable background mode Appendonly yes # enable persistent cluster-enabled yes # Enable cluster mode cluster-config-file nodes.conf # Cluster configuration file cluster-nod-timeout 15000 # Node timeout cluster-announce-ip 192.168.1.126 # Host IP address cluster-announce-port 6379 # External mapping port cluster-announce-bus-port 16379 # Enable the cluster bus port, value =cluster-announce-port +10000Copy the code

2.3. Create directory scripts

redis-cluster/generateFolder.sh

for port in `seq 6379 6384`; do \
  mkdir -p ${port}/conf \
  && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf \
  && mkdir -p ${port}/data; \done
Copy the code

Generatefold. sh will generate six subdirectories under the sibling directory

2.4. Create docker-compose. Yaml in the root directory

For example, Compose
version: "3.8"

# Define service. You can have more than one service
services:
  redis-cluster:
    image: Redis: 6.0.9
    command: redis-cli -a 1234  --cluster create 192.1681.126.: 6379 192.1681.126.: 6380 192.1681.126.: 6381 192.1681.126.: 6382 192.1681.126.: 6383 192.1681.126.: 6384 --cluster-replicas 1  --cluster-yes
    depends_on:
      - redis-6379
      - redis-6380
      - redis-6381
      - redis-6382
      - redis-6383
      - redis-6384
  redis-6379: # Service name
    image: Redis: 6.0.9 # Image required when creating a container
    container_name: redis-6379 # Container name
    restart: always # Container always restarts
    ports:
      - 6379: 6379
      - 16379: 16379
    volumes: # Data volume, directory mount
      - ./redis-cluster/etc_rc.local:/etc/rc.local
      - ./redis-cluster/6379/conf/redis.conf:/etc/redis/redis.conf
      - ./redis-cluster/6379/data:/data
    command: redis-server /etc/redis/redis.conf Overrides the default command executed after the container is started

  redis-6380:
    image: Redis: 6.0.9
    container_name: redis-6380
    ports:
      - 6380: 6379
      - 16380: 16379
    volumes:
      - ./redis-cluster/etc_rc.local:/etc/rc.local
      - ./redis-cluster/6380/conf/redis.conf:/etc/redis/redis.conf
      - ./redis-cluster/6380/data:/data
    command: redis-server /etc/redis/redis.conf

  redis-6381:
    image: Redis: 6.0.9
    container_name: redis-6381
    ports:
      - 6381: 6379
      - 16381: 16379
    volumes:
      - ./redis-cluster/etc_rc.local:/etc/rc.local
      - ./redis-cluster/6381/conf/redis.conf:/etc/redis/redis.conf
      - ./redis-cluster/6381/data:/data
    command: redis-server /etc/redis/redis.conf

  redis-6382:
    image: Redis: 6.0.9
    container_name: redis-6382
    ports:
      - 6382: 6379
      - 16382: 16379
    volumes:
      - ./redis-cluster/etc_rc.local:/etc/rc.local
      - ./redis-cluster/6382/conf/redis.conf:/etc/redis/redis.conf
      - ./redis-cluster/6382/data:/data
    command: redis-server /etc/redis/redis.conf

  redis-6383:
    image: Redis: 6.0.9
    container_name: redis-6383
    ports:
      - 6383: 6379
      - 16383: 16379
    volumes:
      - ./redis-cluster/etc_rc.local:/etc/rc.local
      - ./redis-cluster/6383/conf/redis.conf:/etc/redis/redis.conf
      - ./redis-cluster/6383/data:/data
    command: redis-server /etc/redis/redis.conf

  redis-6384:
    image: Redis: 6.0.9
    container_name: redis-6384
    ports:
      - 6384: 6379
      - 16384: 16379
    volumes:
      - ./redis-cluster/etc_rc.local:/etc/rc.local
      - ./redis-cluster/6384/conf/redis.conf:/etc/redis/redis.conf
      - ./redis-cluster/6384/data:/data
    command: redis-server /etc/redis/redis.conf
Copy the code

2.5 Loading and Starting the Cluster

docker-compose up -d
Copy the code

Problem solving

Caused by: io.lettuce.core.cluster.PartitionSelectorException: Cannot determine a partition for slot nnnnn
Copy the code

For details about the solution, seeJuejin. Cn/post / 684490…

Key points:

docker container ls

docker exec -it 4688b2715f4a /bin/bash

Redis-cli –cluster fix 192.168.1.126:6381-a 1234

3. The spring – the boot integration

3.1. The pom

pom.xml

<! -- Redis Cache -->
<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>
Copy the code

3.2 Configuration File

application.yaml

Database: 0 # redis server connection password: 1234 timeout: 60000ms # Redis Cluster Cluster configuration: # Redis Cluster address information - 192.168.1.126:6379-192.168.1.126:6380-192.168.1.126:6381-192.168.1.126:6382-192.168.1.126:63883 - 192.168.1.129:6384 # Failed to obtain the maximum number of redirects max-redirects: 3 lettuce: pool: max-active: 8 # Maximum number of connections in the connection pool Min -idle: 0 Max -wait: -1 Max -wait: -1 Max -wait timeCopy the code

3.3 configuration class

ClusterConfigurationProperties.java

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {

   / * * spring. Redis. The cluster. Nodes [0] = 127.0.0.1:7379 spring.. Redis cluster. The nodes [1] * = 127.0.0.1:7380... * /
   private List<String> nodes;
   /** * spring.redis.cluster.max-redirects=3 */
   private int maxRedirects;

   /**
    * Get initial collection of known cluster nodes in format {@code host:port}.
    *
    * @return* /
   public List<String> getNodes(a) {
      return nodes;
   }

   public void setNodes(List<String> nodes) {
      this.nodes = nodes;
   }

   public int getMaxRedirects(a) {
      return maxRedirects;
   }

   public void setMaxRedirects(int maxRedirects) {
      this.maxRedirects = maxRedirects; }}Copy the code

3.4 Key Configuration Classes

RedisClusterConfig.java

import io.lettuce.core.ReadFrom; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.scheduling.annotation.EnableAsync; import java.lang.reflect.Method; @Configuration @EnableAsync public class RedisClusterConfig { @Autowired private ClusterConfigurationProperties clusterProperties; @Autowired private RedisProperties redisProperties; @Bean LettuceConnectionFactory redisConnectionFactory(RedisClusterConfiguration redisConfiguration) { LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .readFrom(ReadFrom.REPLICA_PREFERRED).build(); return new LettuceConnectionFactory(redisConfiguration, clientConfig); } @Bean RedisClusterConfiguration redisConfiguration() { RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterProperties.getNodes()); redisClusterConfiguration.setPassword(redisProperties.getPassword()); redisClusterConfiguration.setMaxRedirects(clusterProperties.getMaxRedirects()); return redisClusterConfiguration; } @Bean @ConditionalOnMissingBean(name = "redisTemplate") @Primary RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); template.setKeySerializer(new StringRedisSerializer()); // other settings... return template; } @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target,  Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); }}; }}Copy the code

3.5 Redis access utility class

RedisUtils.java

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import java.io.Serializable; import java.util.*; import java.util.concurrent.TimeUnit; @Component public class RedisUtils { @Autowired private RedisTemplate redisTemplate; ** @param keys */ public void remove(final String... keys) { for (String key : keys) { remove(key); Public void removePattern(final String pattern) {Set<Serializable> keys = redisTemplate.keys(pattern); if (keys.size() > 0) { redisTemplate.delete(keys); }} /** * @param key */ public void remove(final String key) {if (exists(key)) { redisTemplate.delete(key); }} /** * Check whether there is a value in the cache ** @param key * @return */ public Boolean exists(final String key) {return redisTemplate.hasKey(key); } /** * Read cache ** @param key * @return */ public Object get(final String key) {Object result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key); return result; } /** * write to cache ** @param key * @param value * @return */ public Boolean set(final String key, Object value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * write to cache ** @param key * @param value * @return */ public Boolean set(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; }}Copy the code

Then you can use RedisUtils to manipulate Redis in the service.