Redis 本身是软件工程师,进入互联网公司的门票,了解有关Redis Cluster的算法和设计原理的信息,高可用集群管理 API,容错处理、故障转移,是非常有必要的。本文对此进行记录

承接上文,我们完成了 Redis Cluster 集群的搭建,三主三从,部署在三台服务器上,使用的 Redis 版本为 5.0.9

集群简述

  • 由多个Redis服务器组成的分布式网络服务集群
  • 集群之中有多个Master主节点,每一个主节点都可读可写
  • 节点之间会互相通信,两两相连
  • Redis集群无中心节点

缺点



  • Redis Cluster是无中心节点的集群架构,依靠Goss协议(谣言传播)协同自动化修复集群的状态.

但 GosSIp有消息延时和消息冗余的问题,在集群节点数量过多的时候,节点之间需要不断进行 PING/PANG通讯,不必须要的流量占用了大量的网络资源。虽然Reds4.0对此进行了优化,但这个问题仍然存在。


  • 数据迁移问题

Redis Cluster可以进行节点的动态扩容缩容,这一过程,在目前实现中,还处于半自动状态,需要人工介入。在扩缩容的时候,需要进行数据迁移。
而 Redis为了保证迁移的一致性,迁移所有操作都是同步操作,执行迁移时,两端的 Redis均会进入时长不等的阻塞状态,对于小Key,该时间可以忽略不计,但如果一旦Key的内存使用过大,严重的时候会接触发集群内的故障转移,造成不必要的切换。

集群节点复制

在Redis-Cluster集群中,可以给每一个主节点添加从节点,主节点和从节点直接遵循主从模型的特性

当用户需要处理更多读请求的时候,添加从节点可以扩展系统的读性能

故障转移

Redis集群的主节点内置了类似Redis Sentinel的节点故障检测和自动故障转移功能,当集群中的某个主节点下线时,集群中的其他在线主节点会注意到这一点,并对已下线的主节点进行故障转移

集群进行故障转移的方法和Redis Sentinel进行故障转移的方法基本一样,不同的是,在集群里面,故障转移是由集群中其他在线的主节点负责进行的,所以集群不必另外使用Redis Sentinel

集群分片策略

Redis-cluster分片策略,是用来解决key存储位置的

集群将整个数据库分为16384个槽位slot,所有key-value数据都存储在这些slot中的某一个上。一个slot槽位可以存放多个数据,key的槽位计算公式为:slot_number=crc16(key)%16384,其中crc16为16位的循环冗余校验和函数。

集群中的每个主节点都可以处理0个至16383个槽,当16384个槽都有某个节点在负责处理时,集群进入上线状态,并开始处理客户端发送的数据命令请求

集群redirect转向

由于Redis集群无中心节点,请求会随机发给任意主节点

主节点只会处理自己负责槽位的命令请求,其它槽位的命令请求,该主节点会返回客户端一个转向错误

客户端根据错误中包含的地址和端口重新向正确的负责的主节点发起命令请求

集群常用命令

redis5.0版本之后可以直接使用redis-cli命令,之前是 使用 redis-trib.rb , 也就是 ruby, so 其实官方也提供了一些说明:

# 查看 redis-cli集群命令帮助

/usr/local/redis-cluster/bin/redis-cli --cluster help

Cluster Manager Commands:
  create         host1:port1 ... hostN:portN
                 --cluster-replicas <arg>
  check          host:port
                 --cluster-search-multiple-owners
  info           host:port
  fix            host:port
                 --cluster-search-multiple-owners
  reshard        host:port
                 --cluster-from <arg>
                 --cluster-to <arg>
                 --cluster-slots <arg>
                 --cluster-yes
                 --cluster-timeout <arg>
                 --cluster-pipeline <arg>
                 --cluster-replace
  rebalance      host:port
                 --cluster-weight <node1=w1...nodeN=wN>
                 --cluster-use-empty-masters
                 --cluster-timeout <arg>
                 --cluster-simulate
                 --cluster-pipeline <arg>
                 --cluster-threshold <arg>
                 --cluster-replace
  add-node       new_host:new_port existing_host:existing_port
                 --cluster-slave
                 --cluster-master-id <arg>
  del-node       host:port node_id
  call           host:port command arg arg .. arg
  set-timeout    host:port milliseconds
  import         host:port
                 --cluster-from <arg>
                 --cluster-copy
                 --cluster-replace
  help           

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

创建集群

redis-cli --cluster create host1:port1 ... hostN:portN --cluster-replicas

举个栗子

redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1

host1:port1 ... hostN:portN表示的是要添加的集群的节点IP和端口,
--cluster-replicas 表示的是主从节点比例,参数1表示前三个是主节点,后三个是从节点
也就是说7001,7002,7003端口对应的节点是主节点,7004,7005,7006对应的节点是从节点

查询集群节点信息

redis-cli -c -p 7001 cluster nodes

说明:以下的操作均是以上面这个为参数示例

给集群添加一个新主节点

redis-cli --cluster add-node new_host:new_port existing_host:existing_port --cluster-master-id node_id

举个栗子

redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7003 --cluster-master-id bbe8b7035bfd31c47bec7d612acc112cd2869368

new_host:new_port为要新添加的主节点IP和端口,此处是127.0.0.1:7007
existing_host:existing_port表示的是已存在的最后一个主节点的IP和端口,这个可以从上述的节点信息中查看到,根据slots槽数,7003端口对应的节点槽数是10923-16383,16383表示的是最后的槽数
--cluster-master-id表示的是最后一个主节点的节点id,表示的是新添加的主节点要在这个节点后面

再次查看集群信息

redis-cli -c -p 7001 cluster nodes

会发现7007端口对应的节点已经加入到集群中,是主节点,但是没有从节点,也没有分配槽数

给新添加的主节点分配slots槽数

redis-cli --cluster reshard host:port --cluster-from node_id --cluster-to node_id --cluster-slots 500 --cluster-yes

举个栗子

redis-cli --cluster reshard 127.0.0.1:7007 --cluster-from 4dad696ede24995a57c5fd790faa95c72c187a22 --cluster-to 7020c8df9423686727783c60bd2f0e367634ba84 --cluster-slots 500

host:port表示的是新添加的那个主节点IP和端口,此处表示的是127.0.0.1:7007
--cluster-from node_id表示的是集群第一个主节点的节点id,这个可以现有集群的slots槽数分配看出,此处表示的是7001端口对应的节点
--cluster-to node_id表示的是集群最后一个主节点的节点id,也就是新添加的那个主节点id,此处表示的是7007端口对应的节点
--cluster-slots 500表示的是给新主节点分配多少,此处500表示是分配从0-499个slots槽数,若不加上这个会让手动输入
--cluster-yes表示的是自动应答为yes,若不加上这个会让手动输入yes,表示同意此次分配

再次查看集群信息

/redis-cli -c -p 7001 cluster nodes

会发现7007端口对应的主节点已经有slots槽数了,并且是从0开始的

给集群中某个主节点再添加一个从节点

redis-cli --cluster add-node new_host:new_port existing_host:existing_port --cluster-slave --cluster-master-id node_id

举个栗子

redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7008 --cluster-slave --cluster-master-id 7020c8df9423686727783c60bd2f0e367634ba84

new_host:new_port表示的是要添加的那个从节点的IP和端口,此处表示的是127.0.0.1:7008
existing_host:existing_port表示的是要给哪个主节点添加从节点,此处表示的是127.0.0.1:7007
--cluster-slave表示的是要添加从节点,否则则是添加主节点了
--cluster-master-id node_id表示要给哪个主节点添加从节点的该主节点节点id

再次查看集群信息

redis-cli -c -p 7001 cluster nodes

会发现7008端口对应的节点已经是7007端口对应的从节点

从集群中删除一个从节点

redis-cli --cluster del-node host:port node_id

举个栗子

redis-cli --cluster del-node 127.0.0.1:7008 415db07121ba946b202bca98e15cbdffc60bc18a

host:port表示的是要删除的那个节点的IP和端口,此处是127.0.0.1:7008
node_id表示的是删除的那个节点的节点id