redis cluster 学习 实战篇(一)

时间:2022-06-20
本文章向大家介绍redis cluster 学习 实战篇(一),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一 简介

从Redis3.0开始,Redis提供了 redis cluster 集群支持,用于在多个redis节点间共享数据,以提高服务的可用性。 redis cluster 采用去中心化结构,不用proxy代理,应用可以直接访问集群中的数据节点。本文从实战入手,一步步了解redis cluster的创建,运维管理。部署redis cluster 有两种方式:原生命令安装和官方工具安装,本文采用原生的命令安装,可以体会构建redis cluster的具体步骤,深入了解其中的原理。

二 环境

2.1 实例分配

本文计划搭建三节点的redis cluster,每个节点包含一主一从。

主库              从库
10.10.20.7:6381 10.10.20.13:6381
10.10.20.7:6382 10.10.20.13:6382
10.10.20.7:6383 10.10.20.13:6383

讨论 服务器数据量

搭建集群的时候,需要最少3个主节点,否则报错,使用2台,可以像上面那样指定主从配置,如果使用三台机器 A B C 主从配置的时候要避免主从在同一台机器上,设计如下方式:

m   s
A:1 B:1 
B:2 C:2
C:1 A:2

但是当集群规模达到一定数据量时,感觉最好还是使用偶数机器,不要选择奇数集群将redis 构成循环,维护起来巨麻烦,比如c机器要维护,要切换 C:1 A:2,关闭C2 。读者朋友可以反馈你们的生产是如何设计的。

2.2 redis cluster 实例目录

mkdir  -p /data/redis_cluster/{conf,data,run};
mkdir  -p /data/logs/redis_cluster;
mkdir  -p /data/redis_cluster/data/{6381,6382,6383}

其中:

conf 目录存放 集群所有节点的config配置文件

data 是数据目录,存放 rdb文件或者aof文件,用于持久化,集群生成的conf文件也会存放于此。

run 用来存放pid文件

三 安装 部署

3.1 安装ruby

redis 5.0 之前的版本提供基于ruby的集群管理工具redis-trib.rb, 需要ruby的版本在2.3版本,否则会报错版本太低不支持。

wget "https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.2.tar.gz"
tar -zxf ruby-2.6.2.tar.gz; cd ruby-2.6.2/
./configure --prefix=/usr/local/ruby
./configure --prefix=/opt/ruby/
make && make install

给redis-trib.rb安装 redis 驱动

gem install redis

3.2 安装redis

wget "http://download.redis.io/releases/redis-4.0.14.tar.gz"
tar xzf redis-4.0.14.tar.gz
cd redis-4.0.14
make && make PREFIX=/opt/redis install

ln -s /opt/redis/bin/redis-cli /usr/bin/redis-cli ;
ln -s /opt/redis/bin/redis-server  /usr/binredis-server

设置配置文件6381.conf

daemonize yes
pidfile "/data/redis_cluster/run/redis_6381.pid"
port 6381
tcp-backlog 1024
bind 0.0.0.0
timeout 0
tcp-keepalive 60
loglevel notice
logfile "/data/logs/redis_cluster/redis_6381.log"
maxmemory 50000000
maxmemory-policy volatile-lru
dir "/data/redis_cluster/data/6381"
dbfilename "dump_6381.rdb"
# 启用redis-cluster集群
cluster-enabled yes
# 集群节点配置文件
# 该文件无需手工修改,由redis自动维护(创建和更新)
# 需要注意,单机运行多实例时,确保该文件没有被其他实例覆盖(不允许重名)
cluster-config-file nodes-6381.conf

# 节点超时时长(毫秒)
cluster-node-timeout 1500

#默认情况下,集群全部的slot有节点分配,集群状态才为ok,才能提供服务。设置为no,可以在slot没有全部分配的时候提供服务。不建议打开该配置,这样会造成分区的时候,小分区的master一直在接受写请求,而造成很长时间数据不一致。
#当部分key所在的节点不可用时,如果此参数设置为"yes"(默认值), 则整个集群停止接受操作;
#如果此参数设置为 "no",则集群依然为可达节点上的key提供读写操作

cluster-require-full-coverage no

#在进行故障转移的时候,全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间了,导致数据过于陈旧,这样的slave不应该被提升>为master。该参数就是用来判断slave节点与master断线的时间是否过长。判断方法是:
#比较slave断开连接的时间和(node-timeout * slave-validity-factor) + repl-ping-slave-period
#如果节点超时时间为三十秒, 并且slave-validity-factor为10,假设默认的repl-ping-slave-period是10秒,即如果超过310秒slave将不会尝试进行故障转移
#可能出现由于某主节点失联却没有从节点能顶上的情况,从而导致集群不能正常工作,在这种情况下,只有等到原来的主节点重新回归到集群,集群才恢复运作
#如果设置成0,则无论从节点与主节点失联多久,从节点都会尝试升级成主节

cluster-slave-validity-factor 10

#master的slave数量大于该值,slave才能迁移到其他孤立master上,如这个参数若被设为2,那么只有当一个主节点拥有2 个可工作的从节点时,它的一个从节点会尝试迁移。
#主节点需要的最小从节点数,只有达到这个数,主节点失败时,它从节点才会进行迁移。
#cluster-migration-barrier 1

将拷贝到其他节点,修改对应的端口号即可。启动实例

cd /opt/redis/bin
./redis-server  /data/redis_cluster/conf/6381.conf
./redis-server  /data/redis_cluster/conf/6382.conf
./redis-server  /data/redis_cluster/conf/6383.conf

3.3 初始化集群

添加节点,登陆其中一个节点比如 10.10.20.7 6381 执行如下命令

redis-cli -h 10.10.20.7 -p 6381 -c

cluster meet  10.10.20.7 6382
cluster meet  10.10.20.7 6383

添加槽位的脚本 add_slots.sh(如果使用 redis-trib.rb 会比较方便一个命令完成集群的创建和槽位分配。)

#!/bin/bash
###6381
n=0
for ((i=n;i<=5461;i++))
do
   /opt/redis/bin/redis-cli -h 10.10.20.7 -p 6381  CLUSTER ADDSLOTS $i
done

###6382
n=5462
for ((i=n;i<=10922;i++))
do
   /opt/redis/bin/redis-cli -h 10.10.20.7  -p 6382  CLUSTER ADDSLOTS $i
done
###6383
#!/bin/bash
n=10923
for ((i=n;i<=16383;i++))
do
   /opt/redis/bin/redis-cli -h 10.10.20.7  -p 6383  CLUSTER ADDSLOTS $i
done

添加从库角色节点,启动指定的从库角色的slave 实例。登陆任意一个节点执行如下命令将slave实例添加到已经创建好的集群中

cluster meet  10.10.20.13 6381
cluster meet  10.10.20.13 6382
cluster meet  10.10.20.13 6383

配置主从关系,登陆 10.10.20.13 设置为10.10.20.7实例的从库。

cluster nodes0746eb6eda3d6466def110c0d76d6d675ce8a2c7 10.10.20.7:6381@16381 myself,master - 0 1553605588000 1 connected 0-5461308f44c7557e6ed96d7bc84b60dc4395059aa5d9 10.10.20.7:6383@16383 master - 0 1553605589451 2 connected 10923-16383
6312e97ada99cfe48ccf3d5b85714420763d89eb 10.10.20.7:6382@16382 master - 0 1553605589451 4 connected 5462-10922
redis-cli -h 127.0.0.1 -p 6381 -c
cluster replicate 0746eb6eda3d6466def110c0d76d6d675ce8a2c7

redis-cli -h 127.0.0.1 -p 6382 -c
cluster replicate 6312e97ada99cfe48ccf3d5b85714420763d89eb

redis-cli -h 127.0.0.1 -p 6383 -c
cluster replicate 308f44c7557e6ed96d7bc84b60dc4395059aa5d9

使用集群管理工具一次性初始化集群:

/opt/redis/bin/redis-trib.rb create --replicas 1 10.10.20.7:6381 10.10.20.7:6382 10.10.20.7:6383 10.10.20.13:6381 10.10.20.13:6382  10.10.20.13:6383

使用工具的好处是避免繁琐的初始化,搭建主从,分配槽位等命令,一步到位,将主库尽量打散,不在同一台机器上。缺点是主从配对是随机,不一定按照我们的设想来。

四 常用维护命令

查看集群信息

cluster info:查看集群信息,包含几个节点,槽位分配和集群状态。
cluster nodes: 展示redis 集群中所有节点的ip 端口,node id ,主从关系等信息
cluster slaves <node_id>: 列出指定node_id 的从节点信息,node_id 必须是master 角色,否则报错。
127.0.0.1:6381> cluster slaves 035e96f8b129123e5edab58eeed9de4d3fe0008e
(error) ERR The specified node is not a master
127.0.0.1:6381> cluster slaves 0746eb6eda3d6466def110c0d76d6d675ce8a2c7
1) "035e96f8b129123e5edab58eeed9de4d3fe0008e 10.10.20.13:6381@16381 slave 0746eb6eda3d6466def110c0d76d6d675ce8a2c7 0 1553663469372 3 connected"
127.0.0.1:6381>

创建集群

cluster meet <ip> <port>: 将ip和port 指定的 redis 实例添加到当前的集群当中,在同一个节点操作添加其他所有的节点。
cluster replicate <node_id>:将当前节点设置为指定节点的从节点,搭建集群的时候使用

运维集群节点

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,只有在节点加入集群前才能设置。

槽位相关操作

cluster slots:列出节点和槽位的关系映射信息

127.0.0.1:6381> cluster slots
1) 1) (integer) 0
   2) (integer) 5461
   3) 1) "10.10.20.7"
      2) (integer) 6381
      3) "0746eb6eda3d6466def110c0d76d6d675ce8a2c7"
   4) 1) "10.10.20.13"
      2) (integer) 6381
      3) "035e96f8b129123e5edab58eeed9de4d3fe0008e"

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

127.0.0.1:6381> set name redis-cluster
-> Redirected to slot [5798] located at 10.10.20.7:6382
OK
10.10.20.7:6382> cluster keyslot name
(integer) 5798  <--- 位于slot  5798 

cluster countkeysinslot

10.10.20.7:6382> cluster getkeysinslot 5798 3
1) "9223372036854509229"
2) "9223372036854518268"
3) "9223372036854540893"

cluster getkeysinslot

10.10.20.7:6382> cluster countkeysinslot 5798
(integer) 18

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 flushslots:移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。

迁移槽位实践

我们计划手动将位于 10.10.20.7:6381上的槽位0 迁移到10.10.20.7:6382 上,迁移槽位的大概流程如下:

1 在目标节点上声明将从源节点上迁入Slot CLUSTER SETSLOT 2 在源节点上声明将往目标节点迁出Slot CLUSTER SETSLOT 3 批量从源节点获取KEY CLUSTER GETKEYSINSLOT 4 将获取的Key迁移到目标节点 MIGRATE 0 重复步骤3,4直到所有数据迁移完毕,MIGRATE命令会将所有的指定的key通过RESTORE key ttl serialized-value REPLACE迁移给target 5 分别向双方节点发送 CLUSTER SETSLOT 6 等待集群状态变为OK CLUSTER INFO 中的 cluster_state = ok

1. 首先查看各节点的槽位

127.0.0.1:6381> CLUSTER slots
1) 1) (integer) 0
   2) (integer) 5461
   3) 1) "10.10.20.7"
      2) (integer) 6381
      3) "0746eb6eda3d6466def110c0d76d6d675ce8a2c7"
   4) 1) "10.10.20.13"
      2) (integer) 6381
      3) "035e96f8b129123e5edab58eeed9de4d3fe0008e"
2) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "10.10.20.7"
      2) (integer) 6383
      3) "308f44c7557e6ed96d7bc84b60dc4395059aa5d9"
   4) 1) "10.10.20.13"
      2) (integer) 6383
      3) "bfc5edb2265bd198de991ec616c65c803257bb7c"
3) 1) (integer) 5462
   2) (integer) 10922
   3) 1) "10.10.20.7"
      2) (integer) 6382
      3) "6312e97ada99cfe48ccf3d5b85714420763d89eb"
   4) 1) "10.10.20.13"
      2) (integer) 6382
      3) "84ad44a600157da48cabf4306f61e3b3ccc8fa07"

2. 查看要迁移槽位的key

127.0.0.1:6381> cluster countkeysinslot 0
(integer) 3
127.0.0.1:6381> cluster getkeysinslot 0 3
1) "9223372036854548386"
2) "9223372036854641190"
3) "9223372036854663112"

3. 到目标节点执行导入操作从10.10.20.7:6381中导入槽 slot 0 到本节点

redis-cli -h 127.0.0.1 -p 6382 -c

cluster setslot 0 importing 0746eb6eda3d6466def110c0d76d6d675ce8a2c7

4. 到源节点进行迁移操作,将本节点的槽迁移到指定的节点中。

redis-cli -h 127.0.0.1 -p 6381 -c

cluster setslot 0 migrating 6312e97ada99cfe48ccf3d5b85714420763d89eb

5. 在源节点迁移槽位中的key到目标节点

migrate 10.10.20.7 6382 9223372036854548386 0 5000 replace

migrate 10.10.20.7 6382 9223372036854641190 0 5000 replace

migrate 10.10.20.7 6382 9223372036854663112 0 5000 replace

6. 最后设置槽位到目标节点,广播通知其他节点已经将Slot转移到目标节点

127.0.0.1:6381> cluster setslot 0 node 6312e97ada99cfe48ccf3d5b85714420763d89eb
OK
127.0.0.1:6382> cluster setslot 0 node 6312e97ada99cfe48ccf3d5b85714420763d89eb
OK

7. 验证是否迁移成功

127.0.0.1:6381> cluster slots
1) 1) (integer) 1
   2) (integer) 5461
   3) 1) "10.10.20.7"
      2) (integer) 6381
      3) "0746eb6eda3d6466def110c0d76d6d675ce8a2c7"
   4) 1) "10.10.20.13"
      2) (integer) 6381
      3) "035e96f8b129123e5edab58eeed9de4d3fe0008e"
      ....省略其他节点信息....
3) 1) (integer) 0 ## slot 0 已经迁移到节点10.10.20.7:6382
   2) (integer) 0 ##
   3) 1) "10.10.20.7"
      2) (integer) 6382
      3) "6312e97ada99cfe48ccf3d5b85714420763d89eb"
   4) 1) "10.10.20.13"
      2) (integer) 6382
      3) "84ad44a600157da48cabf4306f61e3b3ccc8fa07"
4) 1) (integer) 5462
   2) (integer) 10922
   3) 1) "10.10.20.7"
      2) (integer) 6382
      3) "6312e97ada99cfe48ccf3d5b85714420763d89eb"
   4) 1) "10.10.20.13"
      2) (integer) 6382
      3) "84ad44a600157da48cabf4306f61e3b3ccc8fa07"
127.0.0.1:6381> cluster nodes
0746eb6eda3d6466def110c0d76d6d675ce8a2c7 10.10.20.7:6381@16381 myself,master - 0 1553694073000 1 connected 1-5461
6312e97ada99cfe48ccf3d5b85714420763d89eb 10.10.20.7:6382@16382 master - 0 1553694074606 4 connected 0 5462-10922

8. 查看数据是否迁移成功

127.0.0.1:6381> cluster getkeysinslot 0 10
(empty list or set)

127.0.0.1:6382> cluster getkeysinslot 0 10
1) "9223372036854548386"
2) "9223372036854641190"
3) "9223372036854663112"

至此槽位迁移完毕,如果遇到key的数量特别多,显然人工方式已经不合适了,我们需要编写工具进行迁移。

五 总结

限于篇幅,本文着重介绍如何安装,搭建redis cluster 集群,以及部分常见的运维命令,和如何手动迁移槽位。后续的文章将介绍如何进行redis cluster高可用容灾,以及集群管理工具的使用。

参考文章

[1] https://redis.io/topics/cluster-tutorial

[2] https://www.cnblogs.com/zhoujinyi/p/6477133.html