cluster

第十二章 Redis集群(Redis Cluster)

1 引言

本章将着重介绍Redis集群特性。对于一个在分布式环境下的数据库系统而言,有许多特性特点值得学习和探索。在本章中,我们会将重点放在数据切分(Data Partitioning)和Redis数据库的动态性上。数据切分之所有很重要是因为,一旦数据切分的方法确定下来之后,基本上就能大致确定数据查询、数据增删的处理逻辑、以及数据同步、数据动态调整等问题。另一方面,Redis数据库的动态性也很重要。动态性是指Redis数据库能够动态的增加或者删除节点,动态调整数据。这个特性很重要是因为当数据量增加到某一个层度之后,开发人员需要增加新的节点以平衡各节点的负载,以获得性能最大化。

2 Redis的数据切分方法

2.1 分析

数据切分特性能帮助Redis获得两个好处。其一,因为Redis将所有的数据存放在内存中。因此,如果把所有的数据存放在一个节点上的话,所能容纳的数据量受到当前节点内存大小的限制。为了突破这一限制,使得Redis服务器能存放更多的数据,Redis需要将数据分别存放在多个节点服务器上。 其二,如果所有的数据都在一个节点上,那么,Redis服务器只能使用当前节点的计算资源提供服务。如果Redis能将数据部署于多个节点服务器上的话,那么,这些节点的计算资源都能被用于提供服务。所以,数据切分和分布式部署对于系统扩展性(Scalability)至关重要。

那么,数据切分也为Redis的系统设计带来了极大的困难。其一,当一条命令处理多个键值对时,但是如果这些键值对分布于不同节点之上,则Redis服务器可能不能执行这条命令(至少不能在某一节点上执行这条命令)。其二,我们在之前章节中介绍过Redis的事务处理。Redis能够提供事务原子性、事务隔离性和事务一致性的原因是在单节点的环境中,所有的事物都是顺序执行的。不会发生两个事务同时执行的情况。然而,在多节点环境,多个事务是有可能同时执行的。那么,如何确保事务的原子性、事务隔离性和事务一致性会变得非常困难。其三,数据复制和数据持久性特性将会变得更为困难,毕竟数据分布在不同的节点上,不同节点可能有着不同的数据复制和持久化策略。

2.2 键空间与Slot

在分析完数据切分方法的优点和缺点之后,我们再来介绍Redis数据的切分方法。在Redis服务器中,所有的数据都是以键值对的方式存在的(除订阅者/发布者除外)。所以,Redis将所有的键的取值分为定义为键空间(Key Space)。Redis将键空间切分为16384区间(214个区间,或者0x4000个区间),每个区间被称为一个slot。给定一个键,这个键值对被分配到哪个slot是由下面的公式计算的。其计算过程为:首先计算该键的CRC16的值,然后在取16384的模。因此,从此可以看出,Redis是使用CRC16算法来划分数据的。

ASSIGNED_SLOT = CRC16(key) mod 16384

2.3 Slot分配

当Redis系统工作于单节点模式时,这个节点负责所有Slot中的数据。当Redis系统工作于多节点模式下时,每个节点仅处理自己管理的Slot中的数据。每当节点接收到一条命令时,该节点会计算当前键所对应的Slot。如果该Slot是当前节点负责的,则该节点会继续处理这条命令。如果不是,则会告知客户端能够处理该数据的节点,因此,客户端能向正确的节点再次发送命令。

如下是一个例子,该客户端执行GET命令查询name的值,可是,该客户端所连接的节点并不负责保存这个键值对,所以,该节点返回了正确节点的地址和端口。其中,MOVED表示的是重定向,1234是该命令处理的键对应的Slot号,192.168.0.10:6381表示的是能处理该命令的节点地址和端口。

> GET name
-MOVED 1234 192.168.0.10:6381

在Redis系统运行过程中,节点直接会相互交换信息。每一个节点都会保留一份Slot到节点的映射表,以便于查询能够正确执行命令的节点。

2.4 Hash Tags

我们在2.1小节分析了数据切分的一些缺点。因为多个键值对可能被分配到不同的节点上,因此,这些键值对可能不能由一个命令处理(例如,求两个链表的交集)。事务处理也变得非常困难。为了解决这个问题,Redis提出了一个新的概念Hash Tags。这里的"Hash"是针对计算Slot过程中计算键的哈希值而言的。实际上,CRC16就是一种哈希函数。Hash Tags特性是指,给定两个键或者多个键,即使它们对应的Slot是不同的,如果它们有着相同的Hash Tags的话,它们会被分配到相同的Slot上,以便于包含它们的命令或者事务能由一个节点处理,因为,Slot是数据切分的最小单位。

3 Redis的动态性

理论上,系统有两种扩展方式。纵向扩展(Vertical Scaling)是指增加节点内部使用的计算资源以达到期望的性能要求。例如,替换更快的CPU,增加更多的内存或者硬盘,这些属于纵向扩展。横向扩展(Horizontal Scaling)是指通过增加系统节点的个数以达到期望的性能要求。Redis的动态性和可扩展性主要体现在横向扩展上。

Redis系统能够动态的添加或者删除节点。在添加或者删除节点的过程中,Redis系统能够继续提供服务,不会出现短暂的下线状态。当向Redis系统添加一个新的节点时,开发人员可以将分配于其他节点的Slot迁移到新的节点上,以使得新的节点"融入"Redis整个系统。当需要移除一个节点时,开发人员可以先将该节点负责的Slot迁移到其他节点上,然后再删除该节点。Slot到节点的映射完全由开发人员控制。

Redis添加节点的过程可由以下步骤完成。

  1. 将一个新的节点加入Redis集群。当前节点未分配任何Slot,因此,该节点不能接收或者提供任何数据或者服务。
  2. 使用cluster meet命令,让新节点与其他节点交换信息,并将新节点加入到可信任节点的列表中。实际上,Redis有两种方法加入一个新节点。使用cluster meet命令是其中之一,另一种方法是,如果新节点已被一个节点所接受的话,那么,该节点会将新节点的信息告知其他节点(因为节点之间是会定时交换信息的),因此,其他节点也能与新节点建立起联系。
  3. 使用cluster setslot <slot> importing命令,让新节点准备接收该Slot的数据,并让源节点准备迁出该Slot的数据。
  4. 使用cluster getkeysinslot和migrate命令将Slot中的数据逐步从源节点移至新节点。cluster getkeysinslot命令用于查询Slot内键的值,而migrate命令将该键的数据从源节点移至新节点。
  5. 当将Slot内所有的数据全部移至新节点后,使用cluster setslot命令完成Slot迁移过程。该命令用于通知个节点Slot移动完毕。因此,该命令需要下发至各个节点。

因为从Redis集群删除一个节点的过程与上述添加过程较为类似,是将Slot从待删节点移至其他节点的过程,因此,我们在此处不做详细介绍。

上述步骤介绍了从一个节点向另一个节点移动Slot的过程。在此基础之上,Resharding是指将一个或者多个节点上的Slot移至另外一些节点上(Move slots from a set of nodes to another set of nodes)的过程。在通常情况下,Slot可能需要在几个节点上重新分配,可能是因为某些节点的配置发生了变化,需要增加或者减少Slot的分配。这种情况也可称为Resharding。

Resharding的过程并不复杂,它也是通过一个一个地移动Slot完成地。开发人员通常会使用一个脚本文件完成,或者由客户端程序完成。目前为止,在Redis 6.0服务器端,并不存在一条命令能够完成Resharding的过程。

4 小结

本章介绍了Redis在集群模式下的数据划分的原理和添加/删除节点的过程。无论是单个Slot的迁移,还是针对部分节点的Resharding,Redis服务器都是通过每次移动一个Slot逐步完成的。Redis集群模式有着很好的动态性和可扩展性,因为,它能够提供在线的数据迁移,并且动态添加和删除节点。

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.