redis集群

1  redis集群数据分片

Redis集群不同一致性哈希,它用一种不同的分片形式,在这种形式中,每个key都是一个概念性(hash slot)的一部分。

There are 16384 hash slots in Redis Cluster, and to compute what is the hash slot of a given key, we simply take the CRC16 of the key modulo 16384.

Redis集群中有16384个hash slots,为了计算给定的key应该在哪个hash slot上,我们简单地用这个key的CRC16值来对16384取模。(即:key的CRC16  %  16384)

Every node in a Redis Cluster is responsible for a subset of the hash slots

Redis集群中的每个节点负责一部分hash slots,假设你的集群有3个节点,那么:

  • Node A contains hash slots from 0 to 5500
  • Node B contains hash slots from 5501 to 11000
  • Node C contains hash slots from 11001 to 16383

允许添加和删除集群节点。比如,如果你想增加一个新的节点D,那么久需要从A、B、C节点上删除一些hash slot给到D。同样地,如果你想从集群中删除节点A,那么会将A上面的hash slots移动到B和C,当节点A上是空的时候就可以将其从集群中完全删除。

因为将hash slots从一个节点移动到另一个节点并不需要停止其它的操作,添加、删除节点以及更改节点所维护的hash slots的百分比都不需要任何停机时间。也就是说,移动hash slots是并行的,移动hash slots不会影响其它操作。

Redis支持多个key操作,只要这些key在一个单个命令中执行(或者一个事务,或者Lua脚本执行),那么它们就属于相同的hash slot。你也可以用hash tags俩强制多个key都在相同的hash slot中。

2 redis主从模式

 

In order to remain available when a subset of master nodes are failing or are not able to communicate with the majority of nodes, Redis Cluster uses a master-slave model where every hash slot has from 1 (the master itself) to N replicas (N-1 additional slaves nodes).

 

当部分master节点失败了,或者不能够和大多数节点通信的时候,为了保持可用,Redis集群用一个master-slave模式,这样的话每个hash slot就有1到N个副本。

 

在我们的例子中,集群有A、B、C三个节点,如果节点B失败了,那么5501-11000之间的hash slot将无法提供服务。然而,当我们给每个master节点添加一个slave节点以后,我们的集群最终会变成由A、B、C三个master节点和A1、B1、C1三个slave节点组成,这个时候如果B失败了,系统仍然可用。节点B1是B的副本,如果B失败了,集群会将B1提升为新的master,从而继续提供服务。然而,如果B和B1同时失败了,那么整个集群将不可用。

3 集群一致性保证

 

Redis Cluster is not able to guarantee strong consistency. In practical terms this means that under certain conditions it is possible that Redis Cluster will lose writes that were acknowledged by the system to the client.

 

Redis集群不能保证强一致性。换句话说,Redis集群可能会丢失一些写操作。The first reason why Redis Cluster can lose writes is because it uses asynchronous replication.

 

Redis集群可能丢失写的第一个原因是因为它用异步复制。

 

写可能是这样发生的:

 

  • 客户端写到master B
  • master B回复客户端OK
  • master B将这个写操作广播给它的slaves B1、B2、B3

 

正如你看到的那样,B没有等到B1、B2、B3确认就回复客户端了,也就是说,B在回复客户端之前没有等待B1、B2、B3的确认,这对应Redis来说是一个潜在的风险。所以,如果客户端写了一些东西,B也确认了这个写操作,但是在它将这个写操作发给它的slaves之前它宕机了,随后其中一个slave(没有收到这个写命令)可能被提升为新的master,于是这个写操作就永远丢失了。

 

这和大多数配置为每秒刷新一次数据到磁盘的情况是一样的。你可以通过强制数据库在回复客户端以前刷新数据,但是这样做的结果会导致性能很低,这就相当于同步复制了。

 

基本上,需要在性能和一致性之间做一个权衡。

 

如果绝对需要的话,Redis集群也是支持同步写的,这是通过WAIT命令实现的,这使得丢失写的可能性大大降低。然而,需要注意的是,Redis集群没有实现强一致性,即使用同步复制,因为总是有更复杂的失败场景使得一个没有接受到这个写操作的slave当选为新的master。however note that Redis Cluster does not implement strong consistency even when synchronous replication is used: it is always possible under more complex failure scenarios that a slave that was not able to receive the write is elected as master.

 

另一个值得注意的场景,即Redis集群将会丢失写操作,这发生在一个网络分区中,在这个分区中,客户端与少数实例(包括至少一个主机)隔离。

 

假设这样一个例子,有一个集群有6个节点,分别由A、B、C、A1、B1、C1组成,三个masters三个slaves,有一个客户端我们叫Z1。在分区发生以后,可能分区的一边是A、C、A1、B1、C1,另一边有B和Z1。此时,Z1仍然可用写数据到B,如果网络分区的时间很短,那么集群可能继续正常工作,而如果分区的时间足够长以至于B1在多的那一边被提升为master,那么这个时候Z1写到B上的数据就会丢失。

 

什么意思呢?简单的来说就是,本来三主三从在一个网络分区中,突然网络分区发生,于是一边是A、C、A1、B1、C1,另一边是B和Z1,这时候Z1往B中写数据,于此同时另一边(即A、C、A1、B1、C1)认为B已经挂了,于是将B1提升为master,当分区回复的时候,由于B1变成了master,所以B就成了slave,于是B就要丢弃它自己原有的数据而从B1那里同步数据,于是乎先去Z1写到B的数据就丢失了。

 

注意,有一个最大窗口,这是Z1能够向B写的最大数量:如果时间足够的话,分区的多数的那一边已经选举完成,选择一个slave成为master,此时,所有在少数的那一边的master节点将停止接受写。

 

也就说说,有一个最大窗口的设置项,它决定了Z1在那种情况下能够向B发送多数写操作:如果分隔的时间足够长,多数的那边已经选举slave成为新的master,此后少数那边的所有master节点将不再接受写操作。

 

在Redis集群中,这个时间数量是一个非常重要的配置指令,它被称为node timeout。在超过node timeout以后,一个master节点被认为已经失败了,并且选择它的一个副本接替master。类似地,如果在过了node timeout时间以后,没有一个master能够和其它大多数的master通信,那么整个集群都将停止接受写操作。

 

After node timeout has elapsed, a master node is considered to be failing, and can be replaced by one of its replicas. Similarly after node timeout has elapsed without a master node to be able to sense the majority of the other master nodes, it enters an error state and stops accepting writes.

4 集群参数配置

cluster-enabled <yes/no>:如果是yes,表示启用集群,否则以单例模式启动

cluster-config-file <filename>: 可选,这不是一个用户可编辑的配置文件,这个文件是Redis集群节点自动持久化每次配置的改变,为了在启动的时候重新读取它。

cluster-node-timeout <milliseconds>: 超时时间,集群节点不可用的最大时间。如果一个master节点不可到达超过了指定时间,则认为它失败了。注意,每一个在指定时间内不能到达大多数master节点的节点将停止接受查询请求。

cluster-slave-validity-factor <factor>:如果设置为0,则一个slave将总是尝试故障转移一个master。如果设置为一个正数,那么最大失去连接的时间是node timeout乘以这个factor。

cluster-migration-barrier <count>: 一个master和slave保持连接的最小数量(即:最少与多少个slave保持连接),也就是说至少与其它多少slave保持连接的slave才有资格成为master。

cluster-require-full-coverage <yes/no>:如果设置为yes,这也是默认值,如果key space没有达到百分之多少时停止接受写请求。如果设置为no,将仍然接受查询请求,即使它只是请求部分key。

5 创建集群:

首先使用rz命令上传redis的压缩包,或者下载

cd opt

mkdir redis-cluster

mkdir 7000 7001 7002 7003 7004 7005

cd 7000
touch redis.conf
cp 7000/redis.conf 7001/
cp 7000/redis.conf 7002/
cp 7000/redis.conf 7003/
cp 7000/redis.conf 7004/
cp 7000/redis.conf 7005/

 

cd /opt/redis-cluster
wget http://download.redis.io/releases/redis-4.0.14.tar.gz

tar -zxvf redis-4.0.14.tar.gz 

cd 7000

touch redis.conf

cd 7000
./redis-server 7000/redis.conf

cd 7001
./redis-server 7001/redis.conf 

cd 7002
./redis-server 7002/redis.conf 

cd 7003
./redis-server 7003/redis.conf 

cd 7004
./redis-server 7004/redis.conf

 

加上以下最简单的配置:

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

然后各个修改端口

再执行

 cp redis-4.0.14/src/redis-server 7000

再各自启动redis

./redis-server redis.conf

查看启动情况

 netstat -tnlp |grep 700

 

 安装ruby脚本

yum install ruby
yum install rubygems
gem install redis

 在安装可能会报错

 

升级ruby脚本

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
source /etc/profile.d/rvm.sh
rvm list known
rvm install 2.4.1

创建redis集群:

./redis-trib.rb create --replicas 1 127.0.0.1:7000 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

 

 

redis集群停止,之前我们创建集群用的是redis-trib,现在我们用create-cluster来创建集群。

进入utils/create-cluster,可以看README

create-cluster start

create-cluster create

 

posted @ 2019-05-05 22:10  菩提树下的丁春秋  阅读(196)  评论(0编辑  收藏  举报