掘金 后端 ( ) • 2024-06-30 14:22

序言

在目前我参与开发的代码仓库中,当需要使用 Redis 时,基本上用的都是 Redis 集群。因此,我在办公电脑上也搭建了一个 Redis 集群,以便让我为这些仓库编写的单元测试能成功运行起来。

尽管 Redis 官方提供了部署集群的指引,但这要求团队内的每位成员都要依次执行如下操作:

  1. 用 Homebrew 安装 Redis;
  2. 创建 6 个目录;
  3. 创建 6 份redis.conf配置文件;
  4. 启动 6 个redis-server进程;
  5. redis-cli创建集群。

为了可以让更多的人愿意执行单元测试,必须要降低部署 Redis 集群的操作难度。因此,本文旨在提供一种基于 Docker 的、一键部署 Redis 集群的办法。

启动单个 Redis 容器

Redis 集群需要至少 6 个实例,那么首先要解决的问题便是如何启动单个 Redis 容器。从前文提到的部署集群的指引中可以知道,要启动一个集群模式的 Redis 实例,所需要的配置文件redis.conf的内容如下

port 8000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

参考官方的 redis 镜像的文档的方式,让redis-server读取来自于宿主机的配置文件,示例代码如下

# 选项 --rm 使该容器在退出后(例如按下 ctrl-c)可以被删除,毕竟这里只是先做个演示,不需要留下它。
sudo docker run --rm -v "`pwd`:/usr/local/etc/redis" redis redis-server "/usr/local/etc/redis/redis.conf"

效果如下图所示

启动单个Redis实例.png

启动 6 个 Redis 容器

接下来以相似的方式启动全部的 6 个 Redis 容器。首先创建 6 个目录

# 这里我用 Redis 监听的端口号作为目录名,但这并非强制要求。
mkdir 8000 8001 8002 8003 8004 8005

然后在每一个目录中都创建配置文件redis.conf

for port in 8000 8001 8002 8003 8004 8005 ;
do
    cat << EOF > "./${port}/redis.conf"
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
EOF
done

最后启动它们

# 创建出名为 some-network 的容器间网络。
docker network create some-network

for port in 8000 8001 8002 8003 8004 8005 ;
do
    # --name 选项让这 6 个容器拥有确定的且不同的主机名,以便之后可以在 redis-cli 中指定它们。
    # --network 选项让这 6 个容器处于同一个网络下,以便集群内的节点可以互相通信。
    docker run --name "some-redis-${port}" --network some-network --rm -d -v "`pwd`/${port}:/usr/local/etc/redis" redis redis-server '/usr/local/etc/redis/redis.conf'
done

效果如下图所示

启动6个Redis容器.png

创建集群

此时 6 个运行中的 Redis 实例还不构成一个集群,还需要执行redis-cli的命令--cluster create才行。

# 给 redis-cli 的选项 --cluster-yes 使其默认接受集群内节点的分配情况。这在脚本执行、无法通过标准输出敲入 yes 的时候很有用。
docker run --network some-network --rm -i -t redis redis-cli --cluster create some-redis-8000:8000 some-redis-8001:8001 some-redis-8002:8002 some-redis-8003:8003 some-redis-8004:8004 some-redis-8005:8005 --cluster-replicas 1 --cluster-yes

但命令--cluster create并非幂等的,只能在创建集群的时候使用一次。因此,如果希望通过脚本一键搭建、启动集群,则必须在创建前先检查集群是否曾经被创建过。借助redis-cli的命令--cluster check可以实现

docker run --network some-network --rm -i -t redis redis-cli --cluster check some-redis-8000:8000 | grep 'All 16384 slots covered.' > /dev/null
if [[ "$?" == '0' ]]; then
    echo "Redis 集群已经创建好了。"
else
    echo "开始创建 Redis 集群。"
    docker run --network some-network --rm -i -t redis redis-cli --cluster create some-redis-8000:8000 some-redis-8001:8001 some-redis-8002:8002 some-redis-8003:8003 some-redis-8004:8004 some-redis-8005:8005 --cluster-replicas 1 --cluster-yes
fi

创建成功后,只要新的容器也使用网络some-network,就可以读写集群中的数据了

docker run --network some-network --rm -i -t redis redis-cli -c -h some-redis-8000 -p 8000

效果如下图所示

读写Redis集群.png

总结

我将上面的内容集成到了redis_cluster这个 GitHub 仓库中,只需要克隆到本地并执行脚本start.sh即可,效果如下图所示

一键启动Redis集群.png

全文完。