Redis是一个内存数据库,支持多样类型的数据存储和查询,而且采用了高效的算法把数据压缩到最小。一般测试环境,搭建一个Redis实例就可以满足需求,但是生产环境中,单个Redis实例一旦挂掉之后,就不能提供内存存储服务,所以需要部署多个实例来提高容错性,挂掉一个或多个也能正常提供服务,实现724无间断服务。那么多个Redis实例该怎样部署配合才能满足需求呢?
既然有多个实例,就应该有主有次,不然还不乱套了,所以应该选择一个实例作为主服务器,其他作为从服务器和主服务器同步,这样数据就有多个副本了。
主服务器的配置中,需要注意的有下面几个:
//为了能让其他容器访问,配置为接收所有网络接口的连接
bind 0.0.0.0
//明确自身身份
replica-announce-ip masterA
编写redis-master.yml文件
version: "3.7"
networks:
xxl:
external: true
services:
masterA:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/masterA.conf:/etc/redis/redis.conf:ro
- ./redis/masterA:/data:rw
command: ["redis-server", "/etc/redis/redis.conf"]
deploy:
replicas: 1
使用swarm部署:
//部署服务栈
docker stack deploy -c docker-master.yml m
//移除服务栈
docker stack rm m
至此,一个主服务器就部署好了。如果swarm集群中部署了portainer的话,可以在portainer中看到实例。
进入到容器中,添加一个键值对:
首先也是修改配置文件,有三个文件需要修改,需要注意的有:
//其他容器也可以访问
bind 0.0.0.0
//明确身份
replica-announce-ip replicaA1 //A1实例
replica-announce-ip replicaA2 //A2实例
replica-announce-ip replicaA3 //A3实例
//指定是谁的从服务器
replicaof masterA 6379
接着,编写从服务器的部署文件redis-replica.yml
version: "3.7"
networks:
xxl:
external: true
volumes: //由于windows系统复制数据会有问题,所以使用命名卷。
replicaA1:
external: true
replicaA2:
external: true
replicaA3:
external: true
services:
replicaA1:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/replicaA1.conf:/etc/redis/redis.conf:ro
- replicaA1:/data:rw
command: ["redis-server", "/etc/redis/redis.conf"]
deploy:
replicas: 1
replicaA2:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/replicaA2.conf:/etc/redis/redis.conf:ro
- replicaA2:/data:rw
command: ["redis-server", "/etc/redis/redis.conf"]
deploy:
replicas: 1
replicaA3:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/replicaA3.conf:/etc/redis/redis.conf:ro
- replicaA3:/data:rw
command: ["redis-server", "/etc/redis/redis.conf"]
deploy:
replicas: 1
同样,也用docker部署到swarm中:
//部署服务栈
docker stack deploy -c docker-replica.yml r
//移除服务栈
docker stack rm r
查看portainer,发现多了三个从服务器:
查看任一从服务器容器的log,可以看到从服务器已经连上主服务器并且进行了数据同步。
进入容器中,访问键“/”,得到期望的“better”。
主服务器提供一般提供写入服务,而从服务器提供只读服务。
默认情况下,从服务器和主服务器断开连接后,从服务器会自动重连主服务器,并且进行数据同步。由于同步数据的过程是异步的,数据量较大时,会有短暂的时间窗口出现不同步的情况;但是无论怎么样,从服务器都尽最大的努力,保证和主服务器的数据一致。
如果说,从服务器挂了一个,对系统影响不大,还有其他的从服务器提供只读服务。但是如果主服务器挂了一个呢,整个系统将无法接收新的写入命令。如果此时不手动重启主服务器的话,系统将无法提供正常的服务。但是,作为开发人员,不可能724守着服务器,那么有没有一种方法当主服务器挂掉之后,主服务器能够自动重启呢?
答案是肯定的。docker swarm部署的服务,在挂掉的情况下,会自动重启。
那么如果不是使用docker swarm部署的服务呢?主服务器挂了之后,如果有一个从服务器变为主服务器,提供写入操作就好了。事实上,确实有这样的方案。Redis哨兵就是干这个事的。
启动哨兵一般有两种方式:
本文采用第二种方式部署。
首先修改配置文件,完整的选项列表参考sentinel.conf,最少需要下面四个选项:
sentinel monitor masterA masterA 6379 2 //名为 masterA 的主服务器, 这个主服务器的 IP 地址为 masterA , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意
sentinel down-after-milliseconds masterA 60000 //Sentinel 认为服务器已经断线所需的毫秒数
sentinel failover-timeout masterA 30000 //故障转移超时时间
sentinel parallel-syncs masterA 1 //每次同时同步的从服务器个数
准备三个这样的文件:
接着,编写sentinelA.yml部署文件:
version: "3.7"
networks:
xxl:
external: true
volumes: //由于windows系统复制数据会有问题,所以使用命名卷。
sentinelA1:
external: true
sentinelA2:
external: true
sentinelA3:
external: true
services:
sentinelA1:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/sentinelA1.conf:/etc/redis/redis.conf:rw
- sentinelA1:/tmp:rw
command: ["redis-server", "/etc/redis/redis.conf", "--sentinel"]
deploy:
replicas: 1
sentinelA2:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/sentinelA2.conf:/etc/redis/redis.conf:rw
- sentinelA2:/tmp:rw
command: ["redis-server", "/etc/redis/redis.conf", "--sentinel"]
deploy:
replicas: 1
sentinelA3:
image: redis:latest
networks:
- xxl
volumes:
- ./redis/sentinelA3.conf:/etc/redis/redis.conf:rw
- sentinelA3:/tmp:rw
command: ["redis-server", "/etc/redis/redis.conf", "--sentinel"]
deploy:
replicas: 1
使用swarm部署哨兵:
//部署服务栈
docker stack deploy -c docker-sentinel.yml s
//移除服务栈
docker stack rm s
查看portainer,多了三个哨兵服务:
查看任一个哨兵的日志如下:
可以看出,每个哨兵都有独立的ID,并且知道了主服务器的信息,三个从服务器的信息和另外两个哨兵的信息。
到这里,一个主服务器+三个从服务器+三个哨兵的Redis服务器系统就建好了。
为了验证主服务器挂掉之后,在哨兵的管理下能否成功进行故障转移,现在把主服务器的服务移除:
docker stack rm m
观察任一哨兵服务的日志,可以发现:哨兵观察到了主服务器的下线,选举了一个从服务器转变为新的主服务器,并把其他的从服务器连接到新的主服务器上。
最后,使用role查看每个从服务器的身份,一个master,两个slave。查看键“/”的值,依然是“better”。说明哨兵起到了在主服务器挂掉之后,自动故障迁移到其中一台从服务器上的作用。