验证新的 Dropbox 搜索引擎的性能和可靠性

简介: 验证新的 Dropbox 搜索引擎的性能和可靠性

在上一篇文章中,我们讨论了名为Nautilus的新搜索引擎的架构,以及它使用机器智能来扩展我们的搜索排名和内容理解模型。除了一流的性能,可扩展性和可靠性之外,我们还为实现智能功能提供了基础。这种灵活的系统使我们的工程师能够轻松自定义文档索引和查询处理管道,同时保持强大的保护措施,以保护用户数据的隐私。在这篇文章中,我们将讨论我们的性能和可靠性的过程。

性能

索引格式

我们的数百个搜索页中的每一个都运行我们的检索引擎,其职责包括在创建,编辑和删除文件时处理更新索引(这些是“写入”)以及为搜索查询提供服务(这些是“读取”)。Dropbox流量具有一个有趣的特征,即它以写入为主 , 也就是说,文件的更新频率高于搜索频率。我们通常观察到写入量比读取量高10倍。因此,在优化检索引擎中使用的数据结构时,我们会仔细考虑这些工作负载。

“过帐列表”是一种数据结构,它将令牌(即潜在的搜索词)映射到包含该令牌的文档列表。检索引擎的核心是维护一组构成倒排索引的过帐列表。在搜索请求期间查询过帐列表,并在将更新应用于索引时进行更新。常见的过帐列表格式存储令牌和关联的文档 ID 列表,以及可在评分阶段使用的一些元数据(例如:术语频率)。

此格式非常适合主要为只读的工作负载:每个搜索查询只需要找到适当的发布列表集(可以使用哈希表可以是 O(1)),然后将每个关联的文档 ID 添加到结果集中。

但是,为了能够处理我们在用户行为中观察到的高更新率,我们决定对反向索引使用“爆炸式”发布列表格式。我们的反向索引由键/值存储(RocksDB)支持,每个(命名空间ID,令牌,文档ID)元组都存储为单独的行。更具体地说,行键的格式是“<命名空间 ID>|<token>|<doc ID>”。给定针对特定命名空间中的文档的搜索查询,我们可以有效地运行<namespace ID><token>|以获取所有匹配文档的列表。将命名空间概念内置到密钥的格式中有几个好处。首先,在安全性方面,这是非常重要的,因为它可以防止查询返回用户有权访问的指定命名空间之外的文档。其次,在性能方面,因为它将搜索范围缩小到仅包含在命名空间中的文档,而不是在分区中索引的更大的文档集。使用此方案时,每行的值存储与令牌关联的元数据。

从存储和检索的角度来看,与更传统的格式相比,这是效率较低的,在更传统的格式中,所有文档ID都已分组,并且可以通过使用诸如delta编码之类的技术以紧凑的表示形式存储。但是,“爆炸”表示的主要好处是特别有效地处理索引突变。例如,通过为文档包含的每个令牌插入一行,将文档添加到反向索引中 — 这是一个简单的操作,在大多数键/值存储(包括 RocksDB)上都非常有效地执行。RocksDB 应用键的前缀压缩这一事实减轻了额外的存储损失 — 总体而言,我们发现使用分解表示的索引大小仅比使用传统发布列表表示的索引大 15% 左右。

服务

响应性能对于流畅和交互式的用户体验至关重要。我们用于评估服务性能的主要指标是第 95 和第 99 百分位的查询延迟,即最慢的 5% 和 1% 的查询应分别不低于 500 毫秒和 1 秒(目前)。当然,中位数查询将明显更快。随着鹦鹉螺系统开发的进展,我们不断测量和分析性能。系统的每个组件都经过检测,以便能够确定它对整体延迟的贡献程度。在此过程中,我们学到了一些经验教训,包括:

  • 不要过早地优化:在了解系统的每个组件如何导致整体延迟之前,我们没有改进检索引擎的性能。人们可能预料到大部分时间将花在检索阶段。但是在对数据进行初步分析后,我们确定延迟的很大一部分实际上来自从外部系统获取元数据( 由关系数据库支持),用于检查 ACL 并在返回搜索结果之前“修饰”搜索结果。这包括列出文件夹路径,创建者,上次修改时间等内容。
  • 害怕“死亡的疑问”: 总体延迟可能会受到一些有害查询(有时称为“死亡查询”)的不利影响。这些通常是由于以编程方式命中搜索 API 的软件中的错误(而不是人类用户)造成的。我们构建了断路器来过滤掉这些查询,以保护整个系统。此外,我们还实现了遵守“时间预算”的功能,即一旦超出分配的时间预算,检索引擎就会停止获取查询的候选项。我们发现,这有助于性能和整体系统负载,但代价是有时无法返回所有可能的结果。这主要发生在与许多候选项匹配的非常广泛的查询中,例如,在对单个令牌执行前缀搜索时(如在自动完成搜索查询期间发生的那样)。
  • 副本也可以帮助解决尾部延迟:我们的叶子被复制2倍以实现冗余,以防机器遇到问题。但是,这些副本也具有性能优势:它们可用于改善尾部延迟(最慢请求的延迟)。我们使用众所周知的技术,即向所有副本发送查询,并从最快的副本返回响应。
  • 投资构建基准测试工具:一旦特定组件被确定为性能瓶颈,编写基准测试工具来负载测试和测量该特定组件的性能是快速迭代以提高性能的更好方法,而不是测试整个系统。在我们的例子中,我们为在叶子上运行的核心检索引擎编写了一个基准工具。我们用它来衡量引擎在分区级别针对合成数据的索引和检索性能。生成的分区数据在命名空间、文档、标记的总数以及每个命名空间的文档数和每个文档的标记数分布方面具有接近生产的特征。

可靠性

数以百万计的用户依靠 Dropbox 搜索来执行他们的工作,因此我们在设计系统时特别注意确保我们可以保证用户期望的正常运行时间。

在大型分布式系统中,网络或硬件故障以及软件崩溃经常发生 - 它们是不可避免的。我们在设计 Nautilus 时牢记了这一事实,特别关注服务路径中组件的容错和自动恢复。

一些组件被设计为无状态,这意味着它们不依赖于外部服务或数据来运行。这包括八达通,我们的结果合并和排名系统;和检索引擎的根,该引擎将搜索请求扇出到所有叶子。因此,这些服务可以通过多个实例轻松部署,每个实例都可以在发生故障时自动重新配置。当涉及到叶子实例时,这个问题更具挑战性,因为它们维护索引数据。

分区分配

在 Nautilus 中,每个叶实例负责处理搜索索引的子集,称为“分区”。我们维护所有叶子的注册表,并使用单独的协调器为叶子分配分区。协调员负责确保 100% 的分区连续覆盖。当启动新的叶实例时,它将保持空闲状态,直到协调器指示为分区提供服务,此时它加载索引,然后开始接受搜索请求。

如果叶子正在联机,但其分区中存在对数据的搜索请求,会发生什么情况?我们通过维护每个叶子的副本来处理这个问题,这些副本一起称为“叶副本组”。副本组是叶实例的独立集群,提供索引的完整覆盖。例如,为了确保系统的 2 倍复制,我们运行两个副本组,每个组一个协调器。除了使有关复制的推理变得简单之外,此设置还为执行维护提供了操作优势,例如:

  • 只需将新代码部署到一个又一个组,即可将其部署到生产环境,而不会对可用性产生任何影响。
  • 可以添加或删除整个组。这对于进行硬件或操作系统升级特别方便。例如,可以添加在新硬件上运行的组,一旦它完全运行,我们就可以停用在旧硬件上运行的组。

在这两种情况下,Nautilus完全能够在整个过程中回答所有请求。

恢复

每个叶组都经过过度预置,具有大约 15% 的额外硬件容量,以便有一个空闲实例池随时待命。当协调器检测到分区覆盖率下降时(即,假设当前活动的叶子突然停止为请求提供服务),它会通过选择一个空闲的叶子并指示它为丢失的分区提供服务来做出反应。然后,该叶执行以下步骤:

  • 从索引存储库下载与分区关联的索引数据。这为叶提供了一个过时的索引,因为它是前段时间由脱机生成系统生成的。
  • 重播来自 Kafka 队列的旧突变,从与构建索引分区时对应的偏移量开始。
  • 一旦这些较旧的突变在下载的索引之上完成应用,就意味着叶索引是最新的。此时,叶子进入服务模式并开始处理查询。

Nautilus 是 Dropbox 工程师处理的大型项目类型的典型例子,这些项目涉及数据检索和机器学习

目录
相关文章
|
2天前
|
缓存 监控 Java
提升安卓应用性能的实用策略
【5月更文挑战第21天】在竞争激烈的移动应用领域,卓越的性能是确保用户留存的关键因素。本文将深入探讨针对安卓平台优化应用性能的有效方法,包括内存管理、多线程应用、UI渲染效率和电池使用优化。通过实例分析和最佳实践分享,旨在帮助开发者构建更加流畅、高效的安卓应用。
|
8天前
|
缓存 监控 Android开发
提升安卓应用性能的关键策略
【4月更文挑战第30天】 在竞争激烈的移动应用市场中,性能优化已成为开发流程中不容忽视的一环。尤其对于安卓平台,由于设备多样性和系统碎片化,确保应用流畅运行并减少资源消耗显得尤为关键。本文旨在探讨几个实用的策略,帮助开发者诊断常见性能瓶颈,并提供针对性的解决方案,以期达到更高效的应用性能表现。
|
UED
镭速软件3.4.0.8版本正式上线,用户体验再优化!
还记得那些年你反馈过的问题吗?我们的程序猿小哥哥小姐姐在收到反馈后快马加鞭,在产品的**传输能力、存储、客户端和web管理**方面做了集中优化,**镭速软件3.4.0.8版本今天正式上线啦!**
835 0
|
安全 测试技术 数据安全/隐私保护
76款流行iOS应用易受中间人攻击,1800万用户受影响
本文讲的是76款流行iOS应用易受中间人攻击,1800万用户受影响,安全研究员对iOS移动应用的研究发现,苹果应用商店中有很多流行iOS应用存在一个安全漏洞,可将用户暴露在中间人攻击的危险之中。
1334 0
|
安全 测试技术 数据安全/隐私保护

热门文章

最新文章