Agoda的服务器流量激增50倍,导致数据库性能挑战。团队通过更换SATA硬盘为NVMe硬盘,并优化ScyllaDB的压缩策略和摘要配置,最终将容量提升了50倍。经验表明,打好数据库基础至关重要。
译自:Agoda’s secret to 50x scale: Getting the database basics right
作者:Cynthia Dunlop
Agoda是Booking Holdings的驻新加坡分部,后者是全球领先的在线旅游提供商(旗下品牌包括Booking.com、Kayak、Priceline等)。从2023年1月到2025年2月,Agoda的服务器流量激增了50倍。这代表了巨大的业务增长,但也引发了一项有趣的工程挑战。
具体来说,团队必须确定如何扩展他们由ScyllaDB支持的在线特征存储,以在这种增长下仍能保持10毫秒的P99延迟。使情况复杂化的是,流量具有高度突发性,缓存命中率不可预测,而冷缓存场景可能会在几秒钟内用重复的读取请求淹没数据库。
在2025年怪物规模峰会上,Agoda的首席软件工程师Worakarn Isaratham分享了他们如何应对这一挑战。你可以观看他的完整演讲或阅读下面的亮点。
注意: 怪物规模峰会是一个免费的虚拟会议,专注于极限规模工程,重点关注数据密集型应用。向像Redis创建者antirez、"The Manager's Path"和"Platform Engineering"的作者Camille Fournier、"Designing Data-Intensive Applications"的作者Martin Kleppmann以及来自Discord、Disney、Pinterest、Rivian、Datadog、LinkedIn和Uber Eats等公司的50多名工程师等知名人士学习。注册并加入我们3月11日至12日的热烈交流。
由ScyllaDB和DragonflyDB提供支持的特征存储
Agoda运营着一个内部特征存储,支持离线模型训练和在线推理。
对于不熟悉特征存储的人,Isaratham提供了一个快速入门。特征存储是一个集中式存储库,旨在管理和提供机器学习特征。在机器学习的背景下,特征是数据点的一个可测量属性或特征,用作模型的输入。特征存储有助于管理整个机器学习管道中的特征——从数据摄取到模型训练再到推理。
特征存储对Agoda的业务至关重要。
Isaratham解释说:“我们是一个数字旅行平台,有些用例与我们的产品直接相关。例如,我们尝试预测用户想看什么、推荐哪些酒店以及提供哪些促销活动。在技术方面,我们将其用于机器人检测等。模型使用流量模式来预测用户是否是机器人,如果是,我们可以阻止或降低请求优先级。因此,特征存储对Agoda的产品和工程部门都至关重要。我们有工具来帮助创建特征摄取管道、模型训练以及本文的重点:在线特征服务。”

关于其工作原理的更深一层:

“我们目前每秒向用户提供大约350万个实体(EPS)。大约一半的特征来自客户端SDK中的缓存,我们提供Scala和Python版本。这意味着每秒有170万个实体到达我们的应用程序服务器。这些服务器用Rust编写,运行在我们私有云中的内部Kubernetes Pod中。从应用程序服务器,我们首先检查缓存中是否存在特征。我们使用DragonflyDB作为非持久化集中式缓存。如果缓存中没有,那么我们就会访问ScyllaDB,它是我们的事实来源。”
ScyllaDB是一个高性能数据库,适用于需要超低延迟并能大规模处理的工作负载。Agoda当前的ScyllaDB集群部署为六个裸金属节点,跨四个数据中心进行复制。在稳定状态条件下,ScyllaDB跨所有数据中心每秒提供大约20万个实体,同时满足10毫秒P99延迟的服务级别协议(SLA)。(实际上,他们的延迟通常甚至低于SLA要求。)
流量增长和突发性工作负载
然而,情况并非总是如此顺畅和稳定。大约在2023年中期,当一个新用户想要接入Agoda特征存储时,他们遇到了一个重大的容量问题。他们的流量模式极具突发性:通常流量很低,但偶尔会因外部信号触发而涌入大量请求。这些是冷缓存场景,缓存无法提供帮助。Isaratham分享道,“突发流量达到12万EPS,是当时正常负载的12倍。”
重复请求加剧了这种情况。许多相同的请求迅速接踵而至。不是一个请求填充缓存,后续请求受益,而是所有请求同时击中ScyllaDB——这是一个经典的缓存雪崩。他们还重试失败的请求直到成功——这使得压力持续很高。

这种负载涉及两个数据中心。一个数据中心速度变慢但仍然在线。另一个数据中心实际上已停止服务。Worakarn提供了更多细节:“在出现问题的DC上,错误率很高,重试需要40分钟才能清除;在运行良好的DC上,只需几分钟。指标显示ScyllaDB的读取延迟从毫秒级飙升到秒级。”
诊断瓶颈
于是,他们比较了设置,发现了差异:有问题的数据中心使用的是SATA固态硬盘,而运行良好的数据中心使用的是NVMe固态硬盘。即使在当时,SATA(串行高级技术附件)也已经是旧技术了。团队的速度测试表明,更换磁盘将使读取性能提高10倍——写入速率也会更好。

团队立即订购了新磁盘。然而,鉴于磁盘需要数月才能到货,他们必须在那之前制定一项生存策略。
正如Isaratham分享的那样:“容量测试和预测显示,即使没有新的负载,我们也会在八九个月内达到限制——如果有新的负载,则会更快。因此,我们与用户合作,增加了更积极的客户端缓存,消除了不必要的请求并平滑了突发。这将新负载从12万EPS降低到7千EPS。这足以保持稳定,但我们仍然接近极限。”

使用SATA磁盘生存
鉴于迫在眉睫的容量上限,团队集思广益,思考如何在现有SATA磁盘下改善状况。由于必须先测量才能改进,因此获得清晰的基线是首要任务。
Isaratham详细说明:“早期的容量数据来自实际流量,其中包含缓存效应。我们想直接测量冷缓存性能。因此,我们使用一次性测试实体创建了人工负载,在查询中绕过缓存,并在每次运行前后清空缓存。问题DC的基线读取容量为5K EPS。”
设定基线后,团队考虑了几种不同的方法。
数据建模
所有特征集的所有特征都存储在一个表中。团队希望按特征集拆分表可能会改善局部性并减少读取放大。但事实并非如此。他们已经按特征集和实体进行了分区,因此逻辑上的重组并未改变物理布局。
压缩策略
鉴于读取密集型工作负载频繁更新,ScyllaDB文档建议使用大小分层压缩策略以避免写入放大。但团队最关心的是读取延迟,因此他们选择了不同的路径。
根据Worakarn的说法:“我们尝试了分级压缩,以减少每次读取的SSTable数量。测试显示,获取1KB数据需要从磁盘读取70KB,因此最小化SSTable读取是关键。切换到分级压缩使吞吐量提高了约50%。”
更大的SSTable摘要
ScyllaDB使用摘要文件更有效地导航索引文件。它们的大小由sstable_summary_ratio设置控制。增加该比率会增加摘要文件的大小,以牺牲额外的内存为代价减少索引读取。团队将该比率增加了20倍,这将容量提升至2万EPS。这带来了4倍的显著提升,因此他们立即推广了它。
磁盘带来的巨大改变
最终,NVMe磁盘在几个月后到货了。这一改变带来了巨大的不同。容量跃升至30万EPS,带来了惊人的50-60倍提升。
团队分阶段推出了改进措施:首先是摘要比率调整(获得了2-3倍的喘息空间),然后是NVMe升级(获得了50倍的容量)。他们没有在生产环境中应用分级压缩,因为它只影响新表,并且需要迁移。无论如何,NVMe已经解决了问题。
此后,团队将重心转移到其他领域:改进缓存,用Rust重写应用程序,并添加缓存雪崩预防以减少ScyllaDB的负载。他们仍然偶尔会重新访问ScyllaDB进行实验。举几个例子:
- 新的分区方案:他们尝试了仅按特征集分区并按实体聚类。然而,性能实际上更差,因此他们没有继续推进这个想法。
- 数据重构:应用程序最初为每个特征存储一行。由于某个实体的所有特征总是同时读取,团队测试了将所有特征存储在单个行中。这使性能提高了35%,但这需要表迁移。这在他们稍后要做的事情清单上。
经验教训
Isaratham总结如下:
“我们使用ScyllaDB多年,但没有意识到它的全部潜力,主要是因为我们没有正确设置它。在升级磁盘、进行基准测试和调优数据模型之后,我们终于达到了正确的使用方式。搞定基础——快速存储、了解容量以及将数据模型与工作负载匹配——带来了所有不同。ScyllaDB就是这样帮助我们实现了50倍的扩展。”