pinterest 插画网站pinterest( 三 )


pinterest 插画网站pinterest

文章插图
用于数据结构的一次写入和多次读取并发模型并不意味着我们不能使用多个线程进行写入 。我们计划使用 term 分片策略来支持具有多个线程的写入 。如上图所示,对于具有 term 列表的给定文档,每个 term 将始终映射到固定线程,以便为单次写入和多次读取定制的所有数据结构都可以无限制地直接重用 。
索引刷新索引刷新功能是我们产品的一项关键特性,可实现快速周转并提高开发速度 。一般可以使用两种方法以高效刷新索引,它们分别是动态回填和从离线构建的索引恢复 。
回填索引我们提供了以合理的吞吐量回填文档的功能 。为了避免影响生产的新鲜度,我们需要一个优先级较低的单独流来处理回填流量 。结果,两个流中可能会存在文档的两个版本,而旧版本将覆盖新版本 。为了克服这个问题,我们需要在实时索引管道中引入一种版本控制机制和一个冲突解决程序,以决定哪个版本更新鲜 。
从离线构建索引中恢复有时,以给定的速度对整个数据集进行回填会非常耗时 。我们支持的另一种更快的索引刷新方法是离线构建索引,然后使用离线构建索引和 Kafka 流之间的同步机制来从离线索引中恢复索引 。
故障转移和自动扩展出于各种原因,我们有时会需要启动新实例,例如故障转移和自动缩放等 。对于静态服务,使用从索引存储下载的不变索引来启动新实例是很容易的 。但是,对于具有不断变化的索引的实时服务而言,这就变得很复杂了 。我们如何确保新实例最终具有与其他实例相同的索引副本呢?
pinterest 插画网站pinterest

文章插图
【pinterest 插画网站pinterest】

我们决定使用基于 Leader 的复制,如上图所示 。

我们的流程如下所示:

Leader 定期拍摄新快照并将其上传到持久索引存储中默认情况下,新实例从索引存储下载最新的快照新实例根据快照索引中的检查点恢复消费来自 Kafka 的消息一旦新实例赶上进度,便开始为流量提供服务
这种设计中有一些关键点值得一提:
Leader 选举Leader 的唯一职责是拍摄快照并定期上传索引 。这意味着我们可以在较短的时间内(最多几个小时)无 Leader 或有多个 Leader 。因此,我们在选择 Leader 选举算法方面具有一定的灵活性 。为简单起见,我们选择使用集群维护作业来静态地选举一个 Leader,在此我们会定期检查我们是否有一个好的 Leader 。
快照上传通常,新实例仅连接到 Leader 以下载最新快照 。在这种方法中,从新实例下载快照可能会使 Leader 过载,从而导致级联故障 。相反,我们选择将快照定期上载到索引存储,牺牲存储空间和新鲜度以保持稳定性 。此外,上载的快照对于错误恢复很有用,稍后将对此介绍 。
错误恢复如上所述,错误恢复是实时服务系统的另一挑战 。我们需要处理一些涉及数据损坏的特定场景 。
输入数据损坏我们使用 Kafka 作为输入写入流;不幸的是,这些消息是不可变的,因为生产者只能在其上附加消息,而不能更改现有消息的内容 。这意味着一旦将数据损坏引入 Kafka 消息中,它将是永久性的 。多亏了上传的快照,我们能够将索引回退到不损坏的状态,跳过损坏的消息,然后使用这个修复来消费新消息 。
二进制错误导致数据损坏尽管我们拥有成熟的静态集群索引验证管道,以确保在换入新版本之前新索引和新二进制文件均不会出现问题,但仍有一些错误会潜入生产环境 。幸运的是,我们可以通过回滚二进制或索引来解决此问题 。对于实时服务而言,回滚二进制文件无法回滚索引中的错误,这带来了更大的麻烦 。使用快照上传机制,我们可以将二进制文件与回退的索引一起回滚,然后从 Kafka 重放消息以修复索引中的错误 。
下一步计划随着越来越多的场景加入 Manas,我们需要不断提高系统的效率、可伸缩性和能力 。我们路线图中的一些有趣的项目如下:

共同托管静态和实时集群以简化我们的服务栈优化系统以支持大型数据集构建一个基于通用嵌入的检索以支持高级场景
致谢:这篇文章总结了几个季度的工作,涉及多个团队 。感谢 Tim Koh、Haibin Xie、George Wu、Sheng Chen、Jiacheng Hong 和 Zheng Liu 的无数贡献 。感谢 Mukund Narasimhan、Angela Sheu、Ang Xu、Chengcheng Hu 和 Dumitru Daniliuc 所做的许多有意义的讨论和反馈 。感谢 Roger Wang 和 Randall Keller 的出色领导 。