Redis 集群是Redis 的一个分布式实现,它是一个网状结构,每一个节点都经过 TCP 链接跟其余每一个节点链接。如今来看看Redis集群实现了哪些目标?node
那么Redis集群环境与非分布式Redis环境在功能上有没有什么不一样的呢?git
在进入集群环境搭建时,先介绍集群的一些基本概念,例如节点、槽等等。github
节点(node)能够说是构成集群的基本元素.一般一个Redis集群中包含了多个节点,每一个节点都有一个惟一的名字。redis
节点名字是一个十六进制表示的160 bit 随机数,这个随机数是节点第一次启动时得到的(一般是用 /dev/urandom)。 节点会把它的ID保存在配置文件里,之后永远使用这个ID.若是想要更换ID有以下两种方式:算法
CLUSTER RESET
命令。那么这个节点ID有什么用处呢?数据库
节点ID是用于每一个节点。经过节点ID能够检测到节点 IP 或端口的变化。centos
若是节点发生了 IP 或端口变化时,其余节点是如何得知的呢?安全
集群会使用gossip 协议来发布广播消息,通知配置变动。ruby
节点与节点之间知道对方的哪些信息?bash
节点的 IP 地址和 TCP 端口号。
若是该节点是从节点,会有主节点ID信息。(若是它是个主节点则该信息置为0000000…)
咱们能够经过使用CLUSTER NODES
命令能够得到以上的一些信息,以下
Redis集群经过分片的方式来保存数据库中的键值对:整个键空间被分割为 16384 槽(slot),每一个键都将存放在 16384 槽(slot)的其中一个位置上。
那么是什么决定一个键所存放的位置呢?
下方就是计算键存放的位置的算法。
HASH_SLOT = CRC16(key) mod 16384
经过CRC16算法获取键的16位输出结果,而后再对 16384 取余,结果就是键所在的位置。
既然整个键空间被分割为 16384 槽(slot),那么是如何将这些槽分配给不一样的节点的?
能够经过如下命令将槽分片
CLUSTER ADDSLOTS slot1 [slot2] … [slotN]
本文搭建的集群环境有3个主节点,每一个主节点都有两个从节点,架构图以下
关于集群的配置以下
################################ REDIS CLUSTER ############################### cluster-enabled yes cluster-config-file nodes-6379.conf cluster-node-timeout 5000
cluster-enabled
表示是否开启集群模式
cluster-conf-file
表示保存节点配置文件的路径
cluster-node-timeout
表示节点超时时间
完整的配置文件在https://github.com/rainbowda/learnWay/tree/master/learnRedis/cluster ,有须要的能够去下载
因为采用一个服务器运行三个Redis实例,因此每一个节点的配置有些许不一样,像端口号、文件位置、文件名称等等。这里就不将每一个配置文件贴出来了,Github上有主节点和两个从节点的配置文件。
我在redis文件夹下建立一个cluster文件夹,而后在cluster文件夹下建立一个master文件,存放主节点的配置文件master.conf和一些其余文件;再而后建立两个从节点文件7001和7002,也是存放配置文件等。
mkdir cluster cd cluster mkdir master 7001 7002
将配置文件拷贝到相应文件夹后,根据配置文件启动Redis,这里就不在说明了。
咱们已经有九个正在运行中的 Redis 实例 ,接下来须要使用这些实例来建立集群 。Redis中提供集群命令行工具 redis-trib 来简化集群操做
在执行redis-trib.rb文件以前须要安装ruby环境,嫌麻烦能够直接运行下面命令
yum install centos-release-scl-rh yum install rh-ruby23 -y scl enable rh-ruby23 bash gem install redis
注:若是直接运行
yum install ruby
命令时,再运行gem install redis
会显示redis requires Ruby version >= 2.2.2
错误
执行命令以下
./redis-trib.rb create --replicas 2 192.168.17.101:6379 192.168.17.102:6379 192.168.17.103:6379 192.168.17.101:7001 192.168.17.101:7002 192.168.17.102:7001 192.168.17.102:7002 192.168.17.103:7001 192.168.17.103:7002
命令中的create表示建立集群 ,参数 replicas表示须要一个主节点有几个从节点 ,后面就是节点ip和端口号。
命令执行后,会输出已下内容,内容里面包括主从节点的信息
接下来须要用户输入yes确认
输入yes后, redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通信,最后能够获得以下信息:
当输出已下内容时,表示集群环境已经搭建好了
[OK] All 16384 slots covered
接下来输入cluster info
命令看看集群状态,输出的结果以下
在使用redis-trib建立集群时,咱们并不知道其内部发生了什么,接下来我将简单介绍下其过程。
yes
确认分配方案。yes
以后,便开始执行分配方案。大体的过程如上,接下来介绍下cluster meet 命令
在没有使用 CLUSTER MEET 命令时,每一个节点都是相互独立的, 它们都处于一个只包含本身的集群当中,经过使用 CLUSTER MEET 命令能够将各个独立的节点链接起来, 构成一个包含多个节点的集群 。使用 CLUSTER MEET 命令的格式以下
CLUSTER MEET <ip> <port>
看看这个命令的实现
场景:有A(192.168.17.101)和B(192.168.17.102)两个节点,在B节点的客户端输入CLUSTER MEET 192.168.17.101 6379
,表示B加入到A所在的集群中。A收到命令后便开始执行如下步骤
节点的握手过程以下
这里将模拟一个主节点故障,经过向主节点发送DEBUG SEGFAULT 命令来实现主节点故障效果。
在主节点101上执行DEBUG SEGFAULT命令以后,到103客户端上查看节点状态
能够从上图中看出101主节点多了个fail状态,并且103的一个从节点7001变成了主节点。如今再让101从新上线,再次查看状态
能够看到以前的101主节点变成了从节点。好了接下来看看集群是怎么发现故障及故障如何转移的。
集群是经过什么方式来发现某个节点出现故障?
答:能够分为以下几个步骤.
定义:发送PING消息的节点-->节点A;接受PING消息的节点-->节点B
NODE_TIMEOUT
时间内返回PONG消息,那么节点A会将B节点标记为PFAIL** (疑似下线状态)NODE_TIMEOUT *FAIL_REPORT_VALIDITY_MULT
这个时间内是处于 PFAIL 状态。那么节点A会标记节点 B 为 FAIL (已下线状态)。故障转移步骤:
下线主节点的全部从节点,会有一个从节点被选中。
被选中的从节点会执行SLAVEOF no one
命令,成为新的主节点
新的主节点会撤销全部对已下线主节点的槽指派,并将这些槽所有指派给本身。
新的主节点向集群广播一条PONG消息,这条消息可让集群中的其余节点当即知道这个节点已经由从节点变成了主节点,而且这个主节点已经接管了本来由已下线节点负责处理的槽。
新的主节点开始接收和本身负责处理的槽有关的命令请求,故障转移完成。
如下就是发生故障出现日志内容
2169:M 31 Jul 21:06:20.873 * Marking node 3c29beb7984b40a8c19b580362a0daf29dc349fb as failing (quorum reached). 2169:M 31 Jul 21:06:20.873 # Cluster state changed: fail 2169:M 31 Jul 21:06:21.546 # Failover auth granted to aba761321b40112c0b8de29d810767a40c59d27b for epoch 10 2169:M 31 Jul 21:06:21.586 # Cluster state changed: ok 2169:M 31 Jul 21:13:05.849 * Clear FAIL state for node 3c29beb7984b40a8c19b580362a0daf29dc349fb: master without slots is reachable again.
这篇文章主要介绍集群搭建和故障检测转移,固然集群中还有其余知识点像MOVED 重定向、ASK 重定向和从新分片等功能,这些功能官方文档都有相应的资料。
Redis官网:https://redis.io
Redis中文网:http://www.redis.cn
本篇的集群配置文件:https://github.com/rainbowda/learnWay/tree/master/learnRedis/cluster