Redis集群配置

来源:互联网 发布:心脏 知乎 编辑:程序博客网 时间:2024/06/06 05:31

Redis集群向导

  本文不打算介绍复杂的分布式系统的概念,而仅作为一个入门介绍。旨在从用户的角度提供如何进行redis的配置,测试和操作。详细的配置参照https://redis.io/topics/cluster-spec。 下面就以易于理解的方式向用户介绍Redis的可用性和持久性,版本要求3.0或者更高。想要创建一个在开发环境中运行的正式的redis服务器最好阅读更详细的文档,但该文可以作为一个hello world用来学习。

1.Redis的基本特性

1.1 redis-cluster中的数据可分布在各个节点

1.2 redis-cluster提供了一定程度的可用性,如果部分节点宕机或者连接不上,集群仍可以继续操作。但如果大部分节点宕机(即半数以上的主节点宕机),那么集群的操作失效。

上面的两个特性,使得redis具有如下的能力:

1)自动把数据(空间)分布在多个节点

2)在部分节点失效时,自动切换,使得系统继续正常运行。

2.Redis集群的TCP端口

  提供了两个端口,一个是面向client的基本端口,另一个是用户集群节点间的通信端口。如6379是基本端口,加上10000,即16379是通信端口。这个通信端口在节点间传输二进制数据,可用于生效检测,同步更新,故障切换等。两个端口间的间隔总是10000,且防火墙需要放行这两个端口。

Redis集群正常运行需要每个节点:

1)把基本端口暴露给所有客户端和其他节点

2)把通信端口暴露给其他节点

  当且只有满足上面两个条件,集群才能正常工作。特别地,之所以通信端口使用二进制协议来进行节点间的信息交换,是因为这样占据较少的带宽和处理的时间。

3.Redis和Docker

  当前的Redis还不支持NAT以及IP地址/端口被映射的环境。而Docker(一种类似虚拟机的容器,比虚拟机架构要简化一点),它的默认机制是使用端口映射,因此是不支持redis的,为了支持Redis集群,可以配置模式为桥接模式(虚拟机也有这种模式)。

4.Redis数据分片

  Redis集群不使用一致性hash,而是采用hash槽,一个key在某种意义上可以理解为某个hash槽的一部分。集群中一共有16284个hash槽,系统采用对key采用CRC16校验,然后对16384取模的方法来决定放入哪一个槽。

每个节点负责一部分hash槽,比如共有三个节点,A,B,C

A:负责0-5000hash槽

B:负责5501-11000hash槽

C:负责11001-16383hash槽

  这种做法使得节点的迁移更简单,如需添加节点D,只要从ABC中迁移部分槽到D,如需删除A节点,只需把A的hash槽迁移到BC。由于这种hash槽迁移不影响数据的存取,所有无论添加删除亦或是调节槽的分配比例,都不需要宕机时间。

  Redis集群支持多个key操作,只要一个命令中的所有key(使用整个事务或者LUA脚本)属于同一个hash槽。如何保证所有key属于同一个hash槽?需要使用hash tags的概念。hash tags在Redis Cluster specification有说明,要点就是如果key中有一对大括号{}包含的子字符串,那只有这一部分会用来进行hash计算。因此比如this{foo}key 和 another{foo}key 会保证使用同一个hash槽,也就可以在一个命令一起使用多个key来作为参数。

5.Redis主从模式

  为了保证当主服务器的一部分失败会无法和集群的大部分节点通讯后能保持可用性,Redis集群使用主-从模式,就是每一个哈希槽都有1(主服务器自己)到N分复制(N-1个额外的从节点)在我们的有节点A,B,C的集群例子中,如果B失败了那集群就无法继续使用了,因为我们无法在处理在范围5501-11000之间的哈希槽的数据了。然而当集群创建的时候(或后续的时间),我们对每一个主服务器增加一个从服务器,因此集群最终会包含A,B,C的主节点,和A1,B1,C1的从节点,这样当节点B失败后系统还可以继续使用。节点B1复制B,如果B失败,集群会提升节点B1最为新的主服务器然后继续正确的执行。然而注意到如果B和B1同时失败了,那Redis集群就无法继续执行了。

6.Redis集群的一致性保证

  Redis集群无法保证强一致性,在实际情况中意味着在特定的条件下Redis集群可能会丢失一些系统已经向客户端承认的写操作。Redis集群会丢失写操作的第一个原因是Redis使用异步复制,这意味着下面过程中出现的写:
1)客户端写向B
2)B返回OK到客户端
3)B将写传播到B1,B2,B3

  你可以看到B并不会等待来自B1,B2,B3的响应后才对客户端响应,因为这对Redis来说是禁止的延迟。所以如果你的客户端写了一些东西,B也响应了这些写,但是在将这些写发送到从服务器之前宕机的话,其中的一个从服务器(还没有接收到写操作)会被提升为主服务器,之前的写也就丢失了。这和对于配置成每秒刷新数据到硬盘的数据库的情况是类似的,因此这个场景是已经可以意识到的,而过去传统的数据库系统并没有涉及到分布式系统。类似的你也可以通过迫使数据库在响应客户端之前将数据刷新到硬盘中来提高一致性,但是这通常会造成无法接受的低性能的结果。这和如果Redis集群采用同步复制是一样的。

  基本上这是一个在性能和一致性之间的权衡。Redis集群当在绝对需要的时候也支持同步写,通过WAIT命令实现,这样使得写丢失基本不能发生了,然而注意到Redis集群即使是采用当同步复制也没有实现强一致性:有可能会出现更复杂的失败场景,比如一个从服务器被选为主服务器后无法接受写请求。

  这里有另一个著名的场景Redis集群会丢失写,这发生在当客户端和少部分的Redis实例,这里面至少包含一个主服务器,被隔断到一个网络区间时。看下有6个节点:A,B,C,A1,B1,C1的集群例子,3个主服务器和3个从服务器。这里还有一个客户端,我们称为Z1.当隔断发生时,有可能是在一个区间中有A,C,A1,B1,C1而另一个区间中有B和Z1,Z1依然可以向B写,B也会接受所有的写,当隔断在很短时间和恢复的话,集群会保持正常,然而如果隔断的时间足以使得B1在大部分的这个区间被提升为主服务器,那Z1写到B的数据将会被丢失。

  注意到這了有一个最大窗口来保证Z1依然可以写向B:如果过去了时间超过了大部分区间提升一个从服务器为主服务器的时间,在小部分区间的主服务器节点会停止接收写。这个时间的总量对于Redis集群的配置来说是非常重要的指令,称为nodetimeout。当node timeout过去后,主节点会被认为是失败,可以被它的复制中的某一个替代。类似的当node timeout时间过去后,如果主服务器节点无法感知到集群中的大部分节点,它会进入错误状态,拒绝接受写请求。

7.Redis集群配置参数

  我们打算创建一个集群部署的例子,在进行之前介绍一些在redis.conf文件中关于Redis集群的配置。某一些可能是显然的,其他的就需要继续阅读来弄清楚。

cluster-enabled <yes/no>:

如果是yes则Redis节点支持集群,否则节点最为独立模式。

cluster-config-file <filename>: 

注意到不要管这个选项名字,这并不是一个用户可以编辑的配置文件,而是Redis集群节点当发生变化时自动固话集群的配置(通常来说是状态)的文件,这样就可以在启动的时候重新读取。这个文件列举了集群中的其它节点和他们的状态,固话的值等。通常来说这个文件会在接收到某些信息时重写然后刷新到硬盘。

cluster-node-timeout <milliseconds>: 

Redis集群中一个节点不可用的最长时间,如果没有配置则认为是失败的。如果一个主服务器节点在失联超过指定的时间,就会进行故障转移到它的从服务器上。这个参数也控制着其它Redis中其它重要的事情。显著的是,每一个节点在无法连接到集群中的大部分节点特定时间后就会拒绝接受写

cluster-slave-validity-factor <factor>:

如果设置为0,一个从服务器会总是尝试故障转移为主服务器,而不管主服务器和该从服务器失联的时间。如果该只是整数,有node timeout值乘以这里指定的值计算出来的最大失联时间,如果该节点是从服务器,并且和主服务器失联的时间超过了计算出来的最大失联时间,则该节点永远不会被提升为主服务器。比如节点的node timeout设置为5秒,validity factor设置为10,而从服务器和主服务器的失联时间超过50秒后就不会尝试和其主服务器进行故障转移。任何和0不一样的值都可能会造成Redis集群在主服务器失败,而没有从服务器可以进行故障转移时变得不可用。这种情况下只有在原先的主服务器重新接入到集群中才可以恢复正常。

cluster-require-full-coverage <yes/no>:

如果设置为yes,也是默认的值,集群会在如果某些键的空间没有被集群中的任何一个节点覆盖时拒绝写,如果设置为no,集群会集中处理这些请求,即使只能处理其中的一部分key.

8.创建和使用Redis集群

  注意:手动去部署一个Redis集群对于学习集群的操作是非常重要的。然而如果你需要尽快的有一个可以运行的集群,那可以跳过这章和下一章,直接到使用create-cluster脚本创建Redis集群这章。要创建一个集群,第一件事情就是需要一些运行在集群模式下的空redis实例。实际id意思就是集群并不适用通常的Redis实例来创建,而是需要配置一个特定的模式来使得Redis实例使能集群相关的功能和命令。

下面是一个最小的Redis集群配置文件

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

  你可以看到打开集群模式就是简单的cluster-enabled指令,每一个实例同样包括一个节点配置保存的文件路径,默认是nodes.conf。这个文件永远不会被认为获取,只是在Redis集群实例启动的时候生成,然后在需要的时候进行更新。注意:正常工作的最小集群需要至少3个集群节点,对于你的第一个测试来说,强烈建议启动6个节点的集群,其中3个主节点,3个从节点。为了这么做,进入一个新的目录,然后创建一下的子目录,名称为我们想在里面运行的实例的端口,比如:

mkdir cluster-testcd cluster-testmkdir 7000 7001 7002 7003 7004 7005

在每一个目录中创建redis.conf文件,从70000到7005。最为你配置文件的模板只需要使用上面例子中的小文件,但是要保证将端口号7000替换为对应目录的端口号。

  现在拷贝你的redis-server执行文件,(从GitHub的罪行的非稳定分支编译获取),到cluster-test目录,最后在你喜欢的终端应用中打开6个终端窗口。在每一个窗口中像下面这样启动每一个实例:

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

你可以从每一个实例的日记中看到,因为没有nodes.conf文件存在,每一个节点会给自己分配一个新的ID.

[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I'm 97a3a64667477371c4479320d683e4c8db5858b1

这个ID会被这个特定实例永远使用来保证该实例在集群的上下文中有一个唯一的名字。每一个节点使用ID来记录其它的节点,而不是IP或端口,因为IP地址和端口是可能改变的,但是唯一的节点标识在节点的整个生命周期都是不变的,我们简单的称呼这个标识为Node ID.

至此,Redis集群的基本学习已经完成了,后面的部分有时间再去学习。

原文链接:https://redis.io/topics/cluster-tutorial

0 0
原创粉丝点击