跳转到: 导航, 搜索

Swift/ideas/metadata-sync

< Swift‎ | ideas

将 Swift 对象元数据传播到外部索引(例如 Elasticsearch)

背景

在 Swift 集群中搜索对象比较困难。如果已知对象名称和其容器的一些信息,则可以依赖于前缀/分隔符选项来尝试缩小搜索范围。但是,如果只知道对象名称的一部分,Swift 需要列出整个容器。如果不知道容器,那么搜索会变得更加困难,因为它必须在所有容器中重复进行。

最后,如果只知道与对象关联的元数据键,则搜索需要对每个对象进行 HEAD 请求。这个过程可能需要几天时间。本文档描述了如何使用外部索引(例如 Elasticsearch)来解决此问题。

设计讨论

基本思想是利用容器数据库(类似于容器同步方法)。容器数据库包含传播到索引服务所需的确切信息

  • 对象名称
  • 对象 etag
  • 上次修改日期
  • 已删除标志

唯一缺失的部分是与对象关联的元数据,可以使用 HEAD 请求查找。

该设计增加了一个持续扫描容器数据库的过程,根据需要更新 Elasticsearch。此同步过程的一个实例在每个容器节点上运行。每个实例都配置了要索引的 (account, container) 元组列表。对于每个元组,第一步是检查数据库是否存在于节点上,并创建 ContainerBroker 的实例。其次,爬取过程使用 get_items_since() API 检索最近更改的项目集。

多个实例爬取数据库之间不会相互交互。每个进程记录上次处理的行 ID。在每次迭代中,它检索一组已更改的行。从行集中,只有给定节点的一部分首先被传播。节点 ID 通过测试 row_id % node_id == 0 确定这部分。

在移动到下一组行之前,必须验证其他节点的作业。在验证步骤中,每个节点考虑所有它不负责的行(row_id % node_id != 0)。然后从二级索引检索所有记录,并将索引中的上次修改日期与容器数据库中的日期进行比较。任何缺失的更新——时间戳不匹配的更新——然后被修补。如果所有节点以相似的速度取得进展,则验证步骤不会导致额外的 HEAD 请求。在使用 Elasticsearch 时,要验证的索引文档可以通过单个批量请求检索。

存储索引状态

索引状态存储在每个节点的 /var/lib 中,并具有索引过程。这允许节点即使在无法相互通信或系统的大部分出现故障时也能取得进展。如果替换了节点,则新节点需要通过处理项目并发现它们已被索引来赶上进度。了解赶上进度需要多长时间会很有趣。使用 Elasticsearch 的批量请求可以减少赶上时间。

为了识别节点已被替换——或者当其中一个驱动器发生故障时数据库已被替换——我们还应该在跟踪状态时嵌入其 UUID。一种方法是如果数据库本身有一个表来跟踪进度(最后一个行 ID)。当被替换时,数据库将被重置,并且所有行 ID 都将被使无效。否则,如果我们使用本地存储,将 UUID 嵌入到状态文件中可能是最好的方法。

实现

此概念验证实现有两个项目:Container CrawlerSwift Metadata Sync

中间件

对象元数据也可以通过 Swift 中间件复制。中间件将在通过代理节点进行任何成功请求后提交 Elasticsearch 请求。这种方法的优点是它易于实现,并且 Swift 中已经存在所需的组件。但是,如果无法进行索引服务的更新怎么办?可能会出现网络分区或索引服务可能离线。如果 Swift 继续接受更改,则必须稍后以某种方式进行调整。由于仍然需要调整步骤,因此建议仅从扫描容器数据库开始。