Redis 是一种盛行的内存数据存储,以其速率和灵巧性而有名。当特定事情负载的内存和打算需求可以在单个节点内管理时,它就能高效运行。然而,超出单个节点的扩展常日会导致考虑 Redis 集群。人们普遍认为过渡到 Redis 集群很大略,现有运用程序的行为也将相同,但实际情形并非如此。虽然 Redis 集群办理了某些扩展问题,但它也带来了巨大的繁芜性。这篇文章将谈论 Redis 集群扩展的局限性,并先容一些可以知足许多组织需求的更大略的替代方案。
一、什么是Redis集群?Redis 集群是一种分布式实现,许可您在多个主 Redis 实例之间自动共享数据,从而实现水平扩展。在 Redis 集群设置中,键空间被分为 16384 个哈希槽,有效地设置了16384个主实例的集群大小上限。然而,实际上,建议的最大大小约为 1000 个主实例。集群中的每个主实例管理这16384个哈希槽的特定子集。为了确保高可用性,每个主实例可以与一个或多个副本实例配对。这种方法涉及跨多个实例的数据分片以实现可扩展性和复制以实现冗余,是许多分布式数据存储系统中的常见模式。一个具有三个主 Redis 实例的集群,每个主实例有一个副本,如下所示:
Redis实例

正如您所看到的,Redis Cluster 具有优雅的设计。但在没有深入研究实现细节的情形下,我们已经先容了多个观点(分片、哈希槽等),只是为了有一个基本的理解。我们将不才面磋商更多寻衅。
二、水平扩展的寻衅虽然 Redis 集群常日被认为仅仅是独立 Redis 上的一个设置,但它在很多方面都有所不同。这意味着迁移到 Redis 集群充满了隐蔽的寻衅,纵然是履历丰富的开拓职员也会感到惊异。
客户端库哀求
从客户端库的角度来看,利用 Redis Cluster 须要适应不同的接口。这意味着您很可能须要利用特定于集群的客户端库 - 用于独立 Redis 的现有客户端将无法在集群中开箱即用。我们以go-redis Redis为例。当连接到独立的Redis时,可以利用以下代码片段连接到具有指定主机、密码和逻辑数据库的实例:
import "github.com/redis/go-redis/v9"rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // 未设置密码 DB: 0, // 利用默认逻辑数据库 0(稍后详细先容)})
同一个包供应了特定于集群的客户端,但须要把稳的是,它们是不同的构造:redis.Client用于独立 Redis 和redis.ClusterClient用于 Redis 集群。与初始化过程redis.ClusterClient有所不同,如下所示。这种差异至关主要,由于redis.ClusterClient内部利用多个redis.Client工具来管理与集群中所有节点的通信。此设置中的每个redis.Client都掩护其单独的连接池。
import "github.com/redis/go-redis/v9"rdb := redis.NewClusterClient(&redis.ClusterOptions{ Addrs: []string{ "localhost:7001", "localhost:7002", "localhost:7003", "localhost:7004", "localhost:7005", },})
附带解释的是,该go-redis包还供应了一个redis.UniversalClient接口来简化初始化过程,但它只是不同类型客户端之上的一个抽象层。要利用 Redis 集群,须要开拓如上所述的特定于集群的客户端来知足集群的其他哀求。
多键操作
Redis 中的多键操作是指同时浸染于多个键的命令或命令集。例如,该MSET命令是单个命令,可以在单个原子操作中将多个键设置为多个值。类似地,事务或 Lua 脚本常日涉及多个键,但并非总是如此。Redis 集群的一个关键限定是它无法处理多键操作,除非所涉及的键共享相同的主题标签,如此处规范中所述。您须要仔细检讨运用程序中的所有多键操作,并且须要修正这些操作以避免利用多键操作或仅在同一主题标签的高下文中利用它们。
逻辑数据库
在 Redis 中,逻辑数据库实质上是同一 Redis 实例中的单独键空间。Redis 支持多个数据库,这些数据库由数据库索引(一个大略的整数)来标识。除非另有解释,Redis 客户端在连接时常日利用默认数据库 database 0。利用逻辑数据库可以是分离不同类型数据的有效策略(例如,将会话数据与运用程序数据隔离)。您可以利用该SELECT命令在不同的逻辑数据库之间进行切换。但是,正如SELECT命令文档中所指定的,您将失落去 Redis 集群的这种隔离。因此,如果您要过渡到 Redis 集群,则须要从头开始完备重新构建键空间架构。
设置和掩护的繁芜性
上面我们谈论的只是运用层面。然而,集群的影响延伸到根本举动步伐的繁芜性和运营本钱。
首先,启用 Redis 集群大大增加了根本举动步伐的繁芜性以及管理它的团队的运营包袱。您不须要在单个 Redis 实例上监控指标和可用性,而是须要在数十个或数百个节点上进行监控。
其次,事情负载该当在集群中均匀分布,同时最大限度地减少特定实例中的热点。但实际上,这种情形并不常常发生。一个常见的误解是创建集群会自动导致所有分片之间的流量统一。然而,特定的时段险些总是能比其他时段得到更多的流量。虽然 Redis 许可您对实例进行重新分片,但它没有自动重新平衡功能。
末了但并非最不主要的一点是,实例越多,潜在的故障点就越多。虽然集群在节点涌现故障时供应故障转移功能,但成倍增加的风险是真实存在的。我们假设任何单个 Redis 实例发生故障的可能性为 0.01%。如果发生 100 次,这种可能性就会上升到 1-2%,这意味着更多的事件、消防练习以及可能的不眠之夜。
三、Redis 集群替代方案考虑到 Redis 集群面临的寻衅,值得考虑可以供应更大略的 Redis 扩展路径的替代方案。
运用级优化
调度运用程序对 Redis 的访问模式可以显著最小化事情数据大小。通过对键、数据构造和查询进行小幅调度,您可以从现有的 Redis 支配中得到更多收益。例如,在 Abnormal Security,他们将 64 个字符的密钥字符串缩短为 32 个字符。这减少了每个键的内存占用,使它们能够容纳多 15% 的键值对。然而,运用程序级优化并不总是可行的。深入研究优化过程后,有时会觉得您是在知够数据存储的需求,而不是利用它来支持您的业务目标。
内存有限的事情负载
如果吞吐量不是问题,并且您只须要更多内存,最大略的办理方案是升级到更高内存的实例。当然,这意味着这个更强大的实例附带的额外 CPU 将处于闲置状态,不会加入个中。有时付钱很烦人,但至少你没有为环球变暖做出贡献。
然而,由于 Redis 是单线程的,如果您的事情负载受 CPU 限定(例如,涉及大量解析和修正 JSON 数据),那么大略地添加更多 CPU 可能没有帮助。
数据分层到 SSD/闪存
Redis on Flash也称为数据分层,在 Redis 开源版本中不可用,是 Redis 托管办理方案中相对较新的功能。数据分层许可将 Redis 数据集中不常常访问的部分移动到附加到实例的 SSD 存储层。这为事情数据集供应了显著更多的内存容量(在某些云平台上,内存和 SSD 存储组合高达 2TB),同时将热数据集保留在低延迟主内存中。
由于闪存上的 Redis 将所有键保留在内存中,并且仅根据须要将值存储到磁盘,因此只有当您的键大小均匀远小于值大小时,闪存上的 Redis 才是一个不错的选择。例如,如果 100 字节的密钥存储 120 字节的值,则利用闪存存储只能节省最少的内存。
此外,在 80% 的韶光访问 20% 的数据集的通用原则适用于总数据量,包括键和值。因此,如果您仅检索 20% 的键,但这些键对应 80% 的值,则 Flash 上的 Redis 没有帮助。
闪存上的Redis
除了上述技能之外,另一种选择是采取更当代的 Redis 实现。Dragonfly 是一种大略、高性能且经济高效的内存数据存储,供应与 Redis API 的完备兼容性。Dragonfly 许可您连续垂直扩展至多达 128 个内核和 1TB 内存。单个 Dragonfly 节点可以供应与 Redis 集群类似的规模,但不会增加操作繁芜性和上面谈论的 Redis 功能限定。
Dragonfly的扩展能力
Dragonfly 是 Redis 的直接替代品,无需集群即可知足扩展需求。通过在单个节点上利用多线程无共享架构,Dragonfly 可以处理大量内存事情负载和流量峰值,否则须要集群。
Dragonfly 相对付集群设置的一些紧张上风包括:
无需变动客户端库或运用程序代码操作管理大略,无分片繁芜性由于须要更少的实例而节省本钱通过灵巧的扩展避免性能热点从任何 Redis 支配轻松迁移将运用程序从 Redis 迁移到 Dragonfly 时,主要的是要认识到可能须要进行一些调度才能充分实现 Dragonfly 的上风。为单线程 Redis 构建的运用程序常日会针对最小并行度进行优化。比较之下,Dragonfly是多线程的。花韶光调度客户端代码或配置以增加与 Dragonfly 的连接数量并将数据分散到更多键上可能是值得的。
四、结论虽然水平扩展的需求在一定规模(常日是700GB或1TB内存)之后是不可避免的,但许多组织在耗尽垂直扩展选项之前过早地进行水平扩展。这导致事情负载涌现不必要的操作繁芜性,而这些事情负载本来可以放在一个功能强大的节点上。
对付许多用例来说,容量限定是理论上的,而不是实际的:纵然你的业务增长了,有时你在Redis中保存数据的特定用例也会受到更多限定。
纵然您终极必须横向扩展,您仍旧希望利用具有16或32核的相对强大的实例,而不是将事情分散到数百个小实例上。在这种情形下,每个实例都成为潜在的薄弱环节:如果流量发生变革,或者吞吐量或负载溘然激增,那么小实例将无法应对。
虽然Redis集群供应水平扩展,但它在繁芜性和功能丢失方面的本钱很高。Dragonfly可以在单个实例上支持每秒数百万个操作和tb大小的事情负载,从而避免了集群办理方案的许多毛病。
--END--
欢迎关注【辉哥传书vlog】头条号,喜好记得点赞、收藏、评论、转发哦!