docker 部署 redis 的三种集群模式
master+slave(主从)
主从模式介绍
主从模式:是三种集群方式里最简单的。它主要是基于Redis的主从复制特性架构的。通常我们会设置一个主节点,N个从节点;默认情况下,主节点负责处理使用者的IO操作,而从节点则会对主节点的数据进行备份,并且也会对外提供读操作的处理。主要的特点如下:
- 主从模式下,当某一节点损坏时,因为其会将数据备份到其它Redis实例上,这样做在很大程度上可以恢复丢失的数据。
- 主从模式下,可以保证负载均衡,这里不再叙说了
- 主从模式下,主节点和从节点是读写分离的。使用者不仅可以从主节点上读取数据,还可以很方便的从从节点上读取到数据,这在一定程度上缓解了主机的压力。
- 从节点也是能够支持写入数据的,只不过从从节点写入的数据不会同步到主节点以及其它的从节点下。
从以上,我们不难看出Redis在主从模式下,必须保证主节点不会宕机。一旦主节点宕机,其它节点不会竞争称为主节点,此时,Redis将丧失写的能力。这点在生产环境中,是致命的。
主从快速部署
镜像使用: https://hub.docker.com/r/bitnami/redis
github地址: https://github.com/bitnami/bitnami-docker-redis
docker-compose 安装 就不讲了,不太懂的按照文章进行安装: https://blog.csdn.net/weixin_45444133/article/details/110588884
编写docker-compose.yaml
version: '3'
services:
#reids-master
redis-master:
user: root
container_name: redis-master
image: docker.io/bitnami/redis:6.2
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=masterpassword123
ports:
- '6379:6379'
volumes:
- ./redis/r1:/bitnami
networks:
- redis-cluster-network
#reids-slave1
redis-slave1:
user: root
container_name: redis-slave1
image: docker.io/bitnami/redis:6.2
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_PASSWORD=masterpassword123
- REDIS_MASTER_PASSWORD=masterpassword123
depends_on:
- redis-master
volumes:
- ./redis/r2:/bitnami
networks:
- redis-cluster-network
#reids-slave2
redis-slave2:
user: root
container_name: redis-slave2
image: docker.io/bitnami/redis:6.2
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_PASSWORD=masterpassword123
- REDIS_MASTER_PASSWORD=masterpassword123
depends_on:
- redis-master
volumes:
- ./redis/r3:/bitnami
networks:
- redis-cluster-network
networks:
redis-cluster-network:
driver: bridge
ipam:
config:
- subnet: 192.168.88.0/24
启动&验证
docker-compose up -d
#进入容器进行验证
docker exec -it redis-master /bin/bash
#容器内部
redis-cli -a masterpassword123
#登录获取下面的信息验证主从
127.0.0.1:6379> info
...
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.88.3,port=6379,state=online,offset=28,lag=1
slave1:ip=192.168.88.4,port=6379,state=online,offset=28,lag=1
...
主从到此部署完毕
sentinel(哨兵)
哨兵模式介绍
哨兵模式:是基于主从模式做的一定变化,它能够为Redis提供了高可用性。在实际生产中,服务器难免不会遇到一些突发状况:服务器宕机,停电,硬件损坏等。这些情况一旦发生,其后果往往是不可估量的。而哨兵模式在一定程度上能够帮我们规避掉这些意外导致的灾难性后果。其实,哨兵模式的核心还是主从复制。只不过相对于主从模式在主节点宕机导致不可写的情况下,多了一个竞选机制——从所有的从节点竞选出新的主节点。竞选机制的实现,是依赖于在系统中启动一个sentinel进程。
sentinel特点:
- 监控:它会监听主服务器和从服务器之间是否在正常工作。
- 通知:它能够通过API告诉系统管理员或者程序,集群中某个实例出了问题。
- 故障转移:它在主节点出了问题的情况下,会在所有的从节点中竞选出一个节点,并将其作为新的主节点。
- 提供主服务器地址:它还能够向使用者提供当前主节点的地址。这在故障转移后,使用者不用做任何修改就可以知道当前主节点地址。
sentinel,也可以集群,部署多个哨兵,sentinel可以通过发布与订阅来自动发现Redis集群上的其它sentinel。sentinel在发现其它sentinel进程后,会将其放入一个列表中,这个列表存储了所有已被发现的sentinel。
集群中的所有sentinel不会并发着去对同一个主节点进行故障转移。故障转移只会从第一个sentinel开始,当第一个故障转移失败后,才会尝试下一个。当选择一个从节点作为新的主节点后,故障转移即成功了(而不会等到所有的从节点配置了新的主节点后)。这过程中,如果重启了旧的主节点,那么就会出现无主节点的情况,这种情况下,只能重启集群。
当竞选出新的主节点后,被选为新的主节点的从节点的配置信息会被sentinel改写为旧的主节点的配置信息。完成改写后,再将新主节点的配置广播给所有的从节点。
哨兵快速部署
镜像使用: https://hub.docker.com/r/bitnami/redis-sentinel
github地址: https://github.com/bitnami/bitnami-docker-redis-sentinel
编写docker-compose.yml
哨兵就是在主从的基础上增加了 sentinel 服务 来监控redis 的master 状态
参数可以去github 上面查看,官方写的还是非常详细的
version: '3'
services:
#reids-master
redis-master:
user: root
container_name: redis-master
image: docker.io/bitnami/redis:6.2
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=masterpassword123
ports:
- '6379:6379'
volumes:
- ./redis/r1:/bitnami
networks:
- redis-cluster-network
#reids-slave1
redis-slave1:
user: root
container_name: redis-slave1
image: docker.io/bitnami/redis:6.2
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_PASSWORD=masterpassword123
- REDIS_MASTER_PASSWORD=masterpassword123
depends_on:
- redis-master
volumes:
- ./redis/r2:/bitnami
networks:
- redis-cluster-network
#reids-slave2
redis-slave2:
user: root
container_name: redis-slave2
image: docker.io/bitnami/redis:6.2
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_PASSWORD=masterpassword123
- REDIS_MASTER_PASSWORD=masterpassword123
depends_on:
- redis-master
volumes:
- ./redis/r3:/bitnami
networks:
- redis-cluster-network
#redisn-哨兵
redis-sentinel:
image: 'bitnami/redis-sentinel:6.2'
environment:
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PASSWORD=masterpassword123
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
- redis-cluster-network
networks:
redis-cluster-network:
driver: bridge
ipam:
config:
- subnet: 192.168.88.0/24
启动&验证
#sentinel镜像默认是2个哨兵同意才进行主从切换,所有这里启动三个sentinel
docker-compose up --scale redis-sentinel=3 -d
为了方便以后启动更新,这里写个脚本
#! /bin/bash
main(){
case $1 in
start)
# 镜像默认是2个哨兵同意才进行主从切换,所有这里启动三个sentinel
docker-compose up --scale redis-sentinel=3 -d
;;
update)
docker-compose up --scale redis-sentinel=3 -d
;;
stop)
docker-compose down
;;
*)
echo "start | stop | update"
;;
esac
}
main $1
添加执行权限
chmod +x start.sh
#测试一下
./start.sh update
这里就不展示验证过程了,操作过程很简单,这里就简单描述一下:
- 进入redis-master 查看它是否是 主,并查看有几个从redis
- 进入 sentinel 服务容器, Redis-cli -p 26379 后执行 info 应该要看到显示有三个sentinel : master0:name=mymaster,status=ok,address=192.168.88.2:6379,slaves=2,sentinels=3
- 停止redis-master 服务 ,docker-compose logs -f --tail=200 查看监控和切换的日志输出
- 切换完毕后,进入切换的容器,执行验证当前服务是否是redis 的主,是的话,哨兵模式成功
cluster(集群)
cluster集群模式介绍
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。
Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.
Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:
- 自动分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
Redis Cluster 数据分片
Redis Cluster 不使用一致散列,而是一种不同形式的分片,其中每个键在概念上都是我们所谓的散列槽的一部分。
Redis 集群中有 16384 个哈希槽,要计算给定键的哈希槽是多少,我们只需取密钥的 CRC16 模数 16384。
Redis 集群中的每个节点都负责哈希槽的一个子集,例如,您可能有一个包含 3 个节点的集群,其中:
- 节点 A 包含从 0 到 5500 的哈希槽。
- 节点 B 包含从 5501 到 11000 的哈希槽。
- 节点 C 包含从 11001 到 16383 的哈希槽。
这允许在集群中轻松添加和删除节点。例如,如果我想添加一个新节点 D,我需要将一些哈希槽从节点 A、B、C 移动到 D。同样,如果我想从集群中删除节点 A,我可以移动 A 提供的哈希槽到 B 和 C。当节点 A 为空时,我可以将其从集群中完全删除。
由于将哈希槽从一个节点移动到另一个节点不需要停止操作,因此添加和删除节点或更改节点持有的哈希槽百分比不需要任何停机时间。
Redis Cluster 支持多键操作,只要涉及到单个命令执行(或整个事务,或 Lua 脚本执行)的所有键都属于同一个哈希槽。用户可以使用称为散列标签的概念强制多个键成为同一个散列槽的一部分。
Redis Cluster 规范中记录了哈希标签,但要点是如果键中的 {} 括号之间有一个子字符串,则只有字符串内的内容会被哈希,因此例如this{foo}key
和another{foo}key
保证在同一个哈希槽中, 并且可以在具有多个键作为参数的命令中一起使用。
Redis Cluster 主从模式
为了在主节点子集出现故障或无法与大多数节点通信时保持可用,Redis 集群使用主从模型,其中每个哈希槽具有从 1(主节点本身)到 N 个副本(N -1 个额外的从节点)。
在我们包含节点 A、B、C 的示例集群中,如果节点 B 发生故障,集群将无法继续,因为我们不再有办法为 5501-11000 范围内的哈希槽提供服务。
然而,当集群创建时(或稍后),我们为每个主节点添加一个从节点,这样最终的集群由主节点 A、B、C 和从节点 A1、B1、C1 组成. 这样,如果节点 B 出现故障,系统就能够继续运行。
节点 B1 复制 B,并且 B 失败,集群会将节点 B1 提升为新的 master 并继续正常运行。
但是需要注意的是,如果节点 B 和 B1 同时发生故障,Redis Cluster 将无法继续运行。
Redis 集群一致性保证
Redis Cluster 无法保证强一致性。实际上,这意味着在某些情况下,Redis Cluster 可能会丢失系统已向客户端确认的写入。
Redis Cluster 会丢失写入的第一个原因是因为它使用异步复制。这意味着在写入期间会发生以下情况:
- 您的客户端写入主 B。
- 主 B 向您的客户端回复 OK。
- 主设备 B 将写入传播到其从设备 B1、B2 和 B3。
如您所见,B 在回复客户端之前不会等待来自 B1、B2、B3 的确认,因为这对 Redis 来说是一个令人望而却步的延迟惩罚,因此如果您的客户端写入某些内容,B 会确认写入,但会在此之前崩溃能够将写入发送到其从站,其中一个从站(未收到写入)可以提升为主站,永远失去写入。
这与大多数配置为每秒将数据刷新到磁盘的数据库发生的情况非常相似,因此您已经能够推理出这种情况,因为过去使用不涉及分布式系统的传统数据库系统的经验。同样,您可以通过强制数据库在回复客户端之前将数据刷新到磁盘来提高一致性,但这通常会导致性能低得令人望而却步。在 Redis Cluster 的情况下,这相当于同步复制。
基本上,需要在性能和一致性之间进行权衡。
Redis 集群在绝对需要时支持同步写入,通过WAIT命令实现。这使得丢失写入的可能性大大降低。但是请注意,即使使用同步复制,Redis Cluster 也没有实现强一致性:在更复杂的故障场景下,始终有可能将无法接收写入的从站选为主站。
还有一个值得注意的场景,Redis 集群会丢失写入,这发生在网络分区期间,客户端与少数实例(至少包括一个主实例)隔离。
以我们的6个节点集群为例,由A、B、C、A1、B1、C1组成,有3个master和3个slave。还有一个客户端,我们将其称为 Z1。
分区发生后,可能在分区的一侧有 A、C、A1、B1、C1,而在另一侧有 B 和 Z1。
Z1 仍然能够写入 B,B 将接受其写入。如果分区在很短的时间内恢复,集群将继续正常运行。但是,如果分区持续足够的时间让 B1 在分区的多数侧提升为主节点,则 Z1 同时发送给 B 的写入将丢失。
请注意,Z1 能够发送到 B 的写入量有一个最大窗口:如果分区的多数侧已经有足够的时间来选举一个从属作为主,那么少数侧的每个主节点都将停止接受写入。
这个时间量是 Redis Cluster 的一个非常重要的配置指令,称为节点超时。
节点超时后,主节点被视为发生故障,并且可以由其副本之一替换。类似地,在节点超时后,主节点无法感知大多数其他主节点,它会进入错误状态并停止接受写入。
cluster 模式介绍部署参考官方文档: https://redis.io/topics/cluster-tutorial
集群快速部署
镜像使用: https://hub.docker.com/r/bitnami/redis-cluster
github地址: https://github.com/bitnami/bitnami-docker-redis-cluster
编写docker-compose.yml
cluster 模式通过数据分片的方式来进行数据共享问题,同时提供数据复制和故障转移功能。
参数可以去github 上面查看,官方写的还是非常详细的
version: '3'
services:
redis-node-0:
user: root
container_name: redis-node-0
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16379:6379
volumes:
- ./redis_data-0:/bitnami/redis/data
environment:
- 'REDIS_PASSWORD=bitnami'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.2
redis-node-1:
user: root
container_name: redis-node-1
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16380:6379
volumes:
- ./redis_data-1:/bitnami/redis/data
environment:
- 'REDIS_PASSWORD=bitnami'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.3
redis-node-2:
user: root
container_name: redis-node-2
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16381:6379
volumes:
- ./redis_data-2:/bitnami/redis/data
environment:
- 'REDIS_PASSWORD=bitnami'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.4
redis-node-3:
user: root
container_name: redis-node-3
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16382:6379
volumes:
- ./redis_data-3:/bitnami/redis/data
environment:
- 'REDIS_PASSWORD=bitnami'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.5
redis-node-4:
user: root
container_name: redis-node-4
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16383:6379
volumes:
- ./redis_data-4:/bitnami/redis/data
environment:
- 'REDIS_PASSWORD=bitnami'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.6
redis-node-5:
user: root
container_name: redis-node-5
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16384:6379
volumes:
- ./redis_data-5:/bitnami/redis/data
depends_on:
- redis-node-0
- redis-node-1
- redis-node-2
- redis-node-3
- redis-node-4
environment:
- 'REDIS_PASSWORD=bitnami'
- 'REDISCLI_AUTH=bitnami'
- 'REDIS_CLUSTER_REPLICAS=1'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
- 'REDIS_CLUSTER_CREATOR=yes'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.7
networks:
redis-cluster-network:
driver: bridge
ipam:
config:
- subnet: 192.168.88.0/24
启动&验证
#启动
docker-compose up -d
过程就不完全展示了,贴几张关键的图
cluster 集群常用命令参考: https://www.cnblogs.com/kevingrace/p/7910692.html
可以看到集群已经选取了新的master,其余节点都验证集群通信完好
容器执行 cluster nodes 可以看到 集群将之前master 的slave服务器,升级为新的master
恢复之前停止的master服务器,再次查看可以看到它没有直接顶替成为master,而是成为了master 下的一个 slave 服务器
并向master 发送请求进行同步数据
以上三种redis 集群模式,到此部署完毕。
记录工作中使用到技术部署。