阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

是什么让 Redis“气急败坏”回击:13 年来,总有人想替 Redis 换套新架构

  • 2022-08-10
    北京
  • 本文字数:6076 字

    阅读完需:约 20 分钟

是什么让Redis“气急败坏”回击:13年来,总有人想替Redis换套新架构

回击就代表输了?!


今年年中,一位前谷歌、前亚马逊的工程师推出了他创作的开源内存数据缓存系统 Dragonfly,用 C/C++ 编写,基于 BSL 许可(Business Source License)分发。


根据过往的基准测试结果来看, Dragonfly 可能是世界上最快的内存存储系统,它提供了对 Memcached 和 Redis 协议的支持,但能够以更高的性能进行查询,运行时内存消耗也更少。与 Redis 相比,Dragonfly 在典型工作负载下实现了 25 倍的性能提升;单个 Dragonfly 服务器每秒可以处理数百万个请求;在 5GB 存储测试中,Dragonfly 所需的内存比 Redis 少 30%。


作为一个开源软件,Dragonfly 在短短两个月获得了 9.2K GitHub 星,177 个 fork 分支。虽然这些年,涌现了不少类似的 Redis 兼容型内存数据存储系统,例如 KeyDB、Skytable,但是都没能像这次这么“轰动”。毕竟 Redis 诞生了十多年,这时从头开始设计一个缓存系统,可以抛弃历史包袱,更好地利用资源。



为回击新冒头的 Dragonfly,Redis 的联合创始人兼 CTO Yiftach Shoolman 和 Redis Labs 的首席架构师 Yossi Gottlieb、Redis Labs 的性能工程师 Filipe Oliveira 联合发布了一篇名为《13 年后,Redis 是否需要新的架构》的文章。


在文章中,他们特地给出了自认更加公平的 Redis 7.0 vs. Dragonfly 基准测试结果:Redis 的吞吐量比 Dragonfly 高 18% - 40%,以及一些有关 Redis 架构的观点和思考,以证明 “为什么 Redis 的架构仍然是内存实时数据存储(缓存、数据库,以及介于两者之间的所有内容)的最佳架构”。


虽然他们强调 Redis 架构仍然是同类最佳,但也没法忽视 Dragonfly 这些新软件提供的一些新鲜、有趣的想法和技术,Redis 表示其中的一些甚至有可能在未来进入 Redis(比如已经开始研究的 io_uring 、更现代的 dictionaries、更有策略地使用线程等)。


另外,Redis 指出 Dragonfly 基准测试的比较方法 “不能代表 Redis 在现实世界中的运行方式” 。对此,Reddit 上有网友反驳称:


它绝对代表了现实世界中普通用户运行 Redis 的方式。“在单台机器上运行集群,只是为了能够使用超过 1 个 core" 是额外的复杂性,人们只有在别无选择的情况下才会这样做,如果竞争者无论有多少个 core 都能 “just works",那么最好能有更容易的设置。


还有人表示,这篇文章是 Redis 团队在有礼貌地否认“Dragonfly 是最快的缓存系统”,但更多网友表示,Redis 发文章进行“回击”,就已经代表他们的营销部门输了:


“Redis 投入如此多的工程精力来写这么一篇文章,还对 Reids/Dragonfly 进行了基准测试,这是对 Dragonfly 的极大赞美。”“我很高兴 Redis 发了这篇文章,因此我必须要去了解一下 Dragonfly,它看起来很棒。”

Redis 博客文章翻译:


作为一项基础性技术,每隔段时间总有人跳出来,想要替 Redis 换套新架构。几年之前,KeyDB 就提出了这类方案,而最近亮相的 Dragonfly 则声称是速度最快的 Redis 兼容型内存数据存储系统。没错,这类方案的涌现当然带来了不少值得关注和讨论的有趣技术 / 思路。在 Redis,我们也喜欢迎接挑战,重新审视 Redis 最初的架构设计原则。

 

我们当然一直在寻求为 Redis 提升性能、扩充功能的创新方向,但这里我们想聊聊自己的观点和思考,阐释 Redis 时至今日为何仍是最出色的实时内存数据存储(包括缓存、数据库以及介于二者之间的一切)方案之一。

 

接下来,我们将重点介绍 Redis 对于速度和架构差异的观点,再以此为基础做出比较。在文章的最后,我们还会提供基准测试结果、与 Dragonfly 项目的详尽性能比较信息,欢迎大家自行对比参考。

 

速度问题

Dragonfly 基准测试其实是将独立单进程 Redis 实例(只能使用单一核心)与多线程 Dragonfly 实例(可以使用虚拟机 / 服务器上的全部可用核心)进行比较。很明显,这样的粗暴比较并不能代表 Redis 在现实场景下的运行状态。作为技术构建者,我们希望更确切地把握自有技术同其他方案间的差异,所以这里我们做了一点公平性调整:将具有 40 个分片的 Redis 7.0 集群(可使用其中的大部分实例核心)与 Dragonfly 团队在基准测试中使用的最大实例类型(AWS c4gn.16xlarge)进行性能比较。

 

在这轮测试中,我们看到 Redis 的吞吐量比 Dragonfly 要高出 18% 至 40%,而这还仅仅只用到全部 64 个 vCore 中的 40 个。

 



架构差异

 

背景信息

 

在我们看来,每一位多线程项目的开发者在立项之前,都会根据以往工作中经历过的痛点来指导架构决策。我们也承认,在多核设备上运行单一 Redis 进程(这类设备往往提供几十个核心和数百 GB 内存)确实存在资源无法充分利用的问题。但 Redis 在设计之初也确实没有考虑到这一点,而且众多 Redis 服务商已经拿出了相应的解决方案,借此在市场上占得一席之地。

 

Redis 通过运行多个进程(使用 Redis 集群)实现横向扩展,包括在单一云实例背景下也是如此。在 Redis 公司,我们进一步拓展这个概念并建立起 Redis Enterprise。Redis Enterprise 提供管理层,允许用户大规模运行 Redis,并默认启用高可用性、即时故障转移、数据持久与备份等功能。

 

下面,我们打算分享幕后使用的一些原则,向大家介绍我们如何为 Redis 的生产应用设计良好的工程实践。

 

架构设计原则

 

在每个虚拟机上运行多个 Redis 实例

 

通过在每个虚拟机上运行多个 Redis 实例,我们可以:

  1. 使用一套完全无共享的架构实现纵向与横向线性扩展。与纯纵向扩展的多线程架构相比,这套方案能始终提供更好的架构灵活性。

  2. 提高复制速度,因为复制操作是跨多个进程并发完成的。

  3. 从虚拟机故障中快速恢复。因为新虚拟机的 Redis 实例将同时填充来自多个外部 Redis 实例的数据。

 

将每个 Redis 进程限制为合理的大小

我们不允许单一 Redis 进程的大小超过 25 GB(运行 Redis on Flash 时上限为 50 GB)。如此一来,我们就能:

  • 在出于复制、快照保存、Append Only File(AOF)重写等目的进行 Redis 分叉时,既享受边写边复制的好处,又无需承担繁重的内存开销。若非如此,我们(或客户)将需要支付昂贵的资源成本。

  • 为了轻松管理整个集群,我们希望每个 Redis 实例都保持在较小体量,借此加快迁移分片、重新分片、扩展和重新均衡等的执行速度。

 

横向扩展才是最重要的

以横向扩展的方式灵活运行内存数据存储,是 Redis 获得成功的关键。下面来看具体原因:

  • 更佳弹性——我们在集群中使用的节点越多,整个集群的健壮性就越强。例如,如果您在三节点集群上运行数据集,且其中一个节点发生降级,则代表有三分之一的集群无法运行;但如果是在九节点集群上运行数据集,同样是其中一个节点发生降级,则只有九分之一的集群无法运行。

  • 易于扩展——在横向扩展系统当中,向集群添加一个额外节点、并将数据集的一部分迁移到其中要容易得多。与之对应,在纵向扩展系统中,我们只能直接引入一个更大的节点并复制整个数据集……这是个漫长的过程,而且期间随时有可能闹出麻烦。

  • 逐步扩展更具成本效益——纵向扩展,尤其是云环境下的纵向扩展,往往对应高昂的成本。在多数情况下,即使只需要向数据集内添加几 GB 内容,也需要将实例大小翻倍。

  • 高吞吐——在 Redis,我们看到很多客户会在小型数据集上运行高吞吐量工作负载,即具有极高的网络带宽及 / 或每秒数据包(PPS)需求。我们以每秒操作数 100 万 + 的 1 GB 大小数据集为例,相较于使用单节点 c6gn.16xlarge 集群(128 GB 内存、64 个 CPU 加 100 Gbps 传输带宽,每小时使用成本 2.7684 美元),三个 c6gb.xlarge 节点(8 GB 内存、4 个 CPU 外加最高 25 Gbps 传输带宽,每小时 0.1786 美元)构成的集群能够将运行成本拉低 20%,而且健壮性反而更高。既然成本效益出色、弹性更强且吞吐量反超,那横向扩展无疑就是比纵向扩展更好的选择。

  • 贴近 NUMA 架构——纵向扩展还要求使用能容纳更多核心和大容量 DRAM 的双插槽服务器;相比之下,Redis 这样的多处理架构其实更适应 NUMA 架构,因为其行为特征就接近一种由多个较小节点组成的网络。但必须承认,NUMA 跟多线程架构之间也有天然冲突。根据我们在其他多线程项目中的经验,NUMA 可能令内存数据存储的性能降低达 80%。

  • 存储吞吐量限制——AWS EBS 等外部磁盘的扩展速度,显然不及内存和 CPU。事实上,云服务商会根据所使用设备的类型添加存储吞吐量限制。因此,避免吞吐量限制、满足数据高持久性要求的唯一办法,就是使用横向扩展——即添加更多节点和更多的配套网络附加磁盘。

  • 临时磁盘——临时磁盘是一种将 Redis 运行在 SSD 上的绝佳方式(其中 SSD 用于替代 DRAM,而非充当持久存储介质),能够在保持 Redis 极高速度的同时将数据库成本保持在磁盘级水平。但临时磁盘也有其上限,一旦逼近这一上限,我们还需要进一步扩展容量——这时候,更好的办法仍然是添加更多节点、引入更多临时磁盘。所以,横向扩展继续胜出。

  • 商品硬件——最后,我们的很多客户会在本地数据中心、私有云甚至是小型边缘数据中心内运行 Redis。在这类环境中,绝大多数设备内存不超过 64 GB、CPU 不超过 8 个,所以唯一可行的扩展方式就只有横向扩展。

 

总结

我们仍然欣赏由社区提出的种种有趣思路和技术方案。其中一部分有望在未来进入 Redis(我们已经开始研究 io_uring、更现代的字典、更丰富的线程使用策略等)。但在可预见的未来,我们不会放弃 Redis 所坚守的无共享、多进程等基本架构原则。这种设计不仅具备最佳性能、可扩展性和弹性,同时也能够支持内存内实时数据平台所需要的各类部署架构。

 

附录:Redis 7.0 对 Draonfly 基准测试细节

 

结果概述

版本:

目标:

  • 验证 Dragonfly 公布的结果是否可重现,并确定检索结果的完整条件(鉴于 memtier_benchmark、操作系统版本等信息有所缺失)

  • 确定 AWS c6gn.16xlarge 实例上可实现的最佳 OSS Redis 7.0.0 集群性能,并与 Dragonfly 的基准测试结果相比较

客户端配置:

  • OSS Redis 7.0 解决方案需要大量接入 Redis 集群的开放连接,因为每个 memtier_benchmark 线程都需要连接到所有分片

  • OSS Redis 7.0 解决方案在使用两个 memtier_benchmark 进程时成绩最好,而且为了与 Dragonfly 基准相适应,这两个进程运行在同样的客户端虚拟机上

资源利用与配置优化:

  • OSS Redis 集群在 40 个主分片的配置下性能表现最佳,对应的就是虚拟机上有 24 个备用 vCPU。虽然设备资源仍未得到全部利用,但我们发现继续增加分片数量已经没有意义,反而会拉低整体性能。我们仍在调查具体原因。

  • 另一方面,Dragonfly 解决方案彻底耗尽了虚拟机性能,所有 64 上 vCPU 均达到了 100% 利用率。

  • 在两种解决方案中,我们调整了客户端配置以实现最佳结果。如下所示,我们成功重现了大部分 Dragonfly 基准数据,甚至在 30 通道条件下得出了比项目方更高的测试成绩。

  • 本次测试强调与 Dragonfly 测试环境保持一致,如果调整测试环境,Redis 的成绩还有望进一步提升。

 

最后,我们还发现 Redis 和 Dragonfly 都不受网络每秒数据包或传输带宽的限制。我们已经确认在 2 个虚拟机间(分别作为客户端和服务器,且均使用 c6gn.16xlarge 实例)使用 TCP 传递约 300 B 大小的数据包负载时,可以让每秒数据包传输量达到 1000 万以上、传输带宽超过 30 Gbps。

 

分析结果




单 GET 通道延迟低于 1 毫秒:

  • OSS Redis:每秒 443 万次操作,其中延迟平均值与第 50 百分位值均达到亚毫秒级别。平均客户端延迟为 0.383 毫秒。

  • Dragonfly 声称每秒 400 万次操作:我们成功重现至每秒 380 万次操作,平均客户端延迟为 0.390 毫秒

  • Redis 对 Dragonfly——Redis 吞吐量比 Dragonfly 声称的结果高出 10%,比我们成功重现的 Dragonfly 结果高 18%。

30 条 GET 通道:

  • OSS Redis:每秒 2290 万次操作,客户端平均延迟为 2.239 毫秒

  • Dragonfly 声称每秒可达 1500 万次操作:我们成功重现了每秒 1590 万次操作,客户端平均延迟为 3.99 毫秒

  • Redis 对 Dragonfly——与 Dragonfly 的重现结果和声称结果相比,Redis 分别胜出 43% 和 52%

单 SET 通道延迟低于 1 毫秒:

  • OSS Redis:每秒 474 万次操作,延迟平均值与第 50 百分位值均达到亚毫秒级。客户端平均延迟为 0.391 毫秒

  • Dragonfly 声称每秒 400 万次操作:我们成功重现了每秒 400 万次操作,客户端平均延迟为 0.500 毫秒

  • Redis 对 Dragonfly——与 Dragonfly 的重现结果和声称结果相比,Redis 均胜出 19%

30 条 SET 通道:

  • OSS Redis:每秒 1985 万次操作,客户端平均延迟为 2.879 毫秒

  • Dragonfly 声称每秒 1000 万次操作:我们成功重现了每秒 1400 万次操作,客户端平均延迟为 4.203 毫秒

  • Redis 对 Dragonfly——与 Dragonfly 的重现结果和声称结果相比,Redis 分别胜出 42% 和 99%

用于各变体的 memtier_benchmark 命令:

单 GET 通道延迟低于 1 毫秒

  • Redis:2X: memtier_benchmark –ratio 0:1 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram

  • Dragonfly:memtier_benchmark –ratio 0:1 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram

30 条 GET 通道

  • Redis:2X: memtier_benchmark –ratio 0:1 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram –pipeline 30

  • Dragonfly:memtier_benchmark –ratio 0:1 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram –pipeline 30

单 SET 通道延迟低于 1 毫秒

  • Redis:2X: memtier_benchmark –ratio 1:0 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram

  • Dragonfly:memtier_benchmark –ratio 1:0 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram

30 条 SET 通道

  • Redis:2X: memtier_benchmark –ratio 1:0 -t 24 -c 1 –test-time 180 –distinct-client-seed -d 256 –cluster-mode -s 10.3.1.88 –port 30001 –key-maximum 1000000 –hide-histogram –pipeline 30

  • Dragonfly:memtier_benchmark –ratio 1:0 -t 55 -c 30 -n 200000 –distinct-client-seed -d 256 -s 10.3.1.6 –key-maximum 1000000 –hide-histogram –pipeline 30

 

测试设施细节

在本次比较测试中,我们在客户端(用于运行 memtier_benchmark)和服务器(用于运行 Redis 和 Dragonfly)使用了相同的虚拟机类型,具体规格为:

  • 虚拟机:AWS c6gn.16xlarge

  • aarch64

  • ARM Neoverse-N1

  • 每插槽核心数: 64

  • 每核心线程数: 1

  • NUMA 节点数: 1

  • 核心版本: Arm64 Kernel 5.10

  • 安装内存: 126 GB

 

参考链接:

https://redis.com/blog/redis-architecture-13-years-later/

https://www.reddit.com/r/programming/comments/wiztpx/redis_hits_back_at_dragonfly/


2022-08-10 14:2017318

评论

发布
暂无评论
发现更多内容

🚄【Redis 干货领域】帮你完全搞定 Cluster 原理(实践篇)

洛神灬殇

redis redis集群 redis cluster 5月日更 redis架构

C4C Cloud Application Studio做ABSL开发的一些性能方面的最佳实践

Jerry Wang

Cloud CRM SAP C4C

SAP Fiori Launchpad Tile点击后跳转的调试技巧

Jerry Wang

JavaScript SAP Fiori SAP UI5

如何将BSP应用配置成Fiori Launchpad上的一个tile

Jerry Wang

SAP abap Fiori SAP UI5 bsp

基于Mac的手动搭建WordPress个人站点的方法

三掌柜

5月日更

设计千万级学生管理系统的考试试卷存储方案

9527

开发中Docker常用容器记录

Docker

Go 并发编程-goroutine 初体验

Rayjun

Go 语言 goroutine

Python 持久化 - 文件

若尘

文件 持久化 持久化存储 5月日更

Inner Join, Left Outer Join和Association的区别

Jerry Wang

SAP abap ST05

一个查看 SAP UI5 控件所有公有方法的小技巧

Jerry Wang

JavaScript SAP SAP UI5

Authorization object在哪些ABAP代码里使用到

Jerry Wang

CRM SAP abap Netweaver

自我复盘

lenka

5月日更

高性能 JavaScriptの五 -- 快响应用户界面

空城机

JavaScript 大前端 5月日更

Go 并发编程 — 深入浅出 sync.Pool ,围观最全的使用姿势,理解最深刻的原理

奇伢云存储

并发编程 云存储 Go 语言

和另一半过不一样的520

小英

520单身福利 520 单身福利

模块四-千万级学生管理系统试卷存储方案

华仔架构训练营

利用Chrome的Heap Snapshot功能分析一个时间段内的内存占用率

Jerry Wang

JavaScript chrome

架构实战营-作业四

大可

另一种方式实现事务码SE16里的结果集修改

Jerry Wang

JavaScript SAP Fiori

找出 SAP OData service出错根源的小技巧

Jerry Wang

SAP Fiori SAP UI5 OData

MySQL主从网络延迟解决方案

运维研习社

MySQL 运维 主从同步 5月日更

如何根据日志来了解一个请求经历了什么?

我爱娃哈哈😍

软件架构 架构设计 架构实战

架构实战营模块4作业

Vic

架构实战营

再谈前端性能监控及4个最佳工具分享

devpoint

大前端 sentry

☕【Java技术之旅】从底层角度去认识线程的原理

洛神灬殇

Java 线程 Thread 线程协作 5月日更

Shell脚本-简单爬虫

追风的少年

如何在SAP CRM WebClient UI里创建HANA Live Report

Jerry Wang

CRM SAP WebClient UI

SAP Fiori 应用 Footerbar 区域按钮的高亮显示逻辑

Jerry Wang

JavaScript SAP Fiori SAP UI5

SAP 不同 ABAP 系统里同一 Customizing activity 的显示差异分析

Jerry Wang

CRM SAP ERP abap 定制化

到底哪种类型的错误信息会阻止business transaction的保存

Jerry Wang

CRM SAP abap

是什么让Redis“气急败坏”回击:13年来,总有人想替Redis换套新架构_开源_赵钰莹_InfoQ精选文章