redis优化系列(七)手动搭建Redis Cluster集群

该系列博文之上一篇:传送门 走你


基于docker-compose手动搭建Redis Cluster集群

本篇博文所使用的相关文件:相关文件.zip (自行下载并解压出来)

温馨提示:

如果你按照本篇博文进行搭建的话,那么有一些注意事项:

必须将解压后的所有文件(含文件夹)上传到服务器中的 /usr/docker/redis 目录,如果没有该路径自行创建即可

r1.png

/usr/docker/redis/config 目录中的文件如下:

r2.png


为什么要按照这个目录呢?

答:因为解压出来的Dockerfile和docker-compose.yaml这两个文件中的相关指令就是按照这个目录进行设置的,如果对这两个文件里面中的指令还算熟悉的话,那你可以将解压出来的所有文件(含文件夹)上传到服务器中自己喜欢的目录,然后编辑Dockerfile和docker-compose.yaml这两个文件中的对应的相关地方进行修改保存即可

相关概要

承接上篇博文,介绍完 Redis 集群分区规则之后,下面开始手动搭建 Redis 集群。搭建集群工作需要以下三个步骤:

1)准备节点。

2)节点握手。

3)分配槽。


1)准备节点:

性能:这是Redis赖以生存的看家本领,增加集群功能后当然不能对性能产生太大影响,所以Redis采取了P2P而非Proxy方式、异步复制、客户端重定向等设计,而牺牲了部分的一致性、使用性。


水平扩展:集群的最重要能力当然是扩展,文档中称可以线性扩展到1000结点。


可用性:在Cluster推出之前,可用性要靠Sentinel保证。有了集群之后也自动具有了Sentinel的监控和自动Failover能力。


Redis 集群一般由多个节点组成,节点数量至少为6个(一般至少都是3主3从)才能保证组成完整高可用的集群,前面的主从复制跟哨兵共同构成了高可用。


每个节点需要开启配置 cluster-enabled yes,让 Redis 运行在集群模式下。集群相关配置如下:

port 6379  #节点端口 

cluster-enabled yes  #开启集群模式

cluster-node-timeout 15000  #节点超时时间,单位毫秒

cluster-config-file "nodes-6379.conf"  #集群内部配置文件



Redis 集群一般由多个节点组成,节点数量至少为6个才能保证组成完整高可用的集群。每个节点需要开启配置 cluster-enabled yes,让 Redis 运行在集群模式下,上面的配置都相应的给到redis的配置文件当中并启动。


其它配置和单机模式一致即可,配置文件命名规则 redis-{port}.conf,准备好配置后启动所有节点,第一次启动时如果没有集群配置文件,它会自动创建一份,文件名称采用 cluster-config-file 参数项控制,建议采用 node-{port}.conf 格式定义,也就是说会有两份配置文件。


当集群内节点信息发生变化,如添加节点、节点下线、故障转移等。节点会自动保存集群状态到配置文件中。需要注意的是,Redis 自动维护集群配置文件,不要手动修改,防止节点重启时产生集群信息错乱。



r5.jpg



节点规划如下:

r6.png

docker-compose.yaml文件中的生成的容器名称、ip地址、映射端口号都是按照上图所示来做的

基于博文开头提供的文件(自行解压并上传到服务器)开始手动搭建Redis Cluster集群

1、进入/usr/docker/redis目录使用Dockerfile文件构建接下来要使用的镜像

cd /usr/docker/redis

#生成镜像
docker build -t redis-cluster .

注意一点,生成的镜像名字必须叫:redis-cluster 因为 docker-compose.yaml 文件里面指定的所使用的镜像名字就是 redis-cluster 当然,如果你对 docker-compose.yaml 还算熟悉的话,可以改成别的名字 只是要记得编辑 docker-compose.yaml 文件中对应的地方然后保存即可。


如果在构建镜像过程中报如下错误(大概率事件会报如下错误):

r3.png

这个地址链接超时,wget不下来了。。这样的话。。那就ctrl + c 结束本次构建吧。。放心,在解压中的文件会有一个redis-3.2.1.gem文件,你可以上传到你能访问到的一个网站中的目录,然后编辑Dockerfile文件,将wget https://rubygems.global.ssl.fastly.net/gems/redis-3.2.1.gem 换成 wget www.your_domain/redis-3.2.1.gem 即可


构建成功后可以使用 docker images 查看刚刚构建完成的镜像,示例截图如下:

r4.png


2、使用docker-compose命令来批量创建生成redis节点容器

还是在/usr/docker/redis目录下执行该命令

#批量创建生成redis节点容器
docker-compose -p redis-cluster up -d

上面命令中的-p就是指定服务编排的项目名称  这里我们给这个服务编排起的项目名称为:redis-cluster,可以起任意名字。。最后面的-d表示以守护进程方式启动(启动后在后台运行),好吧,大家都知道的。。示例截图如下:

r7.png


可以使用docker ps 查看是否成功创建了6个redis节点容器

r1.png

如上图所示 6个redis节点创建成功


进入6个容器中的任意一个容器里面查看配置文件:

docker exec -it redis-master1 bash  #进入redis-master1这个容器,你也可以进入其它容器里面都可以

cd /var/lib/redis/

ls #会看到nodes-6379.conf配置文件

r2.png


使用vi来查看该配置文件:vi nodes-6379.conf

r3.png

文件内容记录了集群初始状态,这里最重要的是 节点id,上图中的 4c341506d1c1c60d1c6d6833be65a1f2296454bb 就是 节点id,它是一个40位16进制字符串,用于唯一标识集群内一个节点,节点id 在集群初始化时只创建一次,就算节点重启时,也会加载集群配置文件进行重用,节点id 依然不会改变还是之前生成的 节点id,结合做相应的集群操作,而Redis的 运行id 每次重启都会变化。

2)节点握手

节点握手是指:一批运行在集群模式下的节点通过 Gossip 协议彼此通信,达到感知对方的过程。节点握手是集群彼此通信的第一步,由客户端发起命令:cluster meet{ip}{port} 


Gossip协议是一种分布式协议,关于Gossip协议可以查看如下文章的介绍:

https://www.iteblog.com/archives/2505.html

http://kaiyuan.me/2015/07/08/Gossip/


通过命令 cluster meet 127.0.0.1 6380让节点6379和6380节点进行握手通信。cluster meet 命令是一个异步命令,执行之后立刻返回。内部发起与目标节点进行握手通信。

r4.jpg

①、节点6379本地创建6380节点信息对象,并发送 meet 消息。

②、节点6380接受到 meet 消息后,保存6379节点信息并回复 pong 消息。

③、之后节点6379和6380彼此定期通过 ping/pong 消息进行正常的节点通信。


注意:

①、每个Redis Cluster节点会占用两个TCP端口,一个监听客户端的请求,默认是6379,另外一个在前一个端口加上10000,比如16379,来监听数据的请求,节点和节点之间会监听第二个端口,用一套二进制协议来通信。

节点之间会通过套协议来进行失败检测,配置更新,failover认证等等。

为了保证节点之间正常的访问,需要注意防火墙的配置,或者在你对应云服务器厂商的安全组规则中放通对应端口。


进入redis-master1这个节点容器里面,使用netstat -antp|grep 6391 可以看到有监听两个端口:

r4.png

②、节点建立握手之后集群还不能正常工作,这时集群处于下线状态,所有的数据读写都被禁止

开始搭建节点握手(也就是让每个redis节点之间能够进行连接通讯)

进入6个redis节点容器中的任意一个容器,这里我还是进入redis-master1这个redis节点容器里面

docker exec -it redis-master1 bash  #进入redis-master1这个容器里面


打开redis客户端,并使用 cluster nodes 命令查看集群节点状态

redis-cli -p 6391

cluster nodes

r1.png


在redis客户端中使用cluster meet命令来给每个redis节点进行连接通讯

cluster meet 119.3.220.26 6392

cluster meet 119.3.220.26 6393

cluster meet 119.3.220.26 6394

cluster meet 119.3.220.26 6395

cluster meet 119.3.220.26 6396

r2.png

这里使用公网ip地址进行每个redis节点容器之间通讯,你也可以使用内网ip,只要能ping的通,不过使用公网ip方便省事。对了119.3.220.26要换成你自己服务器的公网ip地址,别看都不看。。啥都复制。。


使用cluster nodes命令来查看节点状态

r3.png

看上图会发现都是连接状态


查看/var/lib/redis/nodes-6379.conf配置文件

r4.png

看上图会发现配置文件也会做相应记录等相关信息


当然,本文中没有设置连接密码。。生产环境中必须设置连接密码。至此。。节点握手搭建成功。

接下来 设置从节点

作为一个完整的集群,需要主从节点,保证当它出现故障时可以自动进行故障转移。集群模式下,Reids 节点角色分为主节点和从节点。


首次启动的节点和被分配槽的节点都是主节点,从节点只是负责复制主节点的槽信息和相关的数据,从节点就是一个备份。


使用 cluster replicate {nodeId} 命令让一个节点成为从节点。其中命令执行必须在对应的从节点上执行将当前节点设置为 node_id 指定的节点的从节点。


注意:集群架构模式下也可以设置1主多从,但是不支持前面章节中的树状主从结构。


本文中的6个redis节点容器中,端口为:6391、6392、6393这三个端口的redis节点容器是master。而6394、6395、6396这三个端口的redis节点容器是slave。6391对应6394、6392对应6395、6393对应6396。也就是接下来的操作需要分别进入6394、6395、6396这三台从节点的redis容器里面执行cluster replicate {nodeId} 命令。不过为了省事,进入其中一台redis节点容器即可,这里我还是进入redis-master1这个节点容器里面,然后直接使用如下命令进行操作。

#进入redis-master1容器里面
docker exec -it redis-master1 bash

#让6394这台redis节点成为4c341506d1c1c60d1c6d6833be65a1f2296454bb(这里也就是redis-master1)这台主节点的从节点
redis-cli -h 119.3.220.26 -p 6394 cluster replicate 4c341506d1c1c60d1c6d6833be65a1f2296454bb

#让6395这台redis节点成为35124ff4f3aaa4cff34a83694f23399ca6502480(这里也就是redis-master2)这台主节点的从节点
redis-cli -h 119.3.220.26 -p 6395 cluster replicate 35124ff4f3aaa4cff34a83694f23399ca6502480

#让6396这台redis节点成为75224ec8b2906095e051edf1e5d83f79700b0593(这里也就是redis-master3)这台主节点的从节点
redis-cli -h 119.3.220.26 -p 6396 cluster replicate 75224ec8b2906095e051edf1e5d83f79700b0593

r5.png

注意:119.3.220.26换成你自己服务器的公网ip地址,4c341506d1c1c60d1c6d6833be65a1f2296454bb、35124ff4f3aaa4cff34a83694f23399ca6502480、75224ec8b2906095e051edf1e5d83f79700b0593 这三个 节点id 换成对应的你自己的 节点id


使用 cluster nodes命令再次查看我们的节点状态,会发现已经配置成功了

r6.png

接下来 分配槽

Redis 集群把所有的数据映射到16384个槽中。每个 key 会映射为一个固定的槽,只有当节点分配了槽,才能响应和这些槽关联的键命令。通过 cluster addslots 命令为节点分配槽。是给redis主节点分配槽。


利用 bash 特性批量设置槽(slots),命令如下:

#还是进入redis-master1这台redis节点容器里面
docker exec -it redis-master1 bash

#分配槽
redis-cli -h 119.3.220.26  -p 6391 cluster addslots {0..5461}
redis-cli -h 119.3.220.26  -p 6392 cluster addslots {5462..10922}
redis-cli -h 119.3.220.26  -p 6393 cluster addslots {10923..16383}

r7.png


进入redis-slave1节点容器里面,执行一个set操作

#进入redis-slave1容器里面
docker exec -it redis-slave1 bash

#随便set一个值,会发现 不行 他会提示你要到对应的节点里面去执行set命令,这里提示你要到6391这台节点里面去执行set命令
redis-cli -p 6394 set wzyl 123

r1.png


如果一定要在这台从节点redis上进行set等操作,那么可以加一个 -c 选项 表示使用集群模式来操作

r2.png

从以上命令中可以发现,redis客户端也可以设置使用集群模式。


你会发现set成功了,也能get成功了。。难道是成功set到这台从redis节点了吗?不是的!虽然是在这台从redis节点set数据并且用了-c集群模式,其实是它自动帮你转移到了相对应的redis节点去set数据啦。


至此。。我们依照 Redis 协议手动建立一个集群。它由6个节点构成,3个主节点负责处理槽和相关数据,3个从节点负责故障转移。手动搭建集群便于理解集群建立的流程和细节,但是从中发现集群搭建需要很多步骤,当集群节点众多时,必然会加大搭建集群的复杂度和运维成本。因此 Redis 官方提供了 redis-trib.rb 工具方便我们快速搭建集群。在生产环境中我们肯定不会这样手动搭建redis集群的!

集群常用命令:

cluster info:打印集群的信息。

cluster nodes:列出集群当前已知的所有节点(node)的相关信息。

cluster meet <ip> <port>:将ip和port所指定的节点添加到集群当中。

cluster addslots <slot> [slot ...]:将一个或多个槽(slot)指派(assign)给当前节点。

cluster delslots <slot> [slot ...]:移除一个或多个槽对当前节点的指派。

cluster slots:列出槽位、节点信息。

cluster slaves <node_id>:列出指定节点下面的从节点信息。

cluster replicate <node_id>:将当前节点设置为指定节点的从节点。

cluster saveconfig:手动执行命令保存保存集群的配置文件,集群默认在配置修改的时候会自动保存配置文件。

cluster keyslot <key>:列出key被放置在哪个槽上。

cluster flushslots:移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。

cluster countkeysinslot <slot>:返回槽目前包含的键值对数量。

cluster getkeysinslot <slot> <count>:返回count个槽中的键。

cluster setslot <slot> node <node_id> 将槽指派给指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽,然后再进行指派。 

cluster setslot <slot> migrating <node_id> 将本节点的槽迁移到指定的节点中。  

cluster setslot <slot> importing <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。 

cluster setslot <slot> stable 取消对槽 slot 的导入(import)或者迁移(migrate)。 

cluster failover:手动进行故障转移。

cluster forget <node_id>:从集群中移除指定的节点,这样就无法完成握手,过期时为60s,60s后两节点又会继续完成握手。

cluster reset [HARD|SOFT]:重置集群信息,soft是清空其他节点的信息,但不修改自己的id,hard还会修改自己的id,不传该参数则使用soft方式。

cluster count-failure-reports <node_id>:列出某个节点的故障报告的长度。

cluster SET-CONFIG-EPOCH:设置节点epoch,只有在节点加入集群前才能设置。


不管多么崎岖不平,都比站在原地更接近幸福    —宫崎骏《千与千寻》



声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

精彩评论

全部回复12人评论7,777人参与