redis系列(7):redis 集群

RedisCluster 是 redis 的分布式解决方案,在 3.0 版本后推出的方案,有效地解决了 Redis 分布式的需求,当遇到单机内存、并发等瓶颈时,可使用此方案来解决这些问题

1 分布式数据库概念:
1,分布式数据库把整个数据按分区规则映射到多个节点,即把数据划分到多个节 点上,每个节点负责整体数据的一个子集 比如我们库有 900 条用户数据,有 3 个 redis 节点,将 900 条分成 3 份,分别存入 到 3个 redis 节点

2,分区规则:

常见的分区规则哈希分区和顺序分区,redis 集群使用了哈希分区,顺序分区暂 用不到,不做具体说明;

rediscluster 采用了哈希分区的“虚拟槽分区”方式(哈希分区分节点取余、一 900 条数据 分区规则 redis-1 redis-2 redis-3致性哈希分区和虚拟槽分区),其它两种也不做介绍,有兴趣可以百度了解一下。

3,虚拟槽分区(槽:slot)

RedisCluster 采用此分区,所有的键根据哈希函数(CRC16[key]&16383)映射到 0 -16383 槽内,共 16384 个槽位,每个节点维护部分槽及槽所映射的键值数据

哈希函数: Hash()=CRC16[key]&16383 按位与

槽与节点的关系如下

redis 用虚拟槽分区原因:1,解耦数据与节点关系,节点自身维护槽映射关系,分布式存储

4,redisCluster 的缺陷:

a,键的批量操作支持有限,比如 mset, mget,如果多个键映射在不同的槽, 就不支持了

b,键事务支持有限,当多个 key 分布在不同节点时无法使用事务,同一节点 是支持事务

c,键是数据分区的最小粒度,不能将一个很大的键值对映射到不同的节点

d,不支持多数据库,只有 0,select 0 e,复制结构只支持单层结构,不支持树型结构。

2 集群环境搭建:

1,在/usr/local/bin/clusterconf 目录

6389 为 6379 的从节点,6390 为 6380 的从节点,6391 为 638

2,分别修改 6379、 6380、 7381、 6389、 6390、 6391 配置文件

port 6379 //节点端口

cluster-enabled yes //开启集群模式

cluster-node-timeout 15000 //节点超时时间(接收pong消息回复的时间)

cluster-config-file /usrlocalbin/cluster/data/nodes-6379.conf 集群内部配置文件 其它节点的配置和这个一致,改端口即可

3,配置完后,启动 6 个 redis 服务

4,自动安装模式: 在/usr/local 新建目录:ruby

下载链接:https://pan.baidu.com/s/1kWsf3Rh 密码:n3pc

从这个链接下载 ruby-2.3.1.tar.gz 和 redis-3.3.0.gem

tar -zxvf ruby-2.3.1.tar.gz

a, cd ruby-2.3.1

b, ./configure -prefix=/usr/local/ruby

c, make && make install //过程会有点慢,大概 5-10 分钟

d, 然后 gem install -l redis-3.3.0.gem //没有 gem 需要安装 yum install gem

e, 准 备 好 6 个 节 点 ,( 注 意 不 要 设 置 requirepass ) , 将 /usr/local/bin/clusterconf/data 的 config-file 删 除 ; 依 次 启 动 6 个 节 点:./redis-server clusterconf/redis6379.conf 如果之前 redis 有数据存在,flushall 清空;(坑:不需要 cluster meet ..)

f, 进入 cd /usr/local/bin, 执行以下:1 代表从节点的个数 ./redis-trib.rb create --replicas 1 192.168.0.111:6379 192.168.0.111:6380 192.168.0.111:6381 192.168.0.111:6389 192.168.0.111:6390 192.168.0.111:6391

主从分配,6379 是 6389 的从节点

貌似只有主节点可读写,从节点不可以

主节点死后,从节点变成主节点

e,集群健康检测: redis-trib.rb check 192.168.42.111:6379 (注:redis 先去注释掉 requirepass,不然 连不上)

如此出现了这个问题,6379 的 5798 槽位号被打开了

解决如下:

6379,6380,6381 的有部分槽位被打开了,分别进入这几个节点,执行

6380:>cluster setslot 1180 stable cluster setslot 2998 stable cluster setslot 11212 stable

其它也一样,分别执行修复完后:

 

此时修复后的健康正常;

当停掉 6379 后,过会 6389 变成主节点

注意:使用客户端工具查询时要加-c

./redis-cli -h 192.168.42.111 -p 6379 -c mset aa bb cc dd,批设置对应在不同的 solt 上,缺点

14,集群正常启动后,在每个 redis.conf 里加上

masterauth “12345678”

requiredpass “12345678”

当主节点下线时,从节点会变成主节点,用户和密码是很有必要的,设置成一致

15,这上面是一主一从,那能不能一主多从呢?

./redis-trib.rb create --replicas 2

192.168.42.111:6379 192.168.42.111:6380 192.168.42.111:6381

192.168.42.111:6479 192.168.42.111:6480 192.168.42.111:6481

192.168.42.111:6579 192.168.42.111:6580 192.168.42.111:6581

3 节点之间的通信

1,节点之间采用 Gossip 协议进行通信,Gossip 协议就是指节点彼此之间不断 通信交换信息

当主从角色变化或新增节点,彼此通过 ping/pong 进行通信知道全部节点的最新状 态并达到集群同步

2,Gossip 协议

Gossip 协议的主要职责就是信息交换,信息交换的载体就是节点之间彼此发送 的 Gossip 消息,常用的 Gossip 消息有 ping 消息、pong 消息、meet 消息、fail 消息
 

 

meet 消息:用于通知新节点加入,消息发送者通知接收者加入到当前集群,meet 消息通信完后,接收节点会加入到集群中,并进行周期性 ping pong 交换

ping 消息:集群内交换最频繁的消息,集群内每个节点每秒向其它节点发 ping 消 息,用于检测节点是在在线和状态信息,ping 消息发送封装自身节点和其他节点的状态 数据;

pong 消息,当接收到 ping meet 消息时,作为响应消息返回给发送方,用来确认正 常通信,pong 消息也封闭了自身状态数据;

fail 消息:当节点判定集群内的另一节点下线时,会向集群内广播一个 fail 消息, 后面会讲到。……

3,消息解析流程

所有消息格式为:消息头、消息体,消息头包含发送节点自身状态数据(比如节点 ID、槽映射、节点角色、是否下线等),接收节点根据消息头可以获取到发送节点的相 关数据。

消息解析流程:

4,选择节点并发送 ping 消息:

Gossip 协议信息的交换机制具有天然的分布式特性,但 ping pong 发送的频率很 高,可以实时得到其它节点的状态数据,但频率高会加重带宽和计算能力,因此每次都 会有目的性地选择一些节点; 但是节点选择过少又会影响故障判断的速度,redis 集群 的 Gossip 协议兼顾了这两者的优缺点,看下图:

不难看出:节点选择的流程可以看出消息交换成本主要体现在发送消息的节点数量 和每个消息携带的数据量

流程说明:

A,选择发送消息的节点数量:集群内每个节点维护定时任务默认为每秒执行 10 次,每秒会随机选取 5 个节点,找出最久没有通信的节点发送 ping 消息,用来 保证信息交换的随机性,每 100 毫秒都会扫描本地节点列表,如果发现节点最近 一次接受 pong 消息的时间大于 cluster-node-timeout/2 则立刻发送 ping 消息,这 样做目的是防止该节点信息太长时间没更新,当我们宽带资源紧张时,在可 redis.conf 将 cluster-node-timeout 15000 改成 30 秒,但不能过度加大

B,消息数据:节点自身信息和其他节点信息

 

5,集群扩容

这也是分布式存储最常见的需求,当我们存储不够用时,要考虑扩容 扩容步骤如下:

A,准备好新节点

B,加入集群,迁移槽和数据

1),同目录下新增 redis6382.conf、redis6392.conf 两 启动两个新 redis 节点

./redis-server clusterconf/redis6382.conf & (新主节点)

./redis-server clusterconf/redis6392.conf & (新从节点)

2),新增主节点 ./redis-trib.rb add-node 192.168.42.111:6382 192.168.42.111:6379 6379 是原存在的主节点,6382 是新的主节点

3),添加从节点

redis-trib.rb add-node --slave --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.42.111:6392 192.168.42.111:6379

--slave,表示添加的是从节点

--master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2 表示主节点 6382 的 master_id 192.168.42.111:6392,新从节点

192.168.42.111:6379 集群原存在的旧节点

4),redis-trib.rb reshard 192.168.42.111:6382 //为新主节点重新分配 solt How many slots do you want to move (from 1 to 16384)? 1000 //设置 slot 数 1000 What is the receiving node ID? 464bc7590400441fafb63f2 //新节点 node id Source node #1:all //表示全部节点重新洗牌

新增完毕!

 

3,集群减缩节点:

集群同时也支持节点下线掉

下线的流程如下:
 

流程说明:

A,确定下线节点是否存在槽 slot,如果有,需要先把槽迁移到其他节点,保证整个 集群槽节点映射的完整性;

B,当下线的节点没有槽或本身是从节点时,就可以通知集群内其它节点(或者叫忘 记节点),当下线节点被忘记后正常关闭。

删除节点也分两种:

一种是主节点 6382,一种是从节点 6392。

在从节点 6392 中,没有分配哈希槽,执行 ./redis-trib.rb del-node 192.168.42.111:6392 7668541151b4c37d2d9 有两个参数 ip:port 和节点的 id。 从节点 6392 从集群中删除了。

主节点 6382 删除步骤: 1,./redis-trib.rb reshard 192.168.42.111:6382 问我们有多少个哈希槽要移走,因为我们这个节点上刚分配了 1000 个所以我们这里输入 1000

2,最后

./redis-trib.rb del-node 192.168.42.111:6382 3e50c6398c75e0088a41f908071c2c2eda1dc900

此时节点下线完成……

请求路由重定向

我们知道,在 redis 集群模式下,redis 接收的任何键相关命令首先是计算这个键 CRC值,通过 CRC 找到对应的槽位,再根据槽找到所对应的 redis 节点,如果该节点是 本身,则直接处理键命令;如果不是,则回复键重定向到其它节点,这个过程叫做 MOVED 重定向

故障转移:

redis 集群实现了高可用,当集群内少量节点出现故障时,通过故障转移可以保证集群 正常对外提供服务。

当集群里某个节点出现了问题,redis 集群内的节点通过 ping pong 消息发现节点是否健 康,是否有故障,其实主要环节也包括了 主观下线和客观下线;

主观下线:指某个节点认为另一个节点不可用,即下线状态,当然这个状态不是最终的 故障判定,只能代表这个节点自身的意见,也有可能存在误判;

下线流程:

A,节点 a 发送 ping 消息给节点 b ,如果通信正常将接收到 pong 消息,节点 a 更新 最近一次与节点 b 的通信时间;

B,如果节点 a 与节点 b 通信出现问题则断开连接,下次会进行重连,如果一直通 信失败,则它们的最后通信时间将无法更新;

C,节点a内的定时任务检测到与节点b最后通信时间超过cluster_note-timeout时, 更新本地对节点 b 的状态为主观下线(pfail)

客观下线:指真正的下线,集群内多个节点都认为该节点不可用,达成共识,将它下线, 如果下线的节点为主节点,还要对它进行故障转移

假如节点 a 标记节点 b 为主观下线,一段时间后节点 a 通过消息把节点 b 的状态发 到其它节点,当节点 c 接受到消息并解析出消息体时,会发现节点 b 的 pfail 状态时, 会触发客观下线流程;

当下线为主节点时,此时 redis 集群为统计持有槽的主节点投票数是否达到一半, 当下线报告统计数大于一半时,被标记为客观下线状态。

故障恢复:

故障主节点下线后,如果下线节点的是主节点,则需要在它的从节点中选一个替换 它,保证集群的高可用;转移过程如下:

1,资格检查:检查该从节点是否有资格替换故障主节点,如果此从节点与主节点断开过通信,那么当前从节点不具体故障转移;

2,准备选举时间:当从节点符合故障转移资格后,更新触发故障选举时间,只有 到达该时间后才能执行后续流程;

3,发起选举:当到达故障选举时间时,进行选举;

4,选举投票:只有持有槽的主节点才有票,会处理故障选举消息,投票过程其实 是一个领导者选举(选举从节点为领导者)的过程,每个主节点只能投一张票给从节点, 当从节点收集到足够的选票(大于 N/2+1)后,触发替换主节点操作,撤销原故障主节点的 槽,委派给自己,并广播自己的委派消息,通知集群内所有节点.
 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值