redis cluster(集群)模式

背景:Redis的官方多机部署方案,Redis Cluster。一组Redis Cluster是由多个Redis实例组成,官方推荐我们使用6实例,其中3个为主节点,3个为从结点。一旦有主节点发生故障的时候,Redis Cluster可以选举出对应的从结点成为新的主节点,继续对外服务,从而保证服务的高可用性。那么对于客户端来说,知道对应的key是要路由到哪一个节点呢?原来,Redis Cluster 把所有的数据划分为16384个不同的槽位,可以根据机器的性能把不同的槽位分配给不同的Redis实例,对于Redis实例来说,他们只会存储部门的Redis数据,当然,槽的数据是可以迁移的,不同的实例之间,可以通过一定的协议,进行数据迁移。
1、本文使用一台物理机,用docker部署多个redis
1.1、创建一个docker虚拟网卡
# 创建redis-cluster虚拟网卡
docker network create redis-cluster
1.2、修改redis.conf,依次修改6个redis的redis.conf,其他redis的配置类似,示例如下
# port(不同的redis对应各自的端口)
port 7379
# 支持集群模式
cluster-enabled yes
# 集群配置名 例nodes-7379.conf
cluster-config-file nodes-port.conf 
# 超时时间
cluster-node-timeout 5000
# 实际上各个网卡的ip(此字段一定要添加)
cluster-announce-ip 192.168.8.124
# 节点映射端口(不同的redis对应各自的端口)
cluster-announce-port 7379
# 节点总线端(不同的redis对应各自的端口)
cluster-announce-bus-port 17379
# 持久化模式打开
appendonly yes
# 保护模式关闭
protected-mode no
1.3、redis启动脚本restart.sh, redis的port和cluster-announce-bus-port一定要挂载出来,不同的redis修改不同的端口映射
# BEGIN ANSIBLE MANAGED BLOCK
#!/bin/bash
HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
docker rm -f redis_4.0.10_7379;
docker run --network redis-cluster  --name redis_4.0.10_7379 \
  --restart=always \
  -v $HOME/data:/data \
  -v $HOME/redis:/etc/redis \
  -p 7379:7379 \
  -p 17379:17379 \
  -d redis:4.0.10 \
  redis-server /etc/redis/redis.conf --appendonly yes
# END ANSIBLE MANAGED BLOCK
  • redis cluster需要6个节点,依次修改上述脚本,创建redis_4.0.10_7379、redis_4.0.10_7479、redis_4.0.10_7579、redis_4.0.10_7679、redis_4.0.10_7779、redis_4.0.10_7879
  • 此时6个redis已经创建完毕(如下图)


    14.png
2、redis集群创建
2.1、5.0.0以后版本
  • 进入到任一节点,执行脚本即可,集群即可创建成功
# 创建redis集群 -a ds123 -a 后面跟的redis密码
redis-cli -a 123456 --cluster create --replicas 1 192.168.8.124:7379 192.168.8.124:7479 192.168.8.124:7579 192.168.8.124:7679 192.168.8.124:7779 192.168.8.124:7879
2.2、5.0.0以前版本

由于redis还不支持--cluster参数,只能先安装ruby环境,然后进行集群创建

2.2.1、安装ruby环境
  • 目录文件如下


    15.png
  • redis-trib.rb 是从安装的redis包中拷贝出来的,一般在src目录下
2.2.2、创建镜像
  • Dockerfile 如下
FROM ruby:latest
MAINTAINER lss
RUN gem install redis
RUN mkdir /redis
WORKDIR /redis
ADD ./redis-trib.rb /redis/redis-trib.rb
# 根据Dockerfile创建镜像
docker build -t redis-trib .
2.2.3、restart.sh
# BEGIN ANSIBLE MANAGED BLOCK
#!/bin/bash
HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
docker rm -f redis-trib;
docker run -dit --network redis-cluster --name redis-trib \
  redis-trib:latest \
# END ANSIBLE MANAGED BLOCK
2.2.4、进入到redis-trib容器中,创建集群
# 进入容器
docker exec -it redis-trib bash
# 创建6个节点
ruby redis-trib.rb create --replicas 1 192.168.8.124:7379 192.168.8.124:7479 192.168.8.124:7579 192.168.8.124:7679 192.168.8.124:7779 192.168.8.124:7879
  • 日志如下


    16.png

    说明集群创建成功

3、集群测试
  • 进入任一redis节点中
# 进入7379节点
redis-cli -p 7379 -c
# 查看集群信息
127.0.0.1:7379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:388
cluster_stats_messages_pong_sent:405
cluster_stats_messages_sent:793
cluster_stats_messages_ping_received:400
cluster_stats_messages_pong_received:388
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:793
# 查看集群节点
127.0.0.1:7379> cluster nodes
f845f1dfed78a463342001e4ccfff5df2d187b3d 192.168.8.124:7679@17679 slave 636a42182b27edde6aee66bc5c8fac11df80336a 0 1594712726590 4 connected
cac8625b5ad4a665d9a5390bf994b3596ef818bf 192.168.8.124:7879@17879 slave 309dd80d9b1cc32fad37f29e4da0db825637df96 0 1594712725580 6 connected
636a42182b27edde6aee66bc5c8fac11df80336a 192.168.8.124:7379@17379 myself,master - 0 1594712726000 1 connected 0-5460
cb7887a912529e231610101a2e1c4eb5ffa571ad 192.168.8.124:7779@17779 slave da9fd04b8fb914ed297f5eb7689aec344f2982cd 0 1594712725000 5 connected
da9fd04b8fb914ed297f5eb7689aec344f2982cd 192.168.8.124:7479@17479 master - 0 1594712726000 2 connected 5461-10922
309dd80d9b1cc32fad37f29e4da0db825637df96 192.168.8.124:7579@17579 master - 0 1594712727601 3 connected 10923-16383
# 执行set操作,发现会重定向到对接节点的槽位
127.0.0.1:7379> set phone 17600000000
-> Redirected to slot [8939] located at 192.168.8.124:7479
OK
192.168.8.124:7479>
注意:本文创建的redis是不带密码的,如果redis设置密码,需要修改redis-trib.rb 文件或者把redis版本升级到5.0.0以上
4、集群扩容
4.1、5.0.0之后版本(本文使用的是5.0.0以下的版本,以上的类似,这里贴了使用命令)
# 扩容
1.
# 添加master节点
# 注意语法,一个新节点IP:端口 空格 一个旧节点IP:端口,注意点是:
# 1.不能多个新节点一次性添加
# 2.新节点后是旧节点
# 3.如果设置--cluster-slave,新节点挂在旧节点下的一个从节点
# 4.如果设置 --cluster-master-id <arg> ,arg设置旧节点的id,具体可以使用cluster nodes查看各个节点的id
# add-node new_host:new_port existing_host:existing_port  --cluster-slave  --cluster-master-id <arg>
# 此时 192.168.8.124:7979 为一个新的master节点
redis-cli --cluster add-node 192.168.8.124:7979 192.168.8.124:7379
2.
# 添加到从节点 此时192.168.8.124:8079 为 192.168.8.124:7979 的从节点
redis-cli --cluster add-node 192.168.8.124:8079 192.168.8.124:7979 --cluster-slave
这里是将节点加入了集群中,但是并没有分配slot,所以这个节点并没有真正的开始分担集群工作。
3.
# 这里是将节点加入了集群中,但是并没有分配slot,所以这个节点并没有真正的开始分担集群工作
# 分配slot
redis-cli --cluster reshard 192.168.8.124:7979 --cluster-from 2846540d8284538096f111a8ce7cf01c50199237,e0a9c3e60eeb951a154d003b9b28bbdc0be67d5b,692dec0ccd6bdf68ef5d97f145ecfa6d6bca6132 --cluster-to 46f0b68b3f605b3369d3843a89a2b4a164ed21e8 --cluster-slots 1024
--cluster-from:表示slot目前所在的节点的node ID,多个ID用逗号分隔
--cluster-to:表示需要新分配节点的node ID(貌似每次只能分配一个)
--cluster-slots:分配的slot数量
4. 
# 添加slave节点
redis-cli --cluster add-node 127.0.0.1:6386 127.0.0.1:6385 --cluster-slave --cluster-master-id 46f0b68b3f605b3369d3843a89a2b4a164ed21e8
add-node: 后面的分别跟着新加入的slave和slave对应的master
cluster-slave:表示加入的是slave节点
--cluster-master-id:表示slave对应的master的node ID
# 收缩
4、收缩集群
下线节点127.0.0.1:6385(master)/127.0.0.1:6386(slave)
1.
首先删除master对应的slave
redis-cli --cluster del-node 127.0.0.1:6386 530cf27337c1141ed12268f55ba06c15ca8494fc
del-node后面跟着slave节点的 ip:port 和node ID
2.
清空master的slot
redis-cli --cluster reshard 127.0.0.1:6385 --cluster-from 46f0b68b3f605b3369d3843a89a2b4a164ed21e8 --cluster-to 2846540d8284538096f111a8ce7cf01c50199237 --cluster-slots 1024 --cluster-yes
reshard子命令前面已经介绍过了,这里需要注意的一点是,由于我们的集群一共有四个主节点,而每次reshard只能写一个目的节点,因此以上命令需要执行三次(--cluster-to对应不同的目的节点)。
--cluster-yes:不回显需要迁移的slot,直接迁移。
3.
下线(删除)节点
redis-cli --cluster del-node 127.0.0.1:6385 46f0b68b3f605b3369d3843a89a2b4a164ed21e8
至此就是redis cluster 简单的操作过程
4.2、扩容 5.0.0版本之前
4.2.1 扩容
# 进入redis-trib容器
docker exec -it redis-trib bash
# 添加节点 192.168.8.124:7979为新节点,192.168.8.124:7379任一老节点都可以
ruby redis-trib.rb add-node 192.168.8.124:7979 192.168.8.124:7379
  • 添加完后进入任一redis实例中,查看集群节点,如下图


    17.png
  • 新节点7979现在已经连接上了集群, 成为集群的一份子, 并且可以对客户端的命令请求进行转向了, 但是和其他主节点相比, 新节点还有两点区别:
  1. 新节点没有包含任何数据, 因为它没有包含任何哈希槽.
  2. 尽管新节点没有包含任何哈希槽, 但它仍然是一个主节点, 所以在集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中。
  • 接下来, 只要使用 redis-trib 程序, 将集群中的某些哈希桶移动到新节点里面, 新节点就会成为真正的主节点了。
  • 分配哈希槽
# 给7979分配哈希槽
ruby redis-trib.rb reshard 192.168.8.124:7979

日志如下


19.png
  • 接下来输入yes就ok了,分配完成后,查看集群信息(如下图),此时已分配哈希槽
20.png
4.2.2 为192.168.8.124:7979添加从节点
# 添加从节点
# --slave 表明此时添加的是从节点  --master-id 后跟主节点id 
# 192.168.8.124:8079 192.168.8.124:7979 前面是新添加的从节点,后面为对应的主节点
ruby redis-trib.rb add-node --slave --master-id 8598e877be674cf31ce1bbf3bdb8cce0cb053482 192.168.8.124:8079 192.168.8.124:7979 
4.2.3 查看集群状态,此时已经多了从节点信息
21.png
5、集群缩容
5.1、使用del-node命令
# 删除从节点
# del-node host:port node_id
ruby redis-trib.rb del-node 192.168.8.124:8079 1ceb81491eace626d601fc0fcfdc569b8e4e896f
  • 此时,8079节点已从集群中移除
5.2、删除主节点
# 删除主节点,删除主节点之前,要将slots分配到其他主节点上
ruby redis-trib.rb reshard 192.168.8.124:7979
  • 日志如下图


    23.png
  • 7979节点中有4096个slots,直接输入4096,enter
5.3、选择接收的节点id,可以选择其他的主节点id

此时选择的是7379的主节点id,all为所有主节点,done:指定节点
可以把分配的过程理解成打扑克牌,

  • all表示大家重新洗牌;
  • 输入某个主节点的node id,然后在输入done的话,就好比从某个节点,抽牌

日志如下:


24.png
注意:此处与4.2.1分配类似
5.4、查看集群信息
25.png
5.5、删除主节点
# 删除主节点
ruby redis-trib.rb del-node 192.168.8.124:7979 8598e877be674cf31ce1bbf3bdb8cce0cb053482
5.6、进入其他的主节点,查看集群节点信息,发现已经没有7979节点
26.png
# 注意,如果中间重新分配slots时,出现错误

Please fix your cluster problems before resharding
执行脚本 ruby redis-trib.rb fix 192.168.8.124:7979,也出现错误时
[ERR] Calling MIGRATE: ERR Syntax error, try CLIENT (LIST | KILL | GETNAME | SETNAME | PAUSE | REPLY)

  • 找到对应的slots的节点
# 先执行flushall
127.0.0.1:6379> flushall
# 再执行bgsave
127.0.0.1:6379> bgsave
  • 再ruby redis-trib.rb fix 192.168.8.124:7979,如果还是报错
    打开redis-trib.rb
# 全局搜索source.r.client.call,替换为source.r.call,总共有2处
source.r.call
至此,redis集群已经配置完毕,当然还有很多功能需要继续完善,希望对你有所帮助!
一 、redis 主从模式、哨兵(sentinel) 配置、cluster(集群)联系与区别
二 、redis 主从模式
三 、redis sentinel(哨兵)模式
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342