Redis高可用篇:Cluster集群能支持的数据量有多大?(三)

简介: 接上文。

客户端如何定位数据所在实例


65 哥:客户端又怎么确定访问的数据到底分布在哪个实例上呢?


Redis 实例会将自己的哈希槽信息通过 Gossip 协议发送给集群中其他的实例,实现了哈希槽分配信息的扩散。


这样,集群中的每个实例都有所有哈希槽与实例之间的映射关系信息。


在切片数据的时候是将 key 通过 CRC16 计算出一个值再对 16384 取模得到对应的 Slot,这个计算任务可以在客户端上执行发送请求的时候执行。


但是,定位到槽以后还需要进一步定位到该 Slot 所在 Redis 实例。


当客户端连接任何一个实例,实例就将哈希槽与实例的映射关系响应给客户端,客户端就会将哈希槽与实例映射信息缓存在本地。


当客户端请求时,会计算出键所对应的哈希槽,在通过本地缓存的哈希槽实例映射信息定位到数据所在实例上,再将请求发送给对应的实例。


image.png


重新分配哈希槽


65 哥:哈希槽与实例之间的映射关系由于新增实例或者负载均衡重新分配导致改变了咋办?


集群中的实例通过 Gossip 协议互相传递消息获取最新的哈希槽分配信息,但是,客户端无法感知。


Redis Cluster 提供了重定向机制:客户端将请求发送到实例上,这个实例没有相应的数据,该 Redis 实例会告诉客户端将请求发送到其他的实例上


65 哥:Redis 如何告知客户端重定向访问新实例呢?


分为两种情况:MOVED 错误、ASK 错误


MOVED 错误


MOVED 错误(负载均衡,数据已经迁移到其他实例上):当客户端将一个键值对操作请求发送给某个实例,而这个键所在的槽并非由自己负责的时候,该实例会返回一个 MOVED 错误指引转向正在负责该槽的节点。


GET 公众号:码哥字节
(error) MOVED 16330 172.17.18.2:6379


该响应表示客户端请求的键值对所在的哈希槽 16330 迁移到了 172.17.18.2 这个实例上,端口是 6379。这样客户端就与 172.17.18.2:6379 建立连接,并发送 GET 请求。


同时,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确


image.png


ASK 错误


65 哥:如果某个 slot 的数据比较多,部分迁移到新实例,还有一部分没有迁移咋办?


如果请求的 key 在当前节点找到就直接执行命令,否则时候就需要 ASK 错误响应了,槽部分迁移未完成的情况下,如果需要访问的 key 所在 Slot 正在从从 实例 1 迁移到 实例 2,实例 1 会返回客户端一条 ASK 报错信息:客户端请求的 key 所在的哈希槽正在迁移到实例 2 上,你先给实例 2 发送一个 ASKING 命令,接着发发送操作命令


GET 公众号:码哥字节
(error) ASK 16330 172.17.18.2:6379


比如客户端请求定位到 key = 「公众号:码哥字节」的槽 16330 在实例 172.17.18.1 上,节点 1 如果找得到就直接执行命令,否则响应 ASK 错误信息,并指引客户端转向正在迁移的目标节点 172.17.18.2。


image.png


注意:ASK 错误指令并不会更新客户端缓存的哈希槽分配信息


所以客户端再次请求 Slot 16330 的数据,还是会先给 172.17.18.1 实例发送请求,只不过节点会响应 ASK 命令让客户端给新实例发送一次请求。


MOVED指令则更新客户端本地缓存,让后续指令都发往新实例。


集群可以设置多大?


65 哥:有了 Redis Cluster,再也不怕大数据量了,我可以无限水平拓展么?


答案是否定的,Redis 官方给的 Redis Cluster 的规模上线是 1000 个实例


65 哥:到底是什么限制了集群规模呢?


关键在于实例间的通信开销,Cluster 集群中的每个实例都保存所有哈希槽与实例对应关系信息(Slot 映射到节点的表),以及自身的状态信息。


在集群之间每个实例通过 Gossip协议传播节点的数据,Gossip 协议工作原理大概如下:


  1. 从集群中随机选择一些实例按照一定的频率发送 PING 消息发送给挑选出来的实例,用于检测实例状态以及交换彼此的信息。 PING 消息中封装了发送者自身的状态信息、部分其他实例的状态信息、Slot 与实例映射表信息。


  1. 实例接收到 PING 消息后,响应 PONG 消息,消息包含的信息跟 PING 消息一样。

集群之间通过 Gossip协议可以在一段时间之后每个实例都能获取其他所有实例的状态信息。


所以在有新节点加入,节点故障,Slot 映射变更都可以通过 PINGPONG 的消息传播完成集群状态在每个实例的传播同步。


Gossip 消息


发送的消息结构是 clusterMsgDataGossip结构体组成:


typedef struct {
    char nodename[CLUSTER_NAMELEN];  //40字节
    uint32_t ping_sent; //4字节
    uint32_t pong_received; //4字节
    char ip[NET_IP_STR_LEN]; //46字节
    uint16_t port;  //2字节
    uint16_t cport;  //2字节
    uint16_t flags;  //2字节
    uint32_t notused1; //4字节
} clusterMsgDataGossip;


所以每个实例发送一个 Gossip消息,就需要发送 104 字节。如果集群是 1000 个实例,那么每个实例发送一个 PING 消息则会占用 大约 10KB。


除此之外,实例间在传播 Slot 映射表的时候,每个消息还包含了 一个长度为 16384 bit 的 Bitmap


每一位对应一个 Slot,如果值 = 1 则表示这个 Slot 属于当前实例,这个 Bitmap 占用 2KB,所以一个 PING 消息大约 12KB。


PONGPING 消息一样,一发一回两个消息加起来就是 24 KB。集群规模的增加,心跳消息越来越多就会占据集群的网络通信带宽,降低了集群吞吐量。


实例的通信频率


65 哥:码哥,发送 PING 消息的频率也会影响集群带宽吧?


Redis Cluster 的实例启动后,默认会每秒从本地的实例列表中随机选出 5 个实例,再从这 5 个实例中找出一个最久没有收到 PING 消息的实例,把 PING 消息发送给该实例。


65 哥:随机选择 5 个,但是无法保证选中的是整个集群最久没有收到 PING 通信的实例,有的实例可能一直没有收到消息,导致他们维护的集群信息早就过期了,咋办呢?


这个问题问的好,Redis Cluster 的实例每 100 ms 就会扫描本地实例列表,当发现有实例最近一次收到 PONG 消息的时间 > cluster-node-timeout / 2。那么就立刻给这个实例发送 PING 消息,更新这个节点的集群状态信息。


当集群规模变大,就会进一步导致实例间网络通信延迟怎加。可能会引起更多的 PING 消息频繁发送。


降低实例间的通信开销


  • 每个实例每秒发送一条 PING消息,降低这个频率可能会导致集群每个实例的状态信息无法及时传播。


  • 每 100 ms 检测实例 PONG消息接收是否超过 cluster-node-timeout / 2,这个是 Redis 实例默认的周期性检测任务频率,我们不会轻易修改。


所以,只能修改 cluster-node-timeout的值:集群中判断实例是否故障的心跳时间,默认 15 S。


所以,为了避免过多的心跳消息占用集群宽带,将 cluster-node-timeout调成 20 秒或者 30 秒,这样 PONG 消息接收超时的情况就会缓解。


但是,也不能设置的太大。都则就会导致实例发生故障了,却要等待 cluster-node-timeout时长才能检测出这个故障,影响集群正常服务


总结


「码哥字节」不跟风不扯淡,助力程序员成长。


《Redis 系列》至今已发布 7 篇,每一篇「码哥字节」都耗费大量精力,精益求精。确保每一篇都给读者带来价值,让大家得到真正的提升。


  • 哨兵集群实现故障自动转移,但是当数据量过大导致生成 RDB 时间过长。而 Fork 执行的时候会阻塞主线程,由于数据量过大导致阻塞主线程过长,所以出现了 Redis 响应慢的表象。


  • 使用 Redis Cluster 集群,主要解决了大数据量存储导致的各种慢问题,同时也便于横向拓展。在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择。


  • 集群的整个数据库被分为 16384 个槽(slot),数据库中的每个键都属于这 16384 个槽的其中一个,集群中的每个节点可以处理 0 个或最多 16384 个槽。


  • Redis 集群节点采用 Gossip 协议来广播自己的状态以及自己对整个集群认知的改变。


  • 客户端连接到集群候任何一个实例后,实例会将哈希槽与实例映射信息发送给客户端,客户端将信息保存,用于将 key 定位到对应的节点。


  • 集群并不能无限增加,由于集群通过 Gossip协议传播集群实例信息,所以通信频率是限制集群大小的主要原因,主要可以通过修改 cluster-node-timeout调整频率。


原创不易,如果觉得文章不错,希望读者朋友点赞、收藏和分享。

相关文章
|
8月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
552 2
|
6月前
|
NoSQL Java 网络安全
SpringBoot启动时连接Redis报错:ERR This instance has cluster support disabled - 如何解决?
通过以上步骤一般可以解决由于配置不匹配造成的连接错误。在调试问题时,一定要确保服务端和客户端的Redis配置保持同步一致。这能够确保SpringBoot应用顺利连接到正确配置的Redis服务,无论是单机模式还是集群模式。
578 5
|
存储 NoSQL 数据库
Redis 逻辑数据库与集群模式详解
Redis 是高性能内存键值数据库,广泛用于缓存与实时数据处理。本文深入解析 Redis 逻辑数据库与集群模式:逻辑数据库提供16个独立存储空间,适合小规模隔离;集群模式通过分布式架构支持高并发和大数据量,但仅支持 database 0。文章对比两者特性,讲解配置与实践注意事项,并探讨持久化及性能优化策略,助你根据需求选择最佳方案。
756 5
|
6月前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
750 6
|
7月前
|
存储 监控 NoSQL
Redis高可用架构全解析:从主从复制到集群方案
Redis高可用确保服务持续稳定,避免单点故障导致数据丢失或业务中断。通过主从复制实现数据冗余,哨兵模式支持自动故障转移,Cluster集群则提供分布式数据分片与水平扩展,三者层层递进,保障读写分离、容灾切换与大规模数据存储,构建高性能、高可靠的Redis架构体系。
|
9月前
|
负载均衡 NoSQL Redis
【赵渝强老师】Redis的主从复制集群
Redis主从复制是指将一台Redis服务器的数据复制到其他Redis服务器,实现数据热备份、故障恢复、负载均衡及高可用架构的基础。主节点负责写操作,从节点同步数据并可提供读服务,提升并发处理能力。
273 5
|
8月前
|
存储 NoSQL 算法
Redis的集群架构与使用经验
本文介绍了Redis的集群架构与使用经验,包括主从复制、哨兵集群及Cluster分片集群的应用场景与实现原理。内容涵盖Redis主从同步机制、数据分片存储方式、事务支持及与Memcached的区别,并讨论了Redis内存用尽时的处理策略。适用于了解Redis高可用与性能优化方案。
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
|
机器学习/深度学习 NoSQL Redis
Redis高可用之集群架构(第三部分)
Redis高可用之集群架构(第三部分)
|
Kubernetes NoSQL Redis
教你在 Kubernetes 上部署 Redis 高可用集群?
教你在 Kubernetes 上部署 Redis 高可用集群?
937 0
下一篇
开通oss服务