搜索中台 ES 优化实践
徐胜 | 携程资深搜索工程师
2021年3月20日,在多想第一期线下分享中,作者分享了关于自己对旅游类搜索的实战和优化。 本文聚焦旅游类度假搜索引擎,主要检索符合从出发地到目的地的相关旅游产品。 其底层引擎都是基于开源的分布式检索平台Elasticsearch来搭建。整个演讲从如下三个角度来分享底层搜索引擎的优化过程及相关思路,希望可以给同行提供一些启发和思考:
- 写入层优化
- 查询层优化
- 业务实战分析
1.关于ES
Elasticsearch 是一个分布式的免费开源搜索和分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。 Elasticsearch 在 Apache Lucene 的基础上开发而成,由 Elasticsearch N.V.(即现在的 Elastic)于 2010 年首次发布。
Elasticsearch 以其简单的 REST 风格 API、分布式特性、速度和可扩展性而闻名,是 Elastic Stack 的核心组件。Elastic Stack 是一套适用于数据采集、扩充、存储、分析和可视化的免费开源工具。人们通常将 Elastic Stack 称为 ELK Stack(代指 Elasticsearch、Logstash 和 Kibana),目前 Elastic Stack 包括一系列丰富的轻量型数据采集代理,这些代理统称为 Beats,可用来向 Elasticsearch 发送数据。
目前ES是全球NO.7的数据库,是全球NO.1的搜索引擎,主要应用场景是垂直搜索引擎、数据可视化分析、日志分析等领域。
图1.数据库管理系统的排名
图2.搜索引擎的排名
2.关于搜索中台架构
旅游类的搜索中台,主要包括了团队游、自由行、游学、主题游、玩乐门票、邮轮等旅游线路的搜索。 如下图,整体上,可以分为三层:
- 前台
前台包含度假、玩乐、邮轮、向导等前端。
- 中台
中台服务主要是搜索预处理服务,主搜索引擎服务,产品卡片详情服务。
- 存储后台
数据存储后台,主要是基于ES和DB。
图3.搜索中台架构图
3.业务优化实战
旅游类搜索架构中,为什么要做优化?存在什么缺陷,以至于要做优化?下面我从几个点来讲一讲。
在旅游的场景开发过程中,我们经常会遇到一些bug,譬如大批量写入超时的情况,查询超时,写入的时候CPU和Load负载特别高,严重影响线下搜索的业务了;譬如,底层的ES集群出现单节点物理机磁盘损坏,分片不合理导致单分片容量过高等等情况。基于我们在线上业务上遇到的情况,我们总结了一套业务层面优化规划方案。
业务优化规划,主要是从集群侧优化和服务侧优化两个维度,总结为如下思维导图:
图4.ES业务优化方案
4.集群部署方式优化
集群的瓶颈通常跟底层物理机的资源,是否使用了高配置的物理机、高IOPS的读写、部署方式等等相关。
从部署方式上面,我们主要是采用的读写分离模式,即写入节点、查询节点、数据存储节点和Master四种角色独立分开。用户应用层的流量首先会经过LB层,到ES集群。在ES集群中,Coordinating node主要是承载查询的流量,Ingrest主要是承接写入节点的请求,data node是存储ES原始索引数据,Master是控制整个集群的主节点。如下图所示。
图5.读写分离部署架构图
从硬件资源层面,我们建议两点:
(1)最优化部署方式
尽可能使用高IOPS和SSD的磁盘,保证ES独占资源。
核心业务集群配置专属节点。
(2)最优化容量规划
单分片最好不超过20GB数据。
每个索引设置一个副本。
5.写入层面优化
写入优化措施有很多,有的是从集群角度来考虑,有的需要从业务角度来考虑,我们这边两个情况都有。综合来说,提升写入速度从以下几个方面入手:
- 加大translog Flush间隔,目的是降低IOPS、writeblock;
- 加大index refresh间隔,除了降低IO,更重要的是降低了segment merge频率;
- 调整bulk请求;
- 优化磁盘间的任务均匀情况,将shard尽量均匀分布到物理主机的各个磁盘,保证单分片容量在合理区间;
- 优化节点间的任务分布,将任务尽量均匀地发到各节点;
- 优化Lucene层建立索引的过程,目的是降低CPU占用率及IO,例如禁用_all。
图6.写入优化点
6.查询层面优化
对于查询层面优化,首先还是先分析原因。有没有慢日志?是否包含大query,为什么查询慢?
通常总结下来,提升查询速度可以从以下几个方面入手:
- 业务上有没有大query查询,需要分析query复杂程度
- 索引结构是否合理
- 是否需要计算相关性,query和filter的合理使用
- 优化搜索中的大聚合查询
图7.查询优化点
7.优化实战
对于玩乐门票的业务,核心的ES集群主要是使用ES 5.3.2版本来部署的。为了保证核心业务的高可用行,用2套集群来提供同城双活。由于疫情逐渐恢复,景点和POI的数据量越来越多,多个JOB写入ES的数据量也越来越大,导致同一个产品ID会出现频繁更新的情况。
其主要的业务特点如下:
- 疫情过后,景点数据量逐步增大,写入数据压力增加。
- 多个JOB直接写入ES,没有增加缓冲区。
- 一个分片,多个副本。
- 同一个产品ID重复写入。
- 单shard数据近30GB左右。
在优化之前,ES的性能监控图如图8所示。在经过深入分析之后,实施了一系列优化措施,优化后的性能指标如图9所示。
主要优化措施:
- 增加写入去重判断。
- 1分片14副本,改造为5分片2副本(总共是15个Node)。
- 统一部署,改造为读写分离部署。
- 控制单分片数据量不超过20GB。
8.优化前后对比
在玩乐业务优化之前,索引设计、写入逻辑都有很多问题,包括索引结构不合理(1个分片14个副本),写入存在对重复ID进行写入,批量写入的时候没有去重等等。
我们将1个分片14个副本的索引结构,修改为5个分片2个副本的索引结构。在同等硬件和环境情况下,我们做了一个监控的对比,分别如图8和图9所示。
图8是老索引结构(1个分片14个副本)的写入高峰期时监控曲线。 从图中可知,在每天凌晨高峰期写入的时候,segments数量达到60多,CPU高峰期达到85%以上,但此时的Query的qps并不是特别大。由于读写没有做分离,导致查询的时候,线上有很多超时的情况。
图9是新索引结构(5个分片2个副本)的监控曲线。 在同等物理机配置下面,可以看出segments降到了40以下,CPU高峰期不超过15%,Load负载明显小了很多。
图8. 优化前的ES性能指标监控图
图9. 优化后的ES性能指标监控图
后期规划方向,还是在基于Elasticsearch的搜索平台建设上面,通过搜索平台和搜索中台的建设来赋能业务。