Docker搭建Redis分布式集群
需求:
- 搭建单机版的redis服务,在应对高并发、稳定性等需求难以胜任。而本次由于项目数据量大,要求稳定性强,能应对高可用,高并发等情况。故搭建redis分布式集群很有必要。考虑到不对物理机造成任何影响,方便管理,本次搭建选择在docker里搭建。
简介
redis分布式集群,由于已经集成了redis哨兵,故具有:
监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。
从而提高了redis服务的稳定性,高可用性等。
工具
- redis镜像
- Docker Compose
图解

- 本次搭建是在两台服务器上,最终集群是三主三从,当使用python客户端连接集群后,数据是通过CRC16算法,之后得到结果,将结果与分配的哈希槽值对比,如果在某一个哈希槽范围内,则将该条数据写入到对应的Master上,同时对应的Slave自动备份;当其中一个Master宕机,在指定的时间内没有恢复,则对应的Slave经过哨兵中自动故障迁移(Automatic failover)功能,提升为Master。之后宕机的服务器恢复后自动降级为Slave。
安装
Docker Compose (可以一条命令启动或删除集群)
# 简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。 # 安装(Linux系统) # 常规安装: 1、下载安装包 sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 2、更改权限 sudo chmod +x /usr/local/bin/docker-compose 3、创建软链接 sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose 4、测试 docker-compose --version # 本次在Linux中下载安装包时,发现慢,掉包严重,下载失败。而直接执行docker-compose时会提示apt install docker-compose。这条命令提示简单,但是安装后发现无法运行YML文件
可以看到,通过
apt install docker-compose安装的docker-compose运行命令docker-compose up -d报错。# 解决 https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Linux-x86_64 复制该url到浏览器中下载二进制文件包,并且重命名为docker-compose(也可以不重命名),将文件上传到Linux服务端中。 # 修改权限 chome +x docker-compose # 复制-->此时任何目录下都可以执行docker-compose命令 cp docker-compose /usr/bin/ # 启动命令(在YML文件目录下执行) docker-compose up -d //-d参数指的是后台启动 # 删除集群 docker-compose down
Redis Cluster配置文件
# 分别在两台服务器上执行以下操作 # 创建目录 mkdir -p /home/redis/redis-cluster/ # 编写redis-cluster.tmpl文件 cd /home/redis/redis-cluster/ vim redis-cluster.tmplredis_cluster.tmpl文件内容如下:# 第一台服务器(192.168.112.133) port ${PORT} requirepass 1234agrass masterauth 1234agrass protected-mode no daemonize no appendonly no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 cluster-announce-ip 192.168.112.133 cluster-announce-port ${PORT} cluster-announce-bus-port 1${PORT} # 第二台服务器(192.168.112.134) port ${PORT} requirepass 1234agrass masterauth 1234agrass protected-mode no daemonize no appendonly no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 cluster-announce-ip 192.168.112.134 cluster-announce-port ${PORT} cluster-announce-bus-port 1${PORT} # 参数说明: port:节点端口; requirepass:添加访问认证; masterauth:如果主节点开启了访问认证,从节点访问主节点需要认证; protected-mode:保护模式,默认值 yes,即开启。开启保护模式以后,需配置 bind ip 或者设置访问密码;关闭保护模式,外部网络可以直接访问; daemonize:是否以守护线程的方式启动(后台启动),默认 no; appendonly:是否开启 AOF 持久化模式,默认 no; cluster-enabled:是否开启集群模式,默认 no; cluster-config-file:集群节点信息文件; cluster-node-timeout:集群节点连接超时时间; cluster-announce-ip:集群节点 IP,填写宿主机的 IP; cluster-announce-port:集群节点映射端口; cluster-announce-bus-port:集群节点总线端口。注意:
每个 Redis 集群节点都需要打开两个 TCP 连接。一个用于为客户端提供服务的正常 Redis TCP 端口,例如 6379。还有一个基于 6379 端口加 10000 的端口,比如 16379。
第二个端口用于集群总线,这是一个使用二进制协议的节点到节点通信通道。节点使用集群总线进行故障检测、配置更新、故障转移授权等等。客户端永远不要尝试与集群总线端口通信,与正常的 Redis 命令端口通信即可,但是请确保防火墙中的这两个端口都已经打开,否则 Redis 集群节点将无法通信

在当前目录下执行以下命令
# 第一台服务器(192.168.112.133) for port in `seq 6371 6373`; do \ mkdir -p ${port}/conf \ && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf \ && mkdir -p ${port}/data;\ done # 第二台服务器(192.168.112.134) for port in `seq 6374 6376`; do \ mkdir -p ${port}/conf \ && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf \ && mkdir -p ${port}/data;\ done
编写Docker Compose模板文件
# 切换目录 cd /home/redis # 编写docker-compose.yml文件 vim docker-compose.ymldocker-compose.yml文件内容:
第一台服务器添加以下信息: # 描述 Compose 文件的版本信息 version: "3.8" # 定义服务,可以多个 services: redis-6371: # 服务名称 image: redis # 创建容器时所需的镜像 container_name: redis-6371 # 容器名称 restart: always # 容器总是重新启动 network_mode: "host" # host 网络模式 volumes: # 数据卷,目录挂载 - /home/redis/redis-cluster/6371/conf/redis.conf:/usr/local/etc/redis/redis.conf - /home/redis/redis-cluster/6371/data:/data command: redis-server /usr/local/etc/redis/redis.conf # 覆盖容器启动后默认执行的命令 redis-6372: image: redis container_name: redis-6372 network_mode: "host" volumes: - /home/redis/redis-cluster/6372/conf/redis.conf:/usr/local/etc/redis/redis.conf - /home/redis/redis-cluster/6372/data:/data command: redis-server /usr/local/etc/redis/redis.conf redis-6373: image: redis container_name: redis-6373 network_mode: "host" volumes: - /home/redis/redis-cluster/6373/conf/redis.conf:/usr/local/etc/redis/redis.conf - /home/redis/redis-cluster/6373/data:/data command: redis-server /usr/local/etc/redis/redis.conf第二台服务器添加以下信息: # 描述 Compose 文件的版本信息 version: "3.8" # 定义服务,可以多个 services: redis-6374: # 服务名称 image: redis # 创建容器时所需的镜像 container_name: redis-6374 # 容器名称 restart: always # 容器总是重新启动 network_mode: "host" # host 网络模式 volumes: # 数据卷,目录挂载 - /home/redis/redis-cluster/6374/conf/redis.conf:/usr/local/etc/redis/redis.conf - /home/redis/redis-cluster/6374/data:/data command: redis-server /usr/local/etc/redis/redis.conf # 覆盖容器启动后默认执行的命令 redis-6375: image: redis container_name: redis-6375 network_mode: "host" volumes: - /home/redis/redis-cluster/6375/conf/redis.conf:/usr/local/etc/redis/redis.conf - /home/redis/redis-cluster/6375/data:/data command: redis-server /usr/local/etc/redis/redis.conf redis-6376: image: redis container_name: redis-6376 network_mode: "host" volumes: - /home/redis/redis-cluster/6376/conf/redis.conf:/usr/local/etc/redis/redis.conf - /home/redis/redis-cluster/6376/data:/data command: redis-server /usr/local/etc/redis/redis.conf启动Redis Cluster
# 进入到docker-compose.yml文件目录下,并执行 docker-compose up -d # 说明: 启动redis容器中的网络模式设置为host,此时redis容器与宿主机是同一个网络,解决主从链接问题

创建Redis Cluster
# 进入其中一台容器中 docker exec -it redis-6371 bash # 切换至指定目录 cd /usr/local/bin/ # redis cluster 主从链接(-a 1234agrass 认证密码) redis-cli -a 1234agrass --cluster create \ 192.168.112.133:6371 \ 192.168.112.133:6372 \ 192.168.112.133:6373 \ 192.168.112.134:6374 \ 192.168.112.134:6375 \ 192.168.112.134:6376 --cluster-replicas 1
以下信息表示成功

# 链接集群 1、进入到docker容器中链接 (-c 参数表示集群) docker exec -it redis-6371 /usr/local/bin/redis-cli -c -a 1234agrass -h 192.168.112.134 -p 6375 2、在windows中链接 redis-cli -c -h 192.168.112.133 -p 6371 > auth 1234agrass # 查看主从 > info replication # 查看集群节点信息 > cluster nodes
python链接示例
# 安装依赖包(此时会安装redis和redis-py-cluster) pip install redis-py-cluster # 链接示例 from rediscluster import RedisCluster def redis_cluster(startup_nodes: list): """链接redis_cluster""" return RedisCluster(startup_nodes=startup_nodes, password='1234agrass', decode_responses=True) def redis_handle(redis_obj): """redis_cluster操作""" result = redis_obj.set('world', 'helloredis') print(result) res = redis_obj.get('world') print(res) if __name__ == '__main__': startup_nodes = [ {"host": "192.168.112.133", "port": "6371"}, {"host": "192.168.112.133", "port": "6372"}, {"host": "192.168.112.133", "port": "6373"} ] try: redis_obj = redis_cluster(startup_nodes=startup_nodes) redis_handle(redis_obj=redis_obj) except Exception as e: print(e)总结
此次搭建使用了
redis-cluster.tmpl文件快速建立了要配置的文件和目录,运用docker compose工具快速启动和删除集群,redis分布式集群的优点:可以将数据分散到不同的服务器上存储,提高了高并发性能,缓解一台服务器的压力,集成redis哨兵机制,使得集群更加的高可用,但是由于是分布式,故redis事务不可用,redis批量操作也不可用(mset、hmset等)。由于redis本身在内存中操作数据,故速度非常快,因此redis cluster中的Slave作用仅仅是备份和故障升级为Master。不用像Mysql做读写分离。经测试,当两台服务都重启后,分别打开redis集群容器,此时集群会自动链接,之后重新组成三主三从,并且在前面配置中redis容器中的快照文件已经做了目录映射,保证了容器删除再启动,数据依然存在,本次考虑到作AOF持久化没必要。

文献
https://my.oschina.net/u/4126211/blog/4555576 https://juejin.cn/post/6868814738751488008 https://www.runoob.com/docker/docker-compose.html