Redis Cluster(集群模式)
假如我们的用户量千万,需要缓存的数据越来越大,我们应该怎么处理呢?
纵向扩展:升级单个 Redis 实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的 CPU。
横向扩展:横向增加当前 Redis 实例的个数,把数据等分成几个部分。
虽然纵向扩展简单直接,直接扩大内存就好了,但是有一些缺点:
- 硬件限制,比如我们有1TB的内存数据,单机就很难支持了,线上机器实例很少会这样配置,有也不给你 Redis 。
- 持久化,大数据量持久化时,
fork
导致主线程阻塞看,数据越大,阻塞时间越长
从 3.0 开始,官方提供了一个名为 Redis Cluster
的方案,Redis Cluster
是 Redis 中一种高可用的框架,用于实现切片集群。Redis Cluster
方案中就规定了数据和实例的对应规则。
将单机 Redis 转向为 多机集群 Redis。
集群通信
一个 Redis 集群由多个节点组成,各个节点之间是怎么通信的呢?通过 Gossip 协议!(也叫Epidemic Protocol流行病协议
)
我们希望这些变化能够让整个集群的每个节点能够尽快发现,那么各个节点之间就需要相互连通并且携带相关状态数据进行传播,这就用到了 Gossip 协议。
你可能会想到用广播的方式不也可以实现,答案是当然可以,但是对CPU和带宽的消耗比较大,所用还是采用 Goosip 协议。
该协议的特点是,在节点数量有限的网络中,每个节点都会“随机”(也不是真正的随机,而是根据规则选择通信节点)与部分节点通信,经过一番杂乱无章(传染病)的通信后,每个节点的状态可以在一定时间内达成一致。
常用的 Gossip 消息分为4种,分别是:ping、pong、meet、fail。
meet 消息:通知新节点加入,当消息发送者接到客户端发送
CLUSTER MEET
命令时,消息发送者会向接收者发送 meet 消息,之后消息发送者通知接收者加入到当前集群。meet 消息通信正常完成后,接收节点会加入到集群中并进行周期性的 ping、pong 消息交换。ping 消息:集群内交换最频繁的消息,集群内每个节点每秒向多个其他节点发送 ping 消息,该信息包含自己的状态还有维护的集群元数据,用于检测节点是否在线和交换彼此状态信息。
pong 消息:当接收到 ping、meet 消息时,作为响应消息回复给发送方确认消息正常通信,返回 ping 和 meet ,包含自己的状态和其它信息。节点也可以向集群内广播自身的 pong 消息来通知整个集群对自身状态进行更新。
fail消息:当节点判定集群内另一个节点下线时,会向集群内广播一个 fail 消息,其他节点接收到 fail 消息之后把对应节点更新为下线状态。
数据切片后如何在多个实例分布?
Redis Cluster 方案采用哈希槽(Hash Slot,接下来我会直接称之为 Slot)来处理数据和实例之间的映射关系。在 Redis Cluster
方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。
具体的映射过程分为两大步:首先根据键值对的 key,按照 CRC16 算法计算一个 16bit 的值;然后,再用这个 16bit 值对16384取模,得到0~16383范围内的模数,每个模数代表一个相应编号的哈希槽。
使用Redis Cluster 方案时,可以使用 cluster create
命令创建集群,此时 Redis 会自动把这些槽平均分布在集群实例上。例如,如果集群中有 N 个实例,每个实例上的槽个数为 16384/N 个。
当然我们也可以手动设置机器上面的hash槽个数,应对线上机器不同配置的情况,这个大家去查看官方文档就好了。
客户端怎么确定数据在哪个实例上?
假设数据一成不变
在定位键值对数据时,客户端发送请求时,来计算它所处的哈希槽。但是,要进一步定位到实例,还需要知道哈希槽分布在哪个实例上。
但集群模式下,Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。
当然,有一些特殊情况,hash槽对应的实例会有变化
- 在集群中,实例有新增或删除,Redis 需要重新分配哈希槽。
- 为了负载均衡,Redis 需要把哈希槽在所有实例上重新分布一遍。
此时客户端缓存的数据就不准了,可能出现以下情景:
本地缓存的实例ip是192.168.0.1,但是此时该hash槽的对应ip变成了192.168.0.2。
MOVED 命令含义:表示请求的key,对应的 hash 槽与对应的实例信息,然后客户端只需要重新在对应的实例去操作就可以了。
当迁移的数据量过大时,就可能出现一种情况,请求时这个 hash 槽只迁移了一部分数据到新实例,还有一部分数据在老实例。
ASK 命令含义,当在 Redis Cluster
中使用 ASK(Ask Redirect)返回报错时,通常表示在执行命令时客户端与集群之间发生了某种异常情况。ASK 是 Redis Cluster
中的一种特殊机制,用于在槽迁移时指示客户端重定向到另一个节点。
优缺点分析
优点:
- Redis Cluster 采用分布式架构,自动将数据分片存储在多个节点上,提供了良好的横向扩展性和高可用性。
- 集群节点可以自动发现和重新分片,并且支持节点动态扩容和缩减,减少了集群管理的复杂性。
- 当新的节点加入或离开集群时,Redis Cluster 能够自动进行节点发现和重新分片,而无需手动干预,这简化了集群管理的复杂度。
缺点:
- Redis Cluster 不支持跨分片的事务操作,事务必须在同一分片上执行,这可能会在某些场景下带来限制。
- 配置和管理 Redis Cluster 相对复杂,需要理解分布式系统的原理和网络分区等问题。需要投入更多的精力来实施和维护集群。
综上所述,集群模式极大的降低了实例的数据量,适合大规模的 Redis。
Cluster Proxy(集群代理)
Proxy 模式通过在 Redis 客户端和服务端之间插入代理(Proxy)来实现负载均衡、故障转移和数据分片等功能。Proxy 可以根据负载情况将请求分发到不同的 Redis 节点上,并在节点故障时自动切换到备用节点。Proxy 模式提供了更灵活的架构设计和更好的可扩展性,但也增加了系统的复杂性和延迟。
优点:
- 负载均衡: Redis Proxy可以实现负载均衡,将客户端请求分发到多个后端的 Redis 服务器上,从而平衡集群中各个节点的负载,提高系统的整体性能和吞吐量。
- 故障转移: 当后端的 Redis 服务器出现故障或不可用时,Redis Proxy可以自动将请求重新路由到其他可用的节点上,从而实现故障转移,保证系统的高可用性。
- 数据分片: Redis Proxy可以将数据分片存储在多个后端的Redis服务器上,并根据数据的键来选择合适的服务器,从而增加系统的存储容量和并发处理能力。
- 协议转换: Redis Proxy 可以支持多种 Redis 协议,如 RESP( REdis Serialization Protocol)、Memcached 协议等,可以根据客户端的请求协议,将请求转换成后端服务器所支持的协议格式。
- 缓存: 一些 Redis Proxy 还提供了缓存功能,可以缓存常用的请求结果,并在后续的请求中直接返回缓存的结果,对于热点数据,非常好用。
缺点:
- 单点故障: Redis Proxy 本身也可能成为系统的单点故障,如果 Proxy 出现故障或不可用,会影响整个系统的稳定性和可用性。
- 性能损耗: 由于 Redis Proxy 介于客户端和后端 Redis 服务器之间,数据传输需要经过额外的中间层,可能会引入一定的性能损耗和延迟。
- 复杂性: 引入 Redis Proxy 会增加系统的复杂性,需要额外的管理和维护工作,包括配置管理、监控和故障排查等,增加了系统的开发和运维成本。
- 一致性问题: 如果 Redis Proxy 缓存了部分数据,并且与后端 Redis 服务器之间存在数据不一致的情况,可能会导致数据一致性的问题,需要谨慎处理。
综上所述,集群代理模式虽然相比于集群模式优化了一些地方,但同时也出现了一些缺陷。集群代理模式整体像哨兵模式,但是相比于哨兵模式它的适用规模更大。
评论(0)