1

复制

我们可以执行SLAVEOF命令或者设置slaveof选项,让一个服务器去复制(replicate)另一个服务器,复制数据的服务器会变成另一台服务器的从服务器,二者保持相同的数据。以后在主服务器上设置键值会自动同步数据到从服务器上。

复制功能的实现

同步

将从服务器的数据库状态更新至主服务器当前所处的数据库状态。

clipboard.png

命令传播

当主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:

REPLICATION ACK <replication_offset>

主要用于检测主从服务器的网络连接状态和命令丢失。

sentinel(redis高可用解决方案)

由一个或多个sentinel实例组成的sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器;并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。如图所示:

clipboard.png

它是如何工作的?

启动

redis-sentinel sentinel.conf 或者
redis-server sentinel.conf --sentinel

初始化服务器

sentinel本质上只是一个运行在特殊模式下的redis服务器,但它不使用数据库,所以并不会载入RDB文件或者AOF文件来还原数据库状态。初始化过程:

  • 使用sentinel专用代码初始化sentinel状态

  • 创建连向主服务器的网络连接

连接建立之后,sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关的信息。对于每个被sentinel监视的主服务器来说,sentinel会创建两个连向主服务器的异步网络连接:

  • 命令连接,向主服务发送命令,并接收命令回复

  • 订阅连接,订阅主服务器的__sentinel__:hello频道

注:如果发现主服务器下有从服务器,也会为从服务器创建命令连接和订阅连接。而sentinel与sentinel之间则只创建命令连接。

获取服务器信息

sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主从服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息。

发送和接收消息

在默认情况下,sentinel会以每两秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送以下格式的命令:

PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

当sentinel与一个主服务器或者从服务器建立起订阅连接之后,sentinel就会通过订阅连接,向服务器发送以下命令:

SUBSCRIBE __sentinel__:hello

sentinel对__sentinel__:hello频道的订阅会一直持续到sentinel与服务器的连接断开为止。

也就是说,对于每个与sentinel连接的服务器,既通过命令连接向服务器的__sentinel__:hello频道发送信息,又通过订阅连接从服务器的__sentinel__:hello频道接收信息。对于监视同一个服务器的多个sentinel来说,一个sentinel发送的信息会被其他sentinel接收到,这些信息会被用于更新其他sentinel对发送信息sentinel的认知,也会被用于更新其他sentinel对被监视服务器的认知。

检测服务器状态

检测主观下线状态

sentinel以每秒一次的频率向实例(包括主服务器、从服务器、其他sentinel)发送PING命令,并根据实例对PING命令的回复来判断实例是否在线,当一个实例在指定的时长中连续向sentinel发送无效回复时,sentinel会将这个实例判断为主观下线。

检测客观下线状态,进行故障转移

当sentinel将一个主服务器判断为主观下线时,它会向同样监视这个主服务器的其他sentinel进行询问,看它们是否同意这个主服务器已经进入主观下线状态;当sentinel收集到足够多的主观下线投票之后,它会将主服务器判断为客观下线,并选取一个领头sentinel发起一次针对主服务器的故障转移操作。
注:更多细节请查阅<<redis设计与实现>> 第16章内容...

集群

redis集群是redis提供的分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能(redis3.0之前需要依靠client端做sharding,3.0之后,开始支持server端的集群)。

节点

一个redis集群由多个节点(node)组成,使用cluster meet ip port连接各个节点(握手),然后通过cluster nodes查看集群节点信息。

  • 启动服务器的时候会判断cluster-enabled值:如果为yes,开启服务器的集群模式成为一个节点。

  • 节点分为主节点和从节点,主节点用于处理槽(有关槽的介绍见下一小节),而从节点用于复制某个主节点,并在被复制的主节点下线时,代替下线主节点继续处理命令请求(集群中的每个节点都会定期地向集群中其他节点发送PING消息,以此来检测对方是否在线)。

注:节点和单机服务器在数据库方面的一个区别是,节点只能使用0号数据库,而单机redis服务器则没有这一限制。

槽指派

redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为16384个槽(slot),数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或最多16384个槽。

  1. 通过向节点发送CLUSTER ADD SLOTS命令, 我们可以将一个或多个槽指派(assign)给某个节点负责,比如将槽0至5000指派给节点7000负责:
    127.0.0.1:7000> CLUSTER ADDSLOTS 0 1 2 3 4 ... 5000

  2. 每个节点都会记录哪些槽指派给了自己,而哪些槽又被指派给了其他节点。当数据库中的16384个槽都有节点在处理时,集群处于上线状态(ok);相反地,如果数据库中有任何一个槽没有得到处理,那么集群处于下线状态(fail)。

分片:将你的数据拆分到多个redis实例的过程,这样每个实例将只包含所有键的子集。通过多台服务器实现分片,可以不再局限于单机所能支持的内存容量,利于扩展。另外,由于每个key最终只会存储到一个特定的redis实例的一个slot中,如果要实现高可用,最好至少保证双写,一个key要存储到两个redis实例中(对应两台服务器),读取的时候可以随机读。

在集群中执行命令过程

clipboard.png

重新分片

redis集群的重新分片操作可以将任意数量已经指派给某个节点(源节点)的槽改为指派给另一个节点(目标节点),并且相关槽所属的键值对也会从源节点被移动到目标节点。重新分片操作可以在线(online) 进行,在重新分片的过程中,集群不需要下线,并且源节点和目标节点都可以继续处理命令请求。对集群中单个槽重新分片需要执行如下命令:

目标节点:CLUSTER SETSLOT <slot> IMPORTING <source_id> ①
源节点:CLUSTER SETSLOT <slot> MIGRATING <target_id> ②
源节点:CLUSTER GETKEYSINSLOT <slot> <count> ③
源节点:MIGRATE <target_ip> <target_port> <key_name> 0 <timeout> ④
任意节点:CLUSTER SETSLOT <slot> NODE <target_id> 通知其它节点该槽指派给了target_id节点

注:重新分片是基于键值对维度的,每个槽中的n个键需要执行n次③和④的操作。


sunnyxd
529 声望30 粉丝