使用 Docker 搭建 Redis Cluster,最重要的环节就是容器通信的问题,这一块我们在之前的文章中已经给大家解决了《Docker 网络模式详解及容器间网络通信》,本篇文章主要练习使用多个容器完成 Redis Cluster 集群环境的搭建,顺便为学习 Docker Compose 铺铺路。俗话说没有对比就没有伤害,通过对比才能感受到 Docker Compose 的好处。

  关于 Redis Cluster 集群更多的内容请阅读《最通俗易懂的 Redis 架构模式详解》。

  

环境

  

  本文所使用的基础设施环境如下:

  • CentOS 7.8.2003
  • Docker version 19.03.12

  

搭建

  

  整体搭建步骤主要分为以下几步:

  • 创建网络;
  • 下载 Redis 镜像(其实这步可以省略,因为创建容器时,如果本地镜像不存在,就会去远程拉取);
  • 编写 Redis 配置文件;
  • 创建 Redis 容器;
  • 创建 Redis Cluster 集群。

  

创建网络

  

  为什么需要创建网络?因为:默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。说简单点就是为了让容器可以直接通过容器名称进行通信。

  从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称进行通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。

  但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

  

  通过 docker network create 命令可以创建自定义网络模式,默认为 bridge 网桥/桥接模式,完整命令如下:

docker network create redis-net

  

  通过 docker network ls 查看网络模式:

  

  我们还可以通过 docker network inspect redis-net 查看 redis-net 网络的详细信息:

  

编写 Redis 配置文件

  

创建目录及文件

  

# 创建目录
mkdir -p /usr/local/docker-redis/redis-cluster
# 切换至指定目录
cd /usr/local/docker-redis/redis-cluster/
# 编写 redis-cluster.tmpl 文件
vi redis-cluster.tmpl

  

编写配置文件

  

  redis-cluster.tmpl 文件内容如下:

port ${PORT}
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
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,如果填写 Docker 分配的 IP(172.x.x.x),可能会导致外部无法正常访问集群;
  • cluster-announce-port:集群节点映射端口;
  • cluster-announce-bus-port:集群节点总线端口。

  每个 Redis 集群节点都需要打开两个 TCP 连接。一个用于为客户端提供服务的正常 Redis TCP 端口,例如 6379。还有一个基于 6379 端口加 10000 的端口,比如 16379。

  第二个端口用于集群总线,这是一个使用二进制协议的节点到节点通信通道。节点使用集群总线进行故障检测、配置更新、故障转移授权等等。客户端永远不要尝试与集群总线端口通信,与正常的 Redis 命令端口通信即可,但是请确保防火墙中的这两个端口都已经打开,否则 Redis 集群节点将无法通信。

  

  在 redis-cluster 目录下执行以下命令:

for port in `seq 6371 6376`; do \
mkdir -p ${port}/conf \
&& PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf \
&& mkdir -p ${port}/data;\
done

上面是一段 shell for 语句,意思就是循环创建 6371 ~ 6376 相关的目录及文件。

  

  查看命令执行结果,如果没有 tree 命令先安装 yum install -y tree

  

  以下内容为每个节点的配置文件详细信息。

[root@localhost redis-cluster]# cat /usr/local/docker-redis/redis-cluster/637{1..6}/conf/redis.conf
port 6371
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6371
cluster-announce-bus-port 16371 port 6372
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6372
cluster-announce-bus-port 16372 port 6373
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6373
cluster-announce-bus-port 16373 port 6374
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6374
cluster-announce-bus-port 16374 port 6375
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6375
cluster-announce-bus-port 16375 port 6376
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6376
cluster-announce-bus-port 16376

  

创建 Redis 容器

  

创建容器

  

  将宿主机的 6371 ~ 6376 之间的端口与 6 个 Redis 容器映射,并将宿主机的目录与容器内的目录进行映射(目录挂载)。记得指定网络模式,使用我们自己创建的 redis-net 网络。

for port in $(seq 6371 6376); do \
docker run -di -p ${port}:${port} -p 1${port}:1${port} \
--restart always --name redis-${port} --net redis-net \
-v /usr/local/docker-redis/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \
-v /usr/local/docker-redis/redis-cluster/${port}/data:/data \
redis redis-server /usr/local/etc/redis/redis.conf; \
done

  

  docker ps -n 6 查看容器是否创建成功。

  

  docker network inspect redis-net | grep -i -E "name|ipv4address" 查看给每个节点分配的IP信息。

  

创建 Redis Cluster 集群

  

  随便进入一个容器节点,并进入 /usr/local/bin/ 目录:

# 进入容器
docker exec -it redis-6371 bash
# 切换至指定目录
cd /usr/local/bin/

  

  接下来我们就可以通过以下命令实现 Redis Cluster 集群的创建。

redis-cli -a 1234 --cluster create 172.18.0.2:6371 172.18.0.3:6372 172.18.0.4:6373 172.18.0.5:6374 172.18.0.6:6375 172.18.0.7:6376 --cluster-replicas 1

  

  出现选择提示信息,输入 yes,结果如下所示:

  集群创建成功如下:

  

  以下内容是创建集群时返回的详细信息,也就是上两幅图中的所有内容。

root@705a5ec95a2e:/usr/local/bin# redis-cli -a 1234 --cluster create 172.18.0.2:6371 172.18.0.3:6372 172.18.0.4:6373 172.18.0.5:6374 172.18.0.6:6375 172.18.0.7:6376 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.18.0.6:6375 to 172.18.0.2:6371
Adding replica 172.18.0.7:6376 to 172.18.0.3:6372
Adding replica 172.18.0.5:6374 to 172.18.0.4:6373
M: 4dbede8f79c98a8cf63556387ce8c2a793d20089 172.18.0.2:6371
slots:[0-5460] (5461 slots) master
M: c2117d59666f20be5a29485b2e22753991a2dcb9 172.18.0.3:6372
slots:[5461-10922] (5462 slots) master
M: a5a8fdda426785c54a0e557b753ef571d22581a7 172.18.0.4:6373
slots:[10923-16383] (5461 slots) master
S: 4aca662dbc0d40498592c11c8dcb94b62c39b15c 172.18.0.5:6374
replicates a5a8fdda426785c54a0e557b753ef571d22581a7
S: 55fe2da8fe4fb1acdf950a6030a6304713eb613b 172.18.0.6:6375
replicates 4dbede8f79c98a8cf63556387ce8c2a793d20089
S: be84c1e8600986d5ebfbd2e18611dc4d1ace41a7 172.18.0.7:6376
replicates c2117d59666f20be5a29485b2e22753991a2dcb9
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join >>> Performing Cluster Check (using node 172.18.0.2:6371)
M: 4dbede8f79c98a8cf63556387ce8c2a793d20089 172.18.0.2:6371
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: be84c1e8600986d5ebfbd2e18611dc4d1ace41a7 192.168.10.10:6376
slots: (0 slots) slave
replicates c2117d59666f20be5a29485b2e22753991a2dcb9
M: c2117d59666f20be5a29485b2e22753991a2dcb9 192.168.10.10:6372
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: a5a8fdda426785c54a0e557b753ef571d22581a7 192.168.10.10:6373
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 4aca662dbc0d40498592c11c8dcb94b62c39b15c 192.168.10.10:6374
slots: (0 slots) slave
replicates a5a8fdda426785c54a0e557b753ef571d22581a7
S: 55fe2da8fe4fb1acdf950a6030a6304713eb613b 192.168.10.10:6375
slots: (0 slots) slave
replicates 4dbede8f79c98a8cf63556387ce8c2a793d20089
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

  

  至此一个高可用的 Redis Cluster 集群搭建完成,如下图所示,该集群中包含 6 个 Redis 节点,3 主 3 从。三个主节点会分配槽,处理客户端的命令请求,而从节点可用在主节点故障后,顶替主节点。

  

查看集群状态

  

  我们先进入容器,然后通过一些集群常用的命令查看一下集群的状态。

# 进入容器
docker exec -it redis-6371 bash
# 切换至指定目录
cd /usr/local/bin/

  

检查集群状态

  

  因为我们使用了自定义的网络进行容器管理,这样可以使容器直接通过容器名称通信。推荐使用这种方式。

# 使用 IP
redis-cli -a 1234 --cluster check 192.168.10.10:6371
# 使用容器名称
redis-cli -a 1234 --cluster check redis-6372:6372

  

查看集群信息和节点信息

  

# 连接至集群某个节点
redis-cli -c -a 1234 -h redis-6373 -p 6373
# 查看集群信息
cluster info
# 查看集群结点信息
cluster nodes

  

SET/GET

  

  在 6371 节点中执行写入和读取,命令如下:

# 进入容器并连接至集群某个节点
docker exec -it redis-6371 /usr/local/bin/redis-cli -c -a 1234 -h redis-6371 -p 6371
# 写入数据
set name mrhelloworld
set aaa 111
set bbb 222
# 读取数据
get name
get aaa
get bbb

  别着急,让我来解释一下上图中的操作过程:

  • 首先进入容器并连接至集群某个节点;
  • 然后执行第一个 set 命令 set name mrhelloworldname 键根据哈希函数运算以后得到的值为 [5798]。当前集群环境的槽分配情况为:[0-5460] 6371节点[5461-10922] 6372节点[10923-16383] 6373节点,所以该键的存储就被分配到了 6372 节点上;
  • 再来看第二个 set 命令 set aaa,这里大家可能会有一些疑问,为什么看不到 aaa 键根据哈希函数运算以后得到的值?因为刚才重定向至 6372 节点插入了数据,此时如果还有数据插入,正好键根据哈希函数运算以后得到的值也还在该节点的范围内,那么直接插入数据即可;
  • 接着是第三个 set 命令 set bbbbbb 键根据哈希函数运算以后得到的值为 [5287],所以该键的存储就被分配到了 6371 节点上;
  • 然后是读取操作,第四个命令 get namename 键根据哈希函数运算以后得到的值为 [5798],被重定向至 6372 节点读取;
  • 第五个命令 get aaaaaa 键根据哈希函数运算以后得到的值也在 6372 节点,直接读取;
  • 第六个命令 get bbbbbb 键根据哈希函数运算以后得到的值为 [5287],被重定向至 6371 节点读取。

  

  通过以上操作我们得知 name 键的存储被分配到了 6372 节点,如果直接连接 6372 节点并获取该值会怎么样?没错,不需要重定向节点,因为数据就在该节点,所以直接读取返回。

  总结下来就是,在 Redis Cluster 集群模式中,无论连接哪个节点,每次我们执行写入或者读取操作的时候,所有的键会根据哈希函数运算并映射到 0 ~ 16383 整数槽内,如果恰好对应的就在你当前连接的节点中,则直接执行命令,否则重定向至对应节点执行命令。

  

客户端连接

  

  最后来一波客户端连接操作,随便哪个节点,看看可否通过外部访问 Redis Cluster 集群。

  至此使用多个容器搭建 Redis Cluster 集群环境就到这里,其实整体搭建过程不算特别麻烦,因为:

  • 创建 Redis 集群需要用到 Ruby,否则就得自己关联节点构建集群,自己分配槽;
  • 如果使用 Ruby 构建 Redis 集群,就需要安装 Ruby 环境;
  • 而 Redis 从 5 版本开始可以直接使用 redis-cli 命令创建集群了,就省去了很多麻烦事;
  • 我们还使用了 shell for 循环语句简化了构建过程,否则那些语句一条条执行也够你闹心的。

  综上所述,有没有更简单的办法呢?当然有了,不然我在这跟你卖什么关子。

  Docker Compose 就可以解决这个问题。后面我们先学习一下什么是 Docker Compose,然后使用 Docker Compose 再来搭建一遍 Redis Cluster 集群环境,感受感受这前后的区别。

本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议

大家可以通过 分类 查看更多关于 Docker 的文章。

  

Docker 搭建 Redis Cluster 集群环境的更多相关文章

  1. Docker Compose 搭建 Redis Cluster 集群环境

    在前文<Docker 搭建 Redis Cluster 集群环境>中我已经教过大家如何搭建了,本文使用 Docker Compose 再带大家搭建一遍,其目的主要是为了让大家感受 Dock ...

  2. 【精】搭建redis cluster集群,JedisCluster带密码访问【解决当中各种坑】!

    转: [精]搭建redis cluster集群,JedisCluster带密码访问[解决当中各种坑]! 2017年05月09日 00:13:18 冉椿林博客 阅读数:18208  版权声明:本文为博主 ...

  3. docker搭建redis主从集群和sentinel哨兵集群,springboot客户端连接

    花了两天搭建redis主从集群和sentinel哨兵集群,讲一下springboot客户端连接测试情况 redis主从集群 从网上查看说是有两种方式:一种是指定配置文件,一种是不指定配置文件 引用地址 ...

  4. 单台服务器-利用docker搭建Redis哨兵集群模式

    前言:只有一台华为云服务器,所以打算创建三个容器来模拟三个服务器了. 一:拉取redis镜像 二:拉取redis.conf文件 放在自定义的目录下:wget -c http://download.re ...

  5. 搭建redis cluster集群服务

    redis 5.0以下为ruby编写,运行命令时需要安装ruby,而5.0以上则为c编写,可直接安装后运行.因此本文使用redis5.0.5 1.编写配置文件 在 /home 下新建 redis-cl ...

  6. Docker构建redis cluster集群

    准备工作 安装gcc ruby 解压编译redis Redis 是 c 语言开发的.安装 redis 需要 c 语言的编译环境.如果没有 gcc 需要在线安装. yum install gcc-c++ ...

  7. docker 安装redis cluster集群

    安装Redis镜像 docker pull yyyyttttwwww/redis 创建redis容器 docker run -it -d --name r1 -p 5001:6379 --net=ne ...

  8. centos6下redis cluster集群部署过程

    一般来说,redis主从和mysql主从目的差不多,但redis主从配置很简单,主要在从节点配置文件指定主节点ip和端口,比如:slaveof 192.168.10.10 6379,然后启动主从,主从 ...

  9. 搭建分布式 Redis Cluster 集群与 Redis 入门

    目录 Redis 集群搭建 Redis 是啥 集群(Cluster) Redis Cluster 说明 Redis Cluster 节点 Redis Cluster 集群模式 不能保证一致性 创建和使 ...

随机推荐

  1. Linux常用命令之cp、mv、rm、cat、more、head、tail、ln命令讲解

    上一章节中,我们了解到了Linux系统的最基础的几个文件处理命令,核心的是ls命令,在今天这章中,我们来继续学习Linux对于文件操作相关的一些命令,比如复制.移动.删除.查看等命令. 1.cp 命令 ...

  2. Linux入门-程序开发

    Linux程序开发 linux程序总体上来说是分两部分的: 1. 底层驱动程序开发: 2.应用层应用程序开发: 驱动程序 一般情况下驱动是跟内核与硬件有关系的,编程语言是C语言,需要懂一些硬件的知识, ...

  3. python获取系统内存占用信息的实例方法

    psutil是一个跨平台库(http://code.google.com/p/psutil/),能够轻松实现获取系统运行的进程和系统利用率(包括CPU.内存.磁盘.网络等)信息.它主要应用于系统监控, ...

  4. artifactdescriptorexception:Failed to read artifact descriptor for xxx:jar ”

    在Eclipse中执行Maven的install命令时,报“Failed to read artifact descriptor for xxx:jar ”的错误.这可能是在下载过程中文件出现错误.或 ...

  5. C#LeetCode刷题之#500-键盘行(Keyboard Row)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3796 访问. 给定一个单词列表,只返回可以使用在键盘同一行的字母 ...

  6. 关于 JavaScript 字符串的一个小知识

    说起字符串,我们再熟悉不过了.接触编程的第一个经典任务就是输出字符串:Hello, world.但是你知道 JavaScript 字符串在计算机里是怎么表示的吗? 最简单直观但不太准确的的理解就是,字 ...

  7. MySQL空间函数实现位置打卡

    项目需求是跟用户当前位置判断是否在给定的地理位置范围内,符合位置限制才可以打卡,其中的位置范围是一个或多个不规则的多边形.如下图,判断用户是在清华还是北大. 图形获取区域坐标 因为项目前端使用微信小程 ...

  8. Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  9. JDK1.8源码学习-Object

    JDK1.8源码学习-Object 目录 一.方法简介 1.一个本地方法,主要作用是将本地方法注册到虚拟机中. private static native void registerNatives() ...

  10. 用Python的Pandas和Matplotlib绘制股票唐奇安通道,布林带通道和鳄鱼组线

    我最近出了一本书,<基于股票大数据分析的Python入门实战 视频教学版>,京东链接:https://item.jd.com/69241653952.html,在其中给出了MACD,KDJ ...