分布式数据首先要解决把整个数据集按照分区规则映射到多个节点的问题,常见的分区规则有哈希分区和顺序分区两种:
Redis Cluster将所有数据划分为16384的slots,每个节点负责其中一部分槽位。槽位的信息存储于每个节点,当Redis cluster的客户端来连接集群时,它会得到一份集群的槽位配置信息,这样当客户端要查找某个key时,可以直接定位到目标节点。
Redis虚拟槽分区的特点:
三个步骤:准备节点、节点握手、分配槽
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}
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协议通信的载体,作用是节点彼此交换数据信息
节点建立握手之后集群还不能正常工作,这时集群处于下线状态,所有的数据读写都被禁止。只有当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)完成后,整个集群的结构如图:
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官方提供了redis-trib.rb工具方便我们快速搭建集群。
参考:https://www.jianshu.com/p/21f67bd739cc
集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全 部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终它们会达到一致的状态。
Gossip协议的主要职责就是信息交换。常用的Gossip消息可分为:ping消息、pong消息、meet消息、fail消息 等
所有的消息格式划分为:消息头和消息体。消息头结构clusterMsg:它包含了发送 节点关键信息,如节点id、槽映射、节点标识(主从角色,是否下线)等。消息体clusterMsgData结构。
由于内部需要频繁地进行节点信息交换,势必会加重带宽和计算的负担。Redis集群 内节点通信采用固定频率(定时任务每秒执行10次)。因此节点每次选择需要通信的节点列表变得非常重要。通信节点选择过多虽然可以做到信息及时 交换但成本过高。节点选择过少会降低集群内所有节点彼此信息交换频率, 从而影响故障判定、新节点发现等需求的速度。所以要选择发送消息的节点数量和每个消息携带的数据量,兼顾信息交换实时性和成本开销。
cluster_node_timeout
参数对消息发送的节点数量影响非常大。当我们的带宽 资源紧张时,可以适当调大这个参数,如从默认15秒改为30秒来降低带宽占 用率。过度调大cluster_node_timeout会影响消息交换的频率从而影响故障转移、槽信息更新、新节点发现的速度。