知道Redis集群
概述
Redis单实例的架构,从最开端的一主N从,到读写别离,再到Sentinel岗兵机制,单实例的Redis缓存足以应对大多数的运用场景,也能完结主从毛病搬迁。
可是,在某些场景下,单实例存Redis缓存会存在的几个问题:
-
写并发:Redis单实例读写别离能够处理读操作的负载均衡,但关于写操作,仍然是悉数落在了master节点上面,在海量数据高并发场景,一个节点写数据简单呈现瓶颈,形成master节点的压力上升。
-
海量数据的存储压力:单实例Redis本质上只需一台Master作为存储,假如面临海量数据的存储,一台Redis的服务器就敷衍不过来了,而且数据量太大意味着耐久化本钱高,严峻时或许会堵塞服务器,形成服务恳求成功率下降,下降服务的稳定性。
针对以上的问题,Redis集群供给了较为完善的计划,处理了存储才干遭到单机约束,写操作无法负载均衡的问题。
Redis供给了去中心化的集群布置形式,集群内一切Redis节点之间两两衔接,而许多的客户端东西会依据key将恳求分发到对应的分片下的某一个节点上进行处理。Redis也内置了高可用机制,支撑N个master节点,每个master节点都能够挂载多个slave节点,当master节点挂掉时,集群会进步它的某个slave节点作为新的master节点。
默许状况下,redis集群的读和写都是到master上去履行的,不支撑slave节点读和写,跟Redis主从仿制下读写别离不相同,由于redis集群的中心的理念,首要是运用slave做数据的热备,以及master毛病时的主备切换,完结高可用的。Redis的读写别离,是为了横向恣意扩展slave节点去支撑更大的读吞吐量。而redis集群架构下,本身master便是能够恣意扩展的,假如想要支撑更大的读或写的吞吐量,都能够直接对master进行横向扩展。
一个典型的Redis集群布置场景如下图所示:
在Redis集群里边,又会区分出分区
的概念,一个集群中可有多个分区。分区有几个特色:
- 同一个分区内的Redis节点之间的数据彻底相同,多个节点确保了数据有多份副本冗余保存,且能够供给高可用确保。
- 不同分片之间的数据不相同。
- 经过水平添加多个分片的方法,能够完结全体集群的容量的扩展。
依照Cluster形式进行布置的时分,要求最少需求布置6个
Redis节点(3个分片,每个分片中1主1从),其间集群中每个分片的master节点担任对外供给读写操作,slave节点则作为毛病搬运运用(master呈现毛病的时分充任新的master)、对外供给只读恳求处理。
集群数据散布战略
Redis Sharding(数据分片)
在Redis Cluster
前,为了处理数据分发到各个分区的问题,遍及选用的是Redis Sharding
(数据分片)计划。所谓的Sharding,其实便是一种数据分发的战略。依据key的hash值进行取模,确认终究归属的节点。
长处便是比较简单,可是
-
扩容或许去除节点时需求从头依据映射联系核算,会导致数据从头搬迁。
-
集群扩容的时分,会导致恳求被分发到过错节点上,导致缓存射中率下降。
假如需求处理这个问题,就需求对原先扩容前现已存储的数据从头进行一次hash核算和取模操作,将悉数的数据从头分发到新的正确节点上进行存储。这个操作被称为从头Sharding
,从头sharding期间服务不可用,或许会对事务形成影响。
共同性Hash
为了下降节点的添加或许移除关于全体已有缓存数据拜访的影响,最大极限的确保缓存射中率,改进后的共同性Hash
算法浮出水面。
Hash槽
何为Hash槽?Hash槽的原理与HashMap有点相似,Redis集群中有16384个哈希槽(槽的规划是 0 -16383,哈希槽),将不同的哈希槽散布在不同的Redis节点上面进行办理,也便是说每个Redis节点只担任一部分的哈希槽。在对数据进行操作的时分,集群会对运用CRC16算法对key进行核算并对16384取模(slot = CRC16(key)%16383),得到的成果便是 Key-Value 所放入的槽,经过这个值,去找到对应的槽所对应的Redis节点,然后直接到这个对应的节点上进行存取操作。
运用哈希槽的长处就在于能够便利的添加或许移除节点,而且不管是添加删去或许修正某一个节点,都不会形成集群不可用的状况。
- 当需求添加节点时,只需求把其他节点的某些哈希槽挪到新节点就能够了;
- 当需求移除节点时,只需求把移除节点上的哈希槽挪到其他节点就行了;
哈希槽数据分区算法具有以下几种特色:
- 解耦数据和节点之间的联系,简化了扩容和缩短难度;
- 节点本身保护槽的映射联系,不需求客户端署理服务保护槽分区元数据
- 支撑节点、槽、键之间的映射查询,用于数据路由,在线弹性等场景
为什么redis集群选用“hash槽”来处理数据分配问题,而不选用“共同性hash”算法呢?
- 共同性哈希的节点散布依据圆环,无法很好的手动操控数据散布,比方有些节点的硬件差,期望少存一点数据,这种很难操作(还得经过虚拟节点映射,总归较繁琐)。
- 而redis集群的槽位空间是能够用户手动自定义分配的,相似于 windows 盘分区的概念,能够手动操控巨细。
- 其实,不管是 “共同性哈希” 仍是 “hash槽” 的方法,在增减节点的时分,都会对一部分数据产生影响,都需求咱们搬迁数据。当然,redis集群也供给了相关手动搬迁槽数据的指令。
Hash槽原理详解
clusterNode
保存节点的当时状况,比方节点的创立时刻,节点的姓名,节点当时的装备纪元,节点的IP和地址,等等。
typedef struct clusterNode {
//创立节点的时刻
mstime_t ctime;
//节点的姓名,由40个16进制字符组成
char name[CLUSTER_NAMELEN];
//节点标识 运用各种不同的标识值记载节点的人物(比方主节点或许从节点)
char shard_id[CLUSTER_NAMELEN];
//以及节点现在所在的状况(比方在线或许下线)
int flags;
//节点当时的装备纪元,用于完结毛病搬运
uint64_t configEpoch;
//由这个节点担任处理的槽
//一共有REDISCLUSTER SLOTS/8个字节长 每个字节的每个位记载了一个槽的保存状况
// 位的值为 1 表明槽正由本节点处理,值为0则表明槽并非本节点处理
unsigned char slots[CLUSTER_SLOTS/8];
uint16_t *slot_info_pairs; /* Slots info represented as (start/end) pair (consecutive index). */
int slot_info_pairs_count; /* Used number of slots in slot_info_pairs */
//该节点担任处理的槽数里
int numslots;
//假如本节点是主节点,那么用这个特点记载从节点的数里
int numslaves;
//指针数组,指向各个从节点
struct clusterNode **slaves;
//假如这是一个从节点,那么指向主节点
struct clusterNode *slaveof;
unsigned long long last_in_ping_gossip; /* The number of the last carried in the ping gossip section */
//终究一次发送 PING 指令的时刻
mstime_t ping_sent;
//终究一次接纳 PONG 回复的时刻戳
mstime_t pong_received;
mstime_t data_received;
//终究一次被设置为 FAIL 状况的时刻
mstime_t fail_time;
// 终究一次给某个从节点投票的时刻
mstime_t voted_time;
//终究一次从这个节点接纳到仿制偏移里的时刻
mstime_t repl_offset_time;
mstime_t orphaned_time;
//这个节点的仿制偏移里
long long repl_offset;
//节点的 IP 地址
char ip[NET_IP_STR_LEN];
sds hostname; /* The known hostname for this node */
//节点的端口号
int port;
int pport; /* Latest known clients plaintext port. Only used
if the main clients port is for TLS. */
int cport; /* Latest known cluster port of this node. */
//保存衔接节点所需的有关信息
clusterLink *link;
clusterLink *inbound_link; /* TCP/IP link accepted from this node */
//链表,记载了一切其他节点对该节点的下线陈述
list *fail_reports;
} clusterNode;
clusterState
记载当时节点所以为的集群现在所在的状况。
typedef struct clusterState {
//指向当时节点的指针
clusterNode *myself;
//集群当时的装备纪元,用于完结毛病搬运
uint64_t currentEpoch;
// 集群当时的状况:是在线仍是下线
int state;
//集群中至少处理着一个槽的节点的数量。
int size;
//集群节点名单(包括 myself 节点)
//字典的键为节点的姓名,字典的值为 clusterWode 结构
dict *nodes;
dict *shards; /* Hash table of shard_id -> list (of nodes) structures */
//节点黑名单,用于CLUSTER FORGET 指令
//防止被 FORGET 的指令从头被添加到集群里边
dict *nodes_black_list;
//记载要从当时节点搬迁到方针节点的槽,以及搬迁的方针节点
//migrating_slots_to[i]= NULL 表明槽 i 未被搬迁
//migrating_slots_to[i]= clusterNode_A 表明槽i要从本节点搬迁至节点 A
clusterNode *migrating_slots_to[CLUSTER_SLOTS];
//记载要从源节点搬迁到本节点的槽,以及进行搬迁的源节点
//importing_slots_from[i]= NULL 表明槽 i 未进行导入
//importing_slots from[i]=clusterNode A 表明正从节点A中导入槽 i
clusterNode *importing_slots_from[CLUSTER_SLOTS];
//担任处理各个槽的节点
//例如 slots[i]=clusterNode_A 表明槽i由节点A处理
clusterNode *slots[CLUSTER_SLOTS];
rax *slots_to_channels;
//以下这些值被用于进行毛病搬运推举
//前次履行推举或许下次履行推举的时刻
mstime_t failover_auth_time;
//节点取得的投票数量
int failover_auth_count;
//假如值为 1,表明本节点现已向其他节点发送了投票恳求
int failover_auth_sent;
int failover_auth_rank; /* This slave rank for current auth request. */
uint64_t failover_auth_epoch; /* Epoch of the current election. */
int cant_failover_reason; /* Why a slave is currently not able to
failover. See the CANT_FAILOVER_* macros. */
/*共用的手动毛病搬运状况*/
//手动毛病搬运履行的时刻约束
mstime_t mf_end;
/*主服务器的手动毛病搬运状况 */
clusterNode *mf_slave;
/*丛服务器的手动毛病搬运状况 */
long long mf_master_offset;
// 指示手动毛病搬运是否能够开端的标志值 值为非 0 时表明各个主服务器能够开端投票
int mf_can_start;
/*以下这些值由主服务器运用,用于记载推举时的状况*/
//集群终究一次进行投票的纪元
uint64_t lastVoteEpoch;
//在进入下个作业循环之前要做的作业,以各个 flag 来记载
int todo_before_sleep;
/* Stats */
//经过 cluster 衔接发送的音讯数量
long long stats_bus_messages_sent[CLUSTERMSG_TYPE_COUNT];
//经过cluster 接纳到的音讯数量
long long stats_bus_messages_received[CLUSTERMSG_TYPE_COUNT];
long long stats_pfail_nodes; /* Number of nodes in PFAIL status,
excluding nodes without address. */
unsigned long long stat_cluster_links_buffer_limit_exceeded; /* Total number of cluster links freed due to exceeding buffer limit */
} clusterState;
节点的槽指使信息
clusterNode数据结构的slots特点和numslot特点记载了节点担任处理那些槽:
slots特点是一个二进制位数组(bit array),这个数组的长度为16384/8=2048个字节,共包括16384个二进制位。Master节点用bit来标识关于某个槽自己是否具有,时刻复杂度为O(1)
集群一切槽的指使信息
当收到集群中其他节点发送的信息时,经过将节点槽的指使信息保存在本地的clusterState.slots数组里边,程序要查看槽i是否现已被指使,又或许取得担任处理槽i的节点,只需求拜访clusterState.slots[i]的值即可,时刻复杂度仅为O(1)
如上图所示,ClusterState 中保存的 Slots 数组中每个下标对应一个槽,每个槽信息中对应一个 clusterNode 也便是缓存的节点。这些节点会对应一个实践存在的 Redis 缓存服务,包括 IP 和 Port 的信息。Redis Cluster 的通讯机制实践上确保了每个节点都有其他节点和槽数据的对应联系。不管Redis 的客户端拜访集群中的哪个节点都能够路由到对应的节点上,由于每个节点都有一份 ClusterState,它记载了一切槽和节点的对应联系。
集群的恳求重定向
Redis集群在客户端层面是没有选用署理的,而且不管Redis 的客户端拜访集群中的哪个节点都能够路由到对应的节点上,下面来看看 Redis 客户端是怎样经过路由来调用缓存节点的:
MOVED恳求
如上图所示,Redis 客户端经过 CRC16(key)%16383 核算出 Slot 的值,发现需求找“缓存节点1”进行数据操作,可是由于缓存数据搬迁或许其他原因导致这个对应的 Slot 的数据被搬迁到了“缓存节点2”上面。那么这个时分 Redis 客户端就无法从“缓存节点1”中获取数据了。可是由于“缓存节点1”中保存了一切集群中缓存节点的信息,因而它知道这个 Slot 的数据在“缓存节点2”中保存,因而向 Redis 客户端发送了一个 MOVED 的重定向恳求。这个恳求奉告其应该拜访的“缓存节点2”的地址。Redis 客户端拿到这个地址,持续拜访“缓存节点2”而且拿到数据。
ASK恳求
上面的比方阐明晰,数据 Slot 从“缓存节点1”现已搬迁到“缓存节点2”了,那么客户端能够直接找“缓存节点2”要数据。那么假如两个缓存节点正在做节点的数据搬迁,此刻客户端恳求会怎样处理呢?
Redis 客户端向“缓存节点1”宣布恳求,此刻“缓存节点1”正向“缓存节点 2”搬迁数据,假如没有射中对应的 Slot,它会回来客户端一个 ASK 重定向恳求而且奉告“缓存节点2”的地址。客户端向“缓存节点2”发送 Asking 指令,问询需求的数据是否在“缓存节点2”上,“缓存节点2”接到音讯今后回来数据是否存在的成果。
频频重定向形成的网络开支的处理:smart客户端
什么是 smart客户端:
在大部分状况下,或许都会呈现一次恳求重定向才干找到正确的节点,这个重定向进程显然会添加集群的网络担负和单次恳求耗时。所以大部分的客户端都是smart的。所谓 smart客户端,便是指客户端本地保护一份hashslot => node的映射表缓存,大部分状况下,直接走本地缓存就能够找到hashslot => node,不需求经过节点进行moved重定向,
JedisCluster的作业原理:
- 在JedisCluster初始化的时分,就会随机挑选一个node,初始化hashslot => node映射表,一起为每个节点创立一个JedisPool衔接池。
- 每次依据JedisCluster履行操作时,首要会在本地核算key的hashslot,然后在本地映射表找到对应的节点node。
- 假如那个node正好仍是持有那个hashslot,那么就ok;假如进行了reshard操作,或许hashslot现已不在那个node上了,就会回来moved。
- 假如JedisCluter API发现对应的节点回来moved,那么运用该节点回来的元数据,更新本地的hashslot => node映射表缓存
- 重复上面几个进程,直到找到对应的节点,假如重试超越5次,那么就报错,JedisClusterMaxRedirectionException
hashslot搬迁和ask重定向:
假如hashslot正在搬迁,那么会回来ask重定向给客户端。客户端接纳到ask重定向之后,会从头定位到方针节点去履行,可是由于ask产生在hashslot搬迁进程中,所以JedisCluster API收到ask是不会更新hashslot本地缓存。
尽管ASK与MOVED都是对客户端的重定向操控,可是有本质区别。ASK重定向阐明集群正在进行slot数据搬迁,客户端无法知道搬迁什么时分完结,因而只能是临时性的重定向,客户端不会更新slots缓存。可是MOVED重定向阐明键对应的槽现已清晰指定到新的节点,客户端需求更新slots缓存。
Redis集群中节点的通讯机制:goosip协议
redis集群的哈希槽算法处理的是数据的存取问题,不同的哈希槽坐落不同的节点上,而不同的节点保护着一份它所以为的当时集群的状况,一起,Redis集群是去中心化的架构。那么,当集群的状况产生改变时,比方新节点参加、slot搬迁、节点宕机、slave进步为新Master等等,咱们期望这些改变尽快被其他节点发现,Redis是怎样进行处理的呢?也便是说,Redis不同节点之间是怎样进行通讯进行保护集群的同步状况呢?
在Redis集群中,不同的节点之间选用gossip协议进行通讯,节点之间通讯的意图是为了保护节点之间的元数据信息。这些元数据便是每个节点包括哪些数据,是否呈现毛病,经过gossip协议,到达终究数据的共同性。
gossip协议,是依据流行病传达方法的节点或许进程之间信息交流的协议。原理便是在不同的节点间不断地通讯交流信息,一段时刻后,一切的节点就都有了整个集群的完好信息,而且一切节点的状况都会到达共同。每个节点或许知道一切其他节点,也或许仅知道几个街坊节点,但只需这些节能够经过网络连通,终究他们的状况就会是共同的。Gossip协议最大的长处在于,即便集群节点的数量添加,每个节点的负载也不会添加许多,几乎是稳定的。
Redis集群中节点的通讯进程如下:
- 集群中每个节点都会独自开一个TCP通道,用于节点间相互通讯。
- 每个节点在固定周期内经过待定的规矩挑选几个节点发送ping音讯
- 接纳到ping音讯的节点用pong音讯作为呼应
运用gossip协议的长处在于将元数据的更新涣散在不同的节点上面,下降了压力;可是缺陷便是元数据的更新有延时,或许导致集群中的一些操作会有一些滞后。别的,由于 gossip 协议对服务器时刻的要求较高,时刻戳不精确会影响节点判别音讯的有效性。而且节点数量增多后的网络开支也会对服务器产生压力,一起结点数太多,意味着到达终究共同性的时刻也相对变长,因而官方引荐最大节点数为1000左右。
redis cluster架构下的每个redis都要敞开两个端口号,比方一个是6379,另一个便是加1w的端口号16379。
- 6379端口号便是redis服务器进口。
- 16379端口号是用来进行节点间通讯的,也便是 cluster bus 的东西,cluster bus 的通讯,用来进行毛病检测、装备更新、毛病搬运授权。cluster bus 用的便是gossip 协议
集群的扩容与缩短
作为散布式布置的缓存节点总会遇到缓存扩容和缓存毛病的问题。这就会导致缓存节点的上线和下线的问题。由于每个节点中保存着槽数据,因而当缓存节点数呈现变化时,这些槽数据会依据对应的虚拟槽算法被搬迁到其他的缓存节点上。所以关于redis集群,集群弹性首要在于槽和数据在节点之间移动。
扩容
- 发动新节点
- 运用cluster meet指令将新节点参加到集群
- 搬迁槽和数据:添加新节点后,需求将一些槽和数据从旧节点搬迁到新节点
如上图所示,集群中原本存在“缓存节点1”和“缓存节点2”,此刻“缓存节点3”上线了而且参加到集群中。此刻依据虚拟槽的算法,“缓存节点1”和“缓存节点2”中对应槽的数据会应该新节点的参加被搬迁到“缓存节点3”上面。
新节点参加到集群的时分,作为孤儿节点是没有和其他节点进行通讯的。因而需求在集群中恣意节点履行 cluster meet 指令让新节点参加进来。假定新节点是 192.168.1.1 5002,老节点是 192.168.1.1 5003,那么运转以下指令将新节点参加到集群中。
192.168.1.1 5003> cluster meet 192.168.1.1 5002
这个是由老节点建议的,有点老成员欢迎新成员参加的意思。新节点刚刚树立没有树立槽对应的数据,也便是说没有缓存任何数据。假如这个节点是主节点,需求对其进行槽数据的扩容;假如这个节点是从节点,就需求同步主节点上的数据。总归便是要同步数据。
如上图所示,由客户端建议节点之间的槽数据搬迁,数据从源节点往方针节点搬迁。
- 客户端对方针节点建议预备导入槽数据的指令,让方针节点预备好导入槽数据。这儿运用 cluster setslot {slot} importing {sourceNodeId} 指令。
- 之后对源节点建议送指令,让源节点预备迁出对应的槽数据。运用指令 cluster setslot {slot} importing {sourceNodeId}。
- 此刻源节点预备搬迁数据了,在搬迁之前把要搬迁的数据获取出来。经过指令 cluster getkeysinslot {slot} {count}。Count 表明搬迁的 Slot 的个数。
- 然后在源节点上履行,migrate {targetIP} {targetPort} “” 0 {timeout} keys {keys} 指令,把获取的键经过流水线批量搬迁到方针节点。
- 重复 3 和 4 两步不断将数据搬迁到方针节点。
- 完结数据搬迁到方针节点今后,经过 cluster setslot {slot} node {targetNodeId} 指令告诉对应的槽被分配到方针节点,而且播送这个信息给全网的其他主节点,更新本身的槽节点对应表。
缩短
- 搬迁槽。
- 忘掉节点。经过指令 cluster forget {downNodeId} 告诉其他的节点
为了安全删去节点,Redis集群只能下线没有担任槽的节点。因而假如要下线有担任槽的master节点,则需求先将它担任的槽搬迁到其他节点。搬迁的进程也与上线操作相似,不同的是下线的时分需求告诉全网的其他节点忘掉自己,此刻经过指令 cluster forget {downNodeId}
告诉其他的节点。
集群的毛病检测与毛病转康复机制:
集群的毛病检测
Redis集群的毛病检测是依据gossip协议的,集群中的每个节点都会守时地向集群中的其他节点发送PING音讯,以此交流各个节点状况信息,检测各个节点状况:在线状况、疑似下线状况PFAIL、已下线状况FAIL。
片面下线(pfail)
当节点A检测到与节点B的通讯时刻超越了cluster-node-timeout 的时分,就会更新本地节点状况,把节点B更新为片面下线。
片面下线并不能代表某个节点真的下线了,有或许是节点A与节点B之间的网络断开了,可是其他的节点仍旧能够和节点B进行通讯。
客观下线
由于集群内的节点会不断地与其他节点进行通讯,下线信息也会经过 Gossip 音讯传遍一切节点,因而集群内的节点会不断收到下线陈述。
当半数以上的主节点符号了节点B是片面下线时,便会触发客观下线的流程(该流程只针对主节点,假如是从节点就会疏忽)。将片面下线的陈述保存到本地的 ClusterNode 的结构fail_reports链表中,而且对片面下线陈述的时效性进行查看,假如超越 cluster-node-timeout*2 的时刻,就疏忽这个陈述,不然就记载陈述内容,将其符号为客观下线。
接着向集群播送一条主节点B的Fail 音讯,一切收到音讯的节点都会符号节点B为客观下线。
集群地毛病康复
当毛病节点下线后,假如是持有槽的主节点则需求在其从节点中找出一个替换它,然后确保高可用。此刻下线主节点的一切从节点都担负着康复责任,这些从节点会守时监测主节点是否进入客观下线状况,假如是,则触发毛病康复流程。毛病康复也便是推举一个节点充任新的master,推举的进程是依据Raft协议推举方法来完结的。
-
从节点过滤:查看每个slave节点与master节点断开衔接的时刻,假如超越了cluster-node-timeout * cluster-slave-validity-factor,那么就没有资历切换成master
-
投票推举:
-
节点排序:对经过过滤条件的一切从节点进行排序,依照priority、offset、run id排序,排序越靠前的节点,越优先进行推举。 (在这步排序抢先的从节点通常会取得更多的票,由于它触发推举的时刻更早一些,取得票的时机更大)
-
priority的值越低,优先级越高
-
offset越大,表明从master节点仿制的数据越多,推举时刻越靠前,优先进行推举
-
假如offset相同,run id越小,优先级越高
-
-
更新装备纪元:每个主节点会去更新装备纪元(clusterNode.configEpoch),这个值是不断添加的整数。这个值记载了每个节点的版别和整个集群的版别。每逢产生重要作业的时分(例如:呈现新节点,从节点精选)都会添加大局的装备纪元而且赋给相关的主节点,用来记载这个作业。更新这个值意图是,确保一切主节点对这件“大事”保持共同,我们都统一成一个装备纪元,表明我们都知道这个“大事”了。
-
建议推举:更新完装备纪元今后,从节点会向集群建议播送推举的音讯(
CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST
),要求一切收到这条音讯,而且具有投票权的主节点进行投票。每个从节点在一个纪元中只能建议一次推举。 -
推举投票:假如一个主节点具有投票权,而且这个主节点没有投票给其他从节点,那么主节点将向要求投票的从节点回来一条
CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
音讯,表明这个主节点支撑从节点成为新的主节点。每个参加推举的从节点都会接纳CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK
音讯,并依据自己收到了多少条这种音讯来计算自己取得了多少主节点的支撑。假如超越(N/2 + 1)数量的master节点都投票给了某个从节点,那么推举经过,这个从节点能够切换成master,假如在 cluster-node-timeout*2 的时刻内从节点没有取得满意数量的票数,本次推举报废,更新装备纪元,并进行第二轮推举,直到选出新的主节点停止。
-
-
替换主节点:当满意投票条件的从节点被选出来今后,会触发替换主节点的操作。删去原主节点担任的槽数据,把这些槽数据添加到自己节点上,而且播送让其他的节点都知道这件作业,新的主节点诞生了。
- 被选中的从节点履行
SLAVEOF NO ONE
指令,使其成为新的主节点 - 新的主节点会吊销一切对已下线主节点的槽指使,并将这些槽悉数指使给自己
- 新的主节点对集群进行播送PONG音讯,奉告其他节点现已成为新的主节点
- 的主节点开端接纳和处理槽相关的恳求
- 被选中的从节点履行
补白:假如集群中某个节点的master和slave节点都宕机了,那么集群就会进入fail状况,由于集群的slot映射不完好。假如集群超越半数以上的master挂掉,不管是否有slave,集群都会进入fail状况。
Redis集群的运维
数据搬迁问题
Redis集群能够进行节点的动态扩容缩容,这一进程现在还处于半自动状况,需求人工介入。在扩缩容的时分,需求进行数据搬迁。而 Redis为了确保搬迁的共同性,搬迁一切操作都是同步操作,履行搬迁时,两头的 Redis均会进入时长不等的堵塞状况,关于小Key,该时刻能够疏忽不计,但假如一旦Key的内存运用过大,严峻的时分会接触发集群内的毛病搬运,形成不必要的切换。
带宽耗费问题
Redis集群是无中心节点的集群架构,依托Gossip协议协同自动化修正集群的状况,但goosip有音讯延时和音讯冗余的问题,在集群节点数量过多的时分,goosip协议通讯会耗费很多的带宽,首要体现在以下几个方面:
- 音讯发送频率:跟cluster-node-timeout密切相关,当节点发现与其他节点的终究通讯时刻超越 cluster-node-timeout/2时会直接发送ping音讯
- 音讯数据量:每个音讯首要的数据占用包括:slots槽数组(2kb)和整个集群1/10的状况数据
- 节点布置的机器规划:机器的带宽上限是固定的,因而相同规划的集群散布的机器越多,每台机器区分的节点越均匀,则整个集群内全体的可用带宽越高
也便是说,每个节点的slot不能有太多,不然集群节点之间相互通讯时,redis会有很多的时刻和带宽在完结通讯
集群带宽耗费首要分为:读写指令耗费+Gossip音讯耗费,因而建立Redis集群需求依据事务数据规划和音讯通讯本钱做出合理规划:
- 在满意事务需求的状况下尽量防止大集群,同一个体系能够针对不同事务场景拆分运用若干个集群。
- 适度供给cluster-node-timeout下降音讯发送频率,可是cluster-node-timeout还影响毛病搬运的速度,因而需求依据本身事务场景统筹二者平衡
- 假如条件答应尽量均匀布置在更多机器上,防止会集布置。假如有60个节点的集群布置在3台机器上每台20个节点,这是机器的带宽耗费将十分严峻
Pub/Sub播送问题
集群形式下内部对一切publish指令都会向一切节点进行播送,加剧带宽担负,所以集群应该防止频频运用Pub/sub功用
集群歪斜
集群歪斜是指不同节点之间数据量和恳求量呈现显着差异,这种状况将加大负载均衡和开发运维的难度。因而需求了解集群歪斜的原因
-
数据歪斜:
-
节点和槽分配不均
-
不同槽对应键数量差异过大
-
调集目标包括很多元素
-
内存相关装备不共同
-
-
恳求歪斜:合理规划键,热门大调集目标做拆分或许运用hmget替代hgetall防止全体读取
集群读写别离
集群形式下读写别离本钱比较高,直接扩展主节点数量来进步集群功能是更好的挑选。
面试题专栏
Java面试题专栏已上线,欢迎拜访。
- 假如你不知道简历怎样写,简历项目不知道怎样包装;
- 假如简历中有些内容你不知道该不该写上去;
- 假如有些归纳性问题你不知道怎样答;
那么能够私信我,我会尽我所能协助你。