Docker Compose——搭建Redis集群

Posted Starzkg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker Compose——搭建Redis集群相关的知识,希望对你有一定的参考价值。

环境配置

Docker 18.x
Docker-Compose 3.7
Redis 6.2.5

主从(Master-Slave)模式

主从复制模式中包含一个主数据库实例(master)与一个或多个从数据库实例(slave),如下图

客户端可对主数据库进行读写操作,对从数据库进行读操作,主数据库写入的数据会实时自动同步给从数据库。

主从模式的具体工作机制

  1. slave启动后,向master发送SYNC命令,master接收到SYNC命令后通过bgsave保存快照(即上文所介绍的RDB持久化),并使用缓冲区记录保存快照这段时间内执行的写命令
  2. master将保存的快照文件发送给slave,并继续记录执行的写命令
  3. slave接收到快照文件后,加载快照文件,载入数据
  4. master快照发送完后开始向slave发送缓冲区的写命令,slave接收命令并执行,完成复制初始化
  5. 此后master每次执行一个写命令都会同步发送给slave,保持master与slave之间数据的一致性

主从模式的特点

  • 主服务器负责接收写请求
  • 从服务器负责接收读请求
  • 从服务器的数据由主服务器复制过去。主从服务器的数据是一致的

主从模式的优点

  • 读写分离(主服务器负责写,从服务器负责读)
  • 高可用(某一台从服务器挂了,其他从服务器还能继续接收请求,不影响服务)
  • 处理更多的并发量(每台从服务器都可以接收读请求,读QPS就上去了)

主从模式的缺点

  • 不具备自动容错与恢复功能,master或slave的宕机都可能导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复
  • master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题
  • 难以支持在线扩容,Redis的容量受限于单机配置

主从同步

主从架构的特点之一:主服务器和从服务器的数据是一致的。
主从同步的2种情况

完整的同步

从服务器向主服务器发送PSYNC命令
收到PSYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件。并用一个缓冲区来记录从现在开始执行的所有写命令。
当主服务器的BGSAVE命令执行完后,将生成的RDB文件发送给从服务器,从服务器接收和载入RBD文件。将自己的数据库状态更新至与主服务器执行BGSAVE命令时的状态。
主服务器将所有缓冲区的写命令发送给从服务器,从服务器执行这些写命令,达到数据最终一致性。

部分重同步

主从服务器的复制偏移量 主服务器每次传播N个字节,就将自己的复制偏移量加上N
从服务器每次收到主服务器的N个字节,就将自己的复制偏移量加上N
通过对比主从复制的偏移量,就很容易知道主从服务器的数据是否处于一致性的状态!

Docker-Compose

https://gitee.com/shentuzhigang/mini-project/tree/master/docker-compose/redis-master-slave

version: "3.7"
services: 
    redis1:
        image: redis:latest
        container_name: redis1
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6376:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.81
    redis2:
        image: redis:latest
        container_name: redis2
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf --replicaof 192.168.88.81 6379"
        depends_on:
        - redis1
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6377:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.82
    redis3:
        image: redis:latest
        container_name: redis3
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf --replicaof 192.168.88.81 6379"
        depends_on:
        - redis1
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6378:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.83
networks:
    redis-cluster-net:
        external: true
        name: redis-cluster-net

哨兵 Sentinel 模式

Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:

  • 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
  • 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
  • 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

哨兵模式基于主从复制模式,只是引入了哨兵来监控与自动处理故障。如图

Docker-Compose

哨兵容器应该等待redis容器先启动,使用depends_on控制

version: "3.7"
services: 
    redis1:
        image: redis:latest
        container_name: redis1
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6376:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.81
    redis2:
        image: redis:latest
        container_name: redis2
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf --replicaof 192.168.88.81 6379"
        depends_on:
        - redis1
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6377:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.82
    redis3:
        image: redis:latest
        container_name: redis3
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf --replicaof 192.168.88.81 6379"
        depends_on:
        - redis1
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6378:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.83
    redis-sentinel1:
        image: redis:latest
        container_name: redis-sentinel1
        command: /bin/bash -c "redis-sentinel /usr/local/etc/redis/redis-sentinel.conf"
        depends_on:
        - redis1
        - redis2
        - redis3
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6373:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.84
    redis-sentinel2:
        image: redis:latest
        container_name: redis-sentinel2
        command: /bin/bash -c "redis-sentinel /usr/local/etc/redis/redis-sentinel.conf"
        depends_on:
        - redis1
        - redis2
        - redis3
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6374:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.85
    redis-sentinel3:
        image: redis:latest
        container_name: redis-sentinel3
        command: /bin/bash -c "redis-sentinel /usr/local/etc/redis/redis-sentinel.conf"
        depends_on:
        - redis1
        - redis2
        - redis3
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6375:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.86
networks:
    redis-cluster-net:
        external: true
        name: redis-cluster-net

redis-sentinel.conf

sentinel monitor mymaster 192.168.88.81 6379 2

设置哨兵监控的主服务器和odown数(sdown数累计达到odown即开启故障转移主从切换) sentinel monitor
mymaster 192.168.11.128 6379 2
x秒不回应即单sentinel判定为sdown sentinel down-after-milliseconds
单次故障转移最长时间,超过则认定为故障转移失败 sentinel failover-timeout mymaster 10000
当发生failover主备切换时最多可以有多少个slave同时对新的master同步,数字越小favilover越快.通常设为1
sentinel parallel-syncs <master-name> <numslaves>
哨兵启动后自动写入的唯一id,每个sentinel不一样,故不能用同一份配置文件 sentinel myid

Redis Cluster 集群模式

Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。

Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。

Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。

Redis 集群提供了以下两个好处:

  • 将数据自动切分(split)到多个节点的能力。
  • 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。

Docker-Compose

version: "3.7"
services: 
    redis1:
        image: redis:latest
        container_name: redis1
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6376:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.81
    redis2:
        image: redis:latest
        container_name: redis2
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6377:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.82
    redis3:
        image: redis:latest
        container_name: redis3
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6378:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.83
    redis4:
        image: redis:latest
        container_name: redis4
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6373:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.84
    redis5:
        image: redis:latest
        container_name: redis5
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6374:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.85
    redis6:
        image: redis:latest
        container_name: redis6
        command: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf"
        environment:
            REDIS_PASSWORD: 123456
        ports:
        - 6375:6379
        volumes:
        - type: bind
          source: /root/redis-cluster/redis
          target: /usr/local/etc/redis
        networks:
          redis-cluster-net:
            ipv4_address: 192.168.88.86
networks:
    redis-cluster-net:
        external: true
        name: redis-cluster-net

启动后执行命令

docker exec -it redis1 \\
redis-cli --cluster create \\
192.168.88.81:6379 \\
192.168.88.82:6379 \\
192.168.88.83:6379 \\
192.168.88.84:6379 \\
192.168.88.85:6379 \\
192.168.88.86:6379 \\
--cluster-replicas 1

Keepalived监控

通过 keepalived 的虚拟 IP,提供主从的统一访问,在主出现问题时, 通过 keepalived 运行脚本将从提升为主,待主恢复后先同步后自动变为主,该方案的好处是主从切换后,应用程序不需要知道(因为访问的虚拟 IP 不变),坏处是引入 keepalived 增加部署复杂性,在有些情况下会导致数据丢失。

Zookeeper监控

通过 zookeeper 来监控主从实例, 维护最新有效的 IP, 应用通过 zookeeper 取得 IP,对 Redis 进行访问,该方案需要编写大量的监控代码

常见问题

参考文章

以上是关于Docker Compose——搭建Redis集群的主要内容,如果未能解决你的问题,请参考以下文章

docker-compose搭建redis集群

Docker Compose——搭建Redis集群

docker-compose搭建redis哨兵集群

docker-compose搭建redis集群一主两从三哨兵

docker compose搭建redis7.0.4高可用一主二从三哨兵集群并整合SpringBoot图文完整版

docker compose搭建redis7.0.4高可用一主二从三哨兵集群并整合SpringBoot图文完整版