compose 搭建 redis-cluster 集群(三 master+ 三 replicas)

滴水穿石 不积跬步,无以至千里;不积小流,无以成江海。 本文由博客端 http://www.itwetouch.com 主动推送

运行 6 个 redis 的容器,三个 master,三个 replicas

redis-cluster.yml

version: '3'

services:
  redis-master1:
    image: redis:6.2.1-alpine
    container_name: redis-master1
    command: ["redis-server","/usr/local/etc/redis/redis.conf"]
    ports:
      - 6379:6379
      - 16379:16379
    volumes:
      # echo 'Asia/Shanghai' > /etc/timezone/timezone
      - /etc/timezone/timezone:/etc/timezone
      - /etc/localtime:/etc/localtime
      - ./config/nodes-6379.conf:/usr/local/etc/redis/redis.conf
      - ./data/master1/:/data
  redis-master2:
    image: redis:6.2.1-alpine
    container_name: redis-master2
    command: ["redis-server","/usr/local/etc/redis/redis.conf"]
    ports:
      - 6380:6379
      - 16380:16379
    volumes:
      # echo 'Asia/Shanghai' > /etc/timezone/timezone
      - /etc/timezone/timezone:/etc/timezone
      - /etc/localtime:/etc/localtime
      - ./config/nodes-6380.conf:/usr/local/etc/redis/redis.conf
      - ./data/master2/:/data
  redis-master3:
    image: redis:6.2.1-alpine
    container_name: redis-master3
    command: ["redis-server","/usr/local/etc/redis/redis.conf"]
    ports:
      - 6381:6379
      - 16381:16379
    volumes:
      # echo 'Asia/Shanghai' > /etc/timezone/timezone
      - /etc/timezone/timezone:/etc/timezone
      - /etc/localtime:/etc/localtime
      - ./config/nodes-6381.conf:/usr/local/etc/redis/redis.conf
      - ./data/master3/:/data
  redis-master4:
    image: redis:6.2.1-alpine
    container_name: redis-master4
    command: ["redis-server","/usr/local/etc/redis/redis.conf"]
    ports:
      - 6382:6379
      - 16382:16379
    volumes:
      # echo 'Asia/Shanghai' > /etc/timezone/timezone
      - /etc/timezone/timezone:/etc/timezone
      - /etc/localtime:/etc/localtime
      - ./config/nodes-6382.conf:/usr/local/etc/redis/redis.conf
      - ./data/master4/:/data
  redis-master5:
    image: redis:6.2.1-alpine
    container_name: redis-master5
    command: ["redis-server","/usr/local/etc/redis/redis.conf"]
    ports:
      - 6383:6379
      - 16383:16379
    volumes:
      # echo 'Asia/Shanghai' > /etc/timezone/timezone
      - /etc/timezone/timezone:/etc/timezone
      - /etc/localtime:/etc/localtime
      - ./config/nodes-6383.conf:/usr/local/etc/redis/redis.conf
      - ./data/master5/:/data
  redis-master6:
    image: redis:6.2.1-alpine
    container_name: redis-master6
    command: ["redis-server","/usr/local/etc/redis/redis.conf"]
    ports:
      - 6384:6379
      - 16384:16379
    volumes:
      # echo 'Asia/Shanghai' > /etc/timezone/timezone
      - /etc/timezone/timezone:/etc/timezone
      - /etc/localtime:/etc/localtime
      - ./config/nodes-6384.conf:/usr/local/etc/redis/redis.conf
      - ./data/master6/:/data

准备 6 份 redis 配置

nodes-6379.conf

bind 0.0.0.0
#关闭保护模式
protected-mode no
# 绑定自定义端口
port 6379
# 禁止redis后台运行
# daemonize yes
pidfile /var/run/redis_6379.pid
# 开启集群 把注释#去掉
cluster-enabled yes
# 集群的配置 配置文件首次启动自动生成
cluster-config-file nodes_6379.conf
# 开启aof
appendonly yes
# 要宣布的IP地址。nat模式要指定宿主机IP
cluster-announce-ip 192.168.2.166
# 要宣布的数据端口。
cluster-announce-port 6379
# 要宣布的集群总线端口
cluster-announce-bus-port 16379
# 密码
requirepass root

其他的 redis-${port}.conf 就修改如下部分的端口号就行了

cluster-config-file nodes_6379.conf
cluster-announce-port 6379
cluster-announce-bus-port 16379
# 运行容器
docker-compose -f redis-cluster.yml up -d
# 随便进去一个容器内部
docker exec -it redis-master1 /bin/sh
# 执行如下命令(写好每个容器的ip+端口,--cluster-replicas 1 是每一个master的备份数量;-a 指令来指定密码)
redis-cli -a root --cluster create 192.168.2.166:6379 192.168.2.166:6380 192.168.2.166:6381 192.168.2.166:6382 192.168.2.166:6383 192.168.2.166:6384 --cluster-replicas 1

image.png

依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<version>2.3.3.RELEASE</version>
</dependency>

连接配置

spring:
  ### redis
  redis:
    database: 0
    ## 集群
    cluster:
      nodes: 192.168.2.166:6379,192.168.2.166:6380,192.168.2.166:6381,192.168.2.166:6382,192.168.2.166:6383,192.168.2.166:6384
      max-redirects: 6
    password: root
    timeout: 5000
    jedis:
      pool:
        # 最大连接数
        max-active: 2000
        # 最大阻塞等待时间(负数表示没限制)
        max-wait: 1000
        # 最大空闲
        max-idle: 300
        # 最小空闲
        min-idle: 60
    client-name: demo-client

RedisTemplateConfig.java

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 lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * Redis config
 *
 * @author x
 * @version 1.0.0
 * @date 2020/4/13 23:30
 **/
@EnableCaching
@Configuration
@AutoConfigureBefore(RedisAutoConfiguration.class)
@RequiredArgsConstructor
@ComponentScan(basePackages = {
        "com.base.redis.utils"
})
public class RedisTemplateConfig {

//    private final RedisConnectionFactory factory;

    @Value("${spring.redis.cluster.nodes}")
    private String nodes;
    @Value("${spring.redis.cluster.max-redirects}")
    private Integer maxRedirects;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.database}")
    private Integer database;

    @Value("${spring.redis.jedis.pool.max-active}")
    private Integer maxActive;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private Integer maxIdle;
    @Value("${spring.redis.jedis.pool.max-wait}")
    private Long maxWait;
    @Value("${spring.redis.jedis.pool.min-idle}")
    private Integer minIdle;
    
    @Bean
    public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPool, RedisClusterConfiguration jedisConfig) {
        JedisConnectionFactory factory = new JedisConnectionFactory(jedisConfig, jedisPool);
        factory.afterPropertiesSet();
        return factory;
    }

    @Bean
    public JedisPoolConfig jedisPool() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWait);
        jedisPoolConfig.setMaxTotal(maxActive);
        jedisPoolConfig.setMinIdle(minIdle);
        return jedisPoolConfig;
    }

    /**
     * 这个配置项默认时单机配置(RedisStandaloneConfiguration),需要用一下配置进行覆盖,否则无法读取数据
     */
    @Bean
    public RedisClusterConfiguration jedisConfig() {
        RedisClusterConfiguration config = new RedisClusterConfiguration();

        String[] sub = nodes.split(",");
        List<RedisNode> nodeList = new ArrayList<>(sub.length);
        String[] tmp;
        for (String s : sub) {
            tmp = s.split(":");
            // fixme 先不考虑异常配置的case
            nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
        }

        config.setClusterNodes(nodeList);
        config.setMaxRedirects(maxRedirects);
        config.setPassword(RedisPassword.of(password));
        return config;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用 Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    250 引用 • 244 回帖 • 568 关注

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...