《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信

一、数据分布

分布式数据首先要解决把整个数据集按照分区规则映射到多个节点的问题,常见的分区规则有哈希分区顺序分区两种:
《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信_第1张图片

常见的哈希分区规则:

1、 节点取余分区:客户端分片:哈希+取余

  • 使用特定的数据,如Redis的键或用户ID,再根据节点数量N使用公式:hash(key)%N计算出哈希值,用来决定数据映射在哪一个节点。
  • 优点:实现简单
  • 缺点:当节点数量变化时,比如加入和删除节点,数据节点映射关系需要重新计算,会导致数据的重新迁移。

2、 一致性哈希分区:客户端分片:哈希+顺时针

  • 为系统中每一个节点分配一个token,范围一般在0-2的32次方,这些token构成一个哈希环。数据读写执行节点查找操作时,先根据key计算hash值,然后顺时针找到第一个大于等于该哈希值的token节点。
  • 优点:加入和删除节点时,只影响哈希中相邻节点,对其他节点无影响,对于节点比较多的情况下,影响范围特别小。
  • 缺点:
    (1)加减节点会造成哈希环中部分数据无法命中,需要手动处理或者忽略这部分数据,因此一致性哈希常用于缓存场景。
    (2)当使用少量节点时,节点变化将大范围影响哈希环中数据映射,因此这种方式不适合少量数据节点的分布式方案。
    (3)普通的一致性哈希分区在增减节点时需要增加一倍或减去一半节点才能保证数据和负载的均衡。

3.、虚拟槽哈希分区: 服务端管理节点、槽、数据

  • 虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot)。这个范围一般远远大于节点数,比如Redis Cluster槽范围是0~16383。槽是集群内数据管理和迁移的基本单位。采用大范围槽的主要目的是为了方便数据拆分和集群扩展。每个节点会负责一定数量的槽。

Redis 集群采用是哈希分区规则,虚拟槽分区

Redis Cluster将所有数据划分为16384的slots,每个节点负责其中一部分槽位。槽位的信息存储于每个节点,当Redis cluster的客户端来连接集群时,它会得到一份集群的槽位配置信息,这样当客户端要查找某个key时,可以直接定位到目标节点。

Redis虚拟槽分区的特点:

  • 解耦数据和节点之间的关系,简化了节点扩容和收缩难度。
  • 节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据。
  • 支持节点、槽、键之间的映射查询,用于数据路由、在线伸缩等场景。

集群功能限制

  1. key批量操作支持有限。因为key被分散到各个槽、各个节点。
  2. key事务操作支持有限。因为key被分散到各个槽、各个节点。
  3. key作为数据分区的最小粒度,因此不能将一个大的键值对象如hash、list等映射到不同的节点。
  4. 不支持多数据库空间。单机下的Redis可以支持16个数据库,集群模式下只能使用一个数据库空间,即db0。
  5. 复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。

二、手动搭建集群

三个步骤:准备节点、节点握手、分配槽

准备节点

Redis集群一般由多个节点组成,节点数量至少为6个才能保证组成完整 ,高可用的集群。每个节点需要开启配置cluster-enabled yes,让Redis运行在集群模式下。

建议为集群内所有节点统一目录,一般划分三个目录conf、data、log,分别存放配置、数据和日志相关文件。

书中试例是单台虚拟机六个节点:
三主:127.0.0.1:6379、127.0.0.1:6380、127.0.0.1:6381
三从:127.0.0.1:6382、127.0.0.1:6383、127.0.0.1:6384

本试例是三台虚拟机:192.168.164.101、192.168.164.102、192.168.164.103
六个节点:
三主:192.168.164.101:6379、192.168.164.102:6379、192.168.164.103:6379
三从:192.168.164.101:6380、192.168.164.102:6380、192.168.164.103:6380

主节点–端口为6379节点配置:

# bind 127.0.0.1
port 6379
daemonize yes
protected-mode no
logfile /usr/local/src/redis-4.0.14/log/redis-6379.log
dbfilename redis-6379.rdb
dir /usr/local/src/redis-4.0.14/data
requirepass 123456
masterauth 123456

# redis cluster
cluster-enabled yes
cluster-node-timeout 15000
cluster-config-file nodes-6379.conf

从节点–端口为6380节点配置:

# bind 127.0.0.1
port 6380
daemonize yes
protected-mode no
logfile /usr/local/src/redis-4.0.14/log/redis-6380.log
dbfilename redis-6380.rdb
dir /usr/local/src/redis-4.0.14/data
requirepass 123456
masterauth 123456


# redis cluster
cluster-enabled yes
cluster-node-timeout 15000
cluster-config-file nodes-6380.conf

集群模式的Redis除了原有的配置文件之外又加了一份集群配置文件。当集群内节点信息发生变化,如添加节点、节点下线、故障转移等。节点会自动保存集群状态到配置文件中。需要注意的是,Redis自动维护集群配置文件,不要手动修改,防止节点重启时产生集群信息错乱。

如果启动时存在集群配置文件,节点会使用配置文件初始化集群信息,如果不存在,会自动创建一分集群配置文件。文件名称采用cluster-config-file参数项控制。

#cat data/nodes-6379.conf
ac70d2174c0bae79bec374895026759b6b096 192.168.164.101:6379@16379 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0

文件内容记录了节点ID,是一个40位16进制字符串,用于唯一表示集群内一个节点,之后很多集群操作都要借助于节点ID来完成。需要注意是,节点ID不同于运行ID:节点ID在集群初始化时只创建一次,节点重启时会加载集群配置文件进行重用,而Redis的运行ID每次重启都会变化。

节点握手

节点通过Gossip协议彼此通信,达到感知对方过程,由客户端发起命令:cluster meet {ip} {port}
《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信_第2张图片

192.168.164.101:6379> cluster meet 192.168.164.102 6379
192.168.164.101:6379> cluster meet 192.168.164.103 6379
192.168.164.101:6379> cluster meet 192.168.164.101 6380
192.168.164.101:6379> cluster meet 192.168.164.102 6380
192.168.164.101:6379> cluster meet 192.168.164.103 6380

这里的ping、pong、meet消息都是Gossip协议通信的载体,作用是节点彼此交换数据信息
《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信_第3张图片
节点建立握手之后集群还不能正常工作,这时集群处于下线状态,所有的数据读写都被禁止。只有当16384个槽全部分配给节点后,集群才进入在线状态

分配槽

Redis集群把所有的数据映射到16384个槽中。每个key会映射为一个固定的槽,只有当节点分配了槽,才能响应和这些槽关联的键命令。通过cluster addslots命令为节点分配槽。这里利用bash特性批量设置槽(slots),命令如下:

# redis-cli -h 127.0.0.1 -p 6379 cluster addslots {0...5461} 为什么有的是三个点????????  但是试了三个点不行啊
redis-cli -a 123456 -h 192.168.164.101 -p 6379 cluster addslots {
     0..5461}
redis-cli -a 123456 -h 192.168.164.102 -p 6379 cluster addslots {
     5462..10922}
redis-cli -a 123456 -h 192.168.164.103 -p 6379 cluster addslots {
     10923..16383}

目前还有三个节点没有使用,作为一个完整的集群,每个负责处理槽的节点应该具有从节点,首次启动的节点和被分配的槽的节点都是主节点,从节点负责复制主节点槽信息和相关数据。使用cluster replicate {nodeld}命令让一个节点变成从节点。命令执行必须要对应从节点执行,nodeId是要复制主节点的节点ID,命令如下:

redis-cli -a 123456 -h 192.168.164.101 -p 6380 
192.168.164.101:6380> cluster replicate 39eac70d2174c0bae79bec374895026759b6b096

redis-cli -a 123456 -h 192.168.164.102 -p 6380
192.168.164.102:6380> cluster replicate 6f955130354d2efd93a879fc24503e7cc1c12fad

redis-cli -a 123456 -h 192.168.164.103 -p 6380
192.168.164.103:6380> cluster replicate 9536f021dbb227bf466365015c52b8022f5a3593

复制(replication)完成后,整个集群的结构如图:
《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信_第4张图片
cluster info查看集群状态,如下所示:

192.168.164.101:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:3956
cluster_stats_messages_pong_sent:3883
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:7844
cluster_stats_messages_ping_received:3883
cluster_stats_messages_pong_received:3961
cluster_stats_messages_received:7844

cluster nodes命令查看集群状态、复制关系、槽节点分布关系,如下所示:

192.168.164.101:6379> cluster nodes
04440bc028b4c4d33767ebbd65749b3e3ea89182 192.168.164.101:6380@16380 slave 39eac70d2174c0bae79bec374895026759b6b096 0 1599035943000 5 connected
39eac70d2174c0bae79bec374895026759b6b096 192.168.164.101:6379@16379 myself,master - 0 1599035945000 1 connected 0-5461
94d54d28687aa1d851a3ba909e3283ef874c6970 192.168.164.103:6380@16380 slave 9536f021dbb227bf466365015c52b8022f5a3593 0 1599035944000 4 connected
6f955130354d2efd93a879fc24503e7cc1c12fad 192.168.164.102:6379@16379 master - 0 1599035945171 2 connected 5462-10922
9536f021dbb227bf466365015c52b8022f5a3593 192.168.164.103:6379@16379 master - 0 1599035946177 3 connected 10923-16383
a3bcbb2702dc33b8c4b4550c821cb54afc4e49aa 192.168.164.102:6380@16380 slave 6f955130354d2efd93a879fc24503e7cc1c12fad 0 1599035944163 2 connected

redis-trib.rb搭建集群及用法

手动搭建集群便于理解集群建立的流程和细节,不过读者也从中发现集群搭建需要很多步骤,当集群节点众多时,必然会加大搭建集群的复杂度和运维成本。因此Redis官方提供了redis-trib.rb工具方便我们快速搭建集群。

参考:https://www.jianshu.com/p/21f67bd739cc

三、节点通信

通信流程

  • 在分布式存储中需要维护节点元数据信息:节点负责哪些数据,是否出现故障等状态信息。常见的元数据维护方式 分为:集中式P2P方式
  • Redis集群采用P2P的Gossip(流言)协议, Gossip协议工作原理就是节点彼此不断通信交换信息,一段时间后所有的节 点都会知道集群完整的信息,这种方式类似流言传播,如图所示:
    《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信_第5张图片
  • 通信过程说明:
    1)集群中的每个节点都会单独开辟一个TCP通道,用于节点之间彼此 通信,通信端口号在基础端口上加10000。
    2)每个节点在固定周期内通过特定规则选择几个节点发送ping消息。
    3)接收到ping消息的节点用pong消息作为响应。

集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全 部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终它们会达到一致的状态

Gossip消息

Gossip协议的主要职责就是信息交换。常用的Gossip消息可分为:ping消息、pong消息、meet消息、fail消息 等
《Redis开发与运维》---- 集群(Redis Cluster)数据分布、搭建集群、节点通信_第6张图片

  • meet消息:用于通知新节点加入。
  • ping消息:集群内每个节点每秒向多个其 他节点发送ping消息,用于检测节点是否在线和交换彼此状态信息。
  • pong消息:当接收到ping、meet消息时,作为响应消息回复给发送方确 认消息正常通信。
  • fail消息:当节点判定集群内另一个节点下线时,会向集群内广播一个 fail消息,其他节点接收到fail消息之后把对应节点更新为下线状态。

所有的消息格式划分为:消息头和消息体。消息头结构clusterMsg:它包含了发送 节点关键信息,如节点id、槽映射、节点标识(主从角色,是否下线)等。消息体clusterMsgData结构。

节点选择

由于内部需要频繁地进行节点信息交换,势必会加重带宽和计算的负担。Redis集群 内节点通信采用固定频率(定时任务每秒执行10次)。因此节点每次选择需要通信的节点列表变得非常重要。通信节点选择过多虽然可以做到信息及时 交换但成本过高。节点选择过少会降低集群内所有节点彼此信息交换频率, 从而影响故障判定、新节点发现等需求的速度。所以要选择发送消息的节点数量和每个消息携带的数据量,兼顾信息交换实时性和成本开销。

  • 选择发送消息的节点数量cluster_node_timeout参数对消息发送的节点数量影响非常大。当我们的带宽 资源紧张时,可以适当调大这个参数,如从默认15秒改为30秒来降低带宽占 用率。过度调大cluster_node_timeout会影响消息交换的频率从而影响故障转移、槽信息更新、新节点发现的速度。
  • 消息数据量:消息体携带数据量的大小跟集群的节点数息息相关,更大的集群每次消息通信的成本也就更高,因此对于Redis集群来说并不是大而全的集群更好。

你可能感兴趣的:(Redis)