「InfoQ」150 毫秒?,如何做到99%的搜索请求延迟低于( 二 )


对于写操作 , 我们将加密的数据插入到RocksDB中 。 如果索引被缓存 , 那么缓存的索引也会通过再次从数据库读取更新后的文档来更新 。 我们还持久化缓存的会员ID , 以便在启动时将它们的索引重新加载到缓存中 。 这使缓存即使在部署之后也能保持温度 。 分区、复制和备份
与大多数分布式系统一样 , 我们通过复制和分区来处理可伸缩性和可用性 。 数据按会员ID和文档ID的组合进行分区 。 一名会员的数据可以分布在多个分区上 , 这有助于我们针对具有大型收件箱的会员进行水平扩展 , 因为索引创建负载可以由多个分区分担 。
对于每个搜索器分区 , 我们有三个活动副本和一个备份副本 。 每个副本独立地使用来自Kafka流的索引事件 。 我们在适当的地方进行了监控 , 以确保没有一个副本比它的对等副本延迟高 。 备份副本定期将数据库快照上传到我们的内部HDFS集群 。 和备份副本一起 , 我们还会备份Kafka偏移量 。 这些偏移量用于确保在服务从备份数据集启动之前 , 我们能够完全捕获Kafka丢失的数据 。 摄入
消息数据的真实来源是Espresso表 。 我们使用Brooklin以流的方式将来自这些表的更新传递给一个Samza作业 , 然后将这些更改日志转换为搜索器索引所需要的格式 。 流处理作业将这个流与其他数据集连接 , 从而使用要使用的实际数据装饰ID(例如 , 用姓名装饰会员ID) 。 它还负责对搜索器所需的数据进行分区 。 现在 , 每个搜索器主机只需使用它所承载的特定Kafka分区的数据 。 代理
代理服务是搜索查询的入口点 , 它负责:查询重写:它根据查询用例将原始查询(例如:“applebanana”)重写为InSearch格式(例如:TITLE:(appleANDbanana)ORBODY:(appleANDbanana)) 。 不同的搜索查询可能使用不同的评分参数对某些字段进行优先级排序 。 分发收集操作:它将请求分发给搜索器主机 , 整理从搜索器那里返回的结果 。 重试:如果出现可重试的失败 , 或者一个特定的搜索器耗时太长 , 那么代理将在一个不同的搜索器副本上重试请求 。 重新排序:对所有搜索器主机的结果进行重新排序 , 得到最终的结果集 , 并根据分页参数进行精简 。
代理使用我们的内部D2zookeeper服务(它维护每个分区的搜索器主机列表)来发现每个分区的搜索器主机 , 以便选择扇出主机 。 我们还确保在这些主机上进行严格的路由 , 这样 , 给定会员的请求就会转到相同的搜索器副本 , 进而就不会在多个副本上重建索引 , 并且提供了一致的搜索体验 。 小结
到目前为止 , 所有来自LinkedIn旗舰应用的消息搜索请求都由InSearch提供 , 我们能够以低于150毫秒的延迟服务于99%的搜索请求 。
目前 , 我们正在将几个企业用例迁移到新系统中 , 并评估其他应用 。 此外 , 我们现在开始利用新的消息搜索系统来加速改进LinkedIn的消息传递体验 。


推荐阅读