58 技术沙龙——云搜 知乎 58 同城 搜索架构


本文地址:http://www.6aiq.com/article/1549118463410
知乎专栏 点击关注
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出

背景

2019 年 1 月 21 日,由 58 集团技术工程平台群联合人力资源神奇学院共同组织的 58 集团技术沙龙第八期 -“搜索工程架构”在 58 集团北京总部举办。沙龙邀请了知乎搜索技术架构团队、58 集团 TEG 搜索技术部团队研发人员。由知乎搜索技术架构负责人孙晓光、58TEG 搜索技术部卢克两位分别分享了各自团队在搜索工程架构实践方面的经验。

部分干货总结

一、知乎搜索工程架构的演进

1. 初代搜索

知乎自建搜索起步于 2016 年,此前知乎的搜索构建于搜狗提供的技术方案。随着业务高速增长,索引时效性、排序质量和内容多样性等定制化需求越发突出,公司决定搭建自己的搜索业务。初代的知乎搜索,解决的是从无到有的问题,因此选用 ElaticSearch 来搭建。从 16 年 8 月份开始,历史半年密集开发,搜索团队搭建起了知乎的第一代搜索。随着初代搜索逐步放量得益于对自己内容质量更深刻的理解,搜索各项业务指标都开始逐步提升。

2. 搜索现状

在初代搜索全量几个月后,搜索系统的稳定性、代码模块过度耦合,严重影响开发效率以及流水线数据质量的稳定性,我们开始规划对初代搜索进行第一次大规模的重构。经过 2018 年一年的工作,我们利用从初代搜索积累下来的经验,将原有系统所有的组件基本上都重新设计和开发了一遍。虽然模块数量明显增加,但是得益于模块和模块之间边界更清晰的划分,整个系统的可维护性更高且更易于理解。

3ef1fa03b3084cdeb3e62de02bf8cc70.png

在新架构上线完成后,以往很可能需要数月开发上线周期的多源召回和基于点击调权的混排策略得以在更短的时间内开发上线,完成放量。配合公司成熟的 AB 测试平台,算法团队的策略迭代效率得到了极大的提升。

本轮迭代工期拉的最长的是搜索引擎部分。我们使用 Rust 重写了一套同 Lucene 索引格式兼容的搜索系统,逐步的替换掉了 ElasticSearch,同时将原本倒排、正排和排序集成在一体巨大的单体服务分拆成多个独立的服务分别维护。一方面每个服务更加专注也很好的控制了代码量的规模,再加上 Rust 无 GC 的特点,最终整体服务的稳定性、可维护性和可管理性都得到了很大的进步。

为了屏蔽数据流水线批量和增量两个数据源的事实,我们还基于 HDFS 和 MySQL 搭建了新一代的数据流水线 DataHub。为用户暴露出来一个版本单调递增的文档数据流,流水线的消费者可以用更简单的方式来消费流水线的数据,由 DataHub 自动决定是完全以增量还是以批量加增量的方式恢复状态。

3. 继续完善

经过 2018 年的大规模重构,知乎搜索的稳定性和迭代效率有了质的提升。但是我们也看到在效果上还有很大优化空间,在未来我们将会投入更多工作在排序质量和内容召回能力等方向。

二、58 搜索技术架构

1.58 搜索系统架构概览

uesearch 搜索系统是搜索技术部完全自研的一套高性能,易扩展的搜索系统,目前广泛服务于 58 业务的各个垂直搜索场景。在 58 这个类电商性的业务场景下,对搜索的时效性和一致性,有着比普通垂直搜索更高的要求,uesearch 很好的满足了其业务场景的苛刻要求,长期以来表现良好,这与其系统的设计和架构有着密不可分的关系。uesearch 整体系统架构如下图(1)所示。

图(1)搜索系统架构



(1)上层 proxy 是接入集群,为对外服务接口,接受搜索请求,其无状态性能够保证增加机器就能扩充 proxy 集群性能。

(2)中层 merger 是逻辑集群,主要用于实现搜索合并,以及打分排序,业务相关的 rank 就在这一层实现,其无状态性也能够保证增加机器就能扩充 merger 集群性能。

(3)底层 searcher 是真正检索集群,服务和索引数据部署在同一台机器上,服务启动时可以加载索引数据到内存,请求访问时从内存中 load 数据,访问速度很快。

(3.1)为了满足数据容量的扩展性,索引数据进行了水平切分,增加切分份数 (即 sharding 功能),就能够无限扩展性能,如图(1)searcher 分为了 N 组。

(3.2)为了满足一份数据的性能扩展性,同一份数据进行了冗余,理论上做到增加机器就无限扩展性能,如图(1)每组 searcher 多个副本冗余。

如此设计,真正做到做到增加机器就能承载更多的数据量,响应更高的并发量。

2. 高效实时索引更新设计

实时索引更新是一个搜索引擎非常重要的一环,对于更新时效性要求高的场景,快速文档更新和检索生效是一项很有技术挑战的技术。

58 的实时索引实现,是在检索服务模块中,一边提供检索功能,一边接收文档的更新,在内存中实时建立倒排索引,内存中建立好的倒排索引然后在进程内直接提供给检索线程使用,从而实现索引数据快速更新生效。实时索引内部设计如图(2)所示。

图(2)实时搜索实现

一个检索进程内部有两个监听服务,一个是接收检索请求,另外一个是接收文档更新。接收到文档更新请求后,有一个专门的线程负责在内存中建立倒排索引,建成的倒排索引数据文件,会交付给检索的线程使用,从而实现更新的文档能被快速的查询。

图(3) 倒排索引数据分段策略

实时建倒排的过程如图(3)所示,在检索进程的内部有大小不同的倒排索引数据段,这根据时间段而定,每个数据段都有一个最长生命周期。接收到的更新文档,每 3 秒 (根据实时性的需要而定,下同) 生成一个小的倒排结构,然后生成的倒排就可以参与检索。3 秒的数据段生命周期到了后,会与 15 分钟的倒排数据段合并成一个新的 15 分钟倒排段,而 15 分钟的数据段生命周期到了后,会与一个小时的数据段合并,生成一个新的一小时段,以此类推,一直合并到最后的永久段。整个过程保证了数据的快速更新,和检索的效率。

3. 云搜

云搜是 58 搜索团队基于 uesearch 和 kubernetes 系统之上开发的私有云搜索服务。在云搜系统中,用户只要关心两件事,在云搜上自定义搜索 schema 和文档写入到云搜,然后即可使用检索服务。整个搜索系统的创建,资源的分配调度,分片和副本设置等功能都完全由云搜平台自动实在。云搜会在内部为每个搜索业务,自动化的创建一个实例,保证各个业务的独立使用。

图(4)云搜示意图

如图(4)所示,从资源的层面看,云搜通过 kubernetes 把所有的机器硬件资源统一管理起来,通过虚拟的 docker 容器来使用这些资源,资源的分配的单位是 pod,每个 pod 可以包括多个容器,但每个 pod 是一个模块或者服务,是一个完整的逻辑单元。一个搜索实例的各个模块,就通过 kubernetes 的分配和调度,生成了多个 pod,多 pod 协同工作,共同完成了一个搜索服务。当某一个模块或者服务出现故障,也即一个 pod 发生了异常,kubernetes 会自动找到空闲的资源,重新生成一个 pod,我们的云搜会完成对应的数据同步和完整性检验,从而让新的 pod 参与服务,检索系统就实现了自动恢复。

三、总结

本次沙龙大家就搜索索引组织更新、分布式索引状态同步、query 改写、多副本之间一致性、相关性计算、搜索质量评估等方面,展开深入讨论,交流双方的技术亮点,并分享各自解决挑战的方案,收获较大;在一些开源的技术如 Elaticsearch,Lucene,Kubernetes,根据双方在工程中的使用情景,交流使用经验,深入总结其优点弊端,收获颇丰。未来希望在搜索工程架构的建设和运维上有更多的探索和交流,共同提高搜索工程架构的稳定性、时效性,提升搜索结果的相关性。


本文地址:http://www.6aiq.com/article/1549118463410
知乎专栏 点击关注
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出