建造并维护一个亿级的查找引擎并非易事,也不存在一劳永逸的最优办理方法。本文是在实践中不断学习和总结的成果,介绍了怎么建立一个可支撑从千万级到亿级产品量级的查找体系,并完成查询总 QPS 从百级增长到千级,写入总 QPS 从百级添加到万级的进程。其中,ES 资源扩容是必不可少的,但除此之外,本文还将重点介绍一些扩容无法处理的 ES 功能问题。希望经过本文咱们可以对 ES 的运用场景有更多数据和运用上的参阅。因为篇幅有限,关于稳定性办理的部分将在下篇文章中进行介绍。

事务介绍

渠道招商办理体系服务于抖音电商渠道活动的多实体招商场景,会经过招商渠道来进行收品,选品,然后分发品到各 C 端体系。招商的实体也十分的多样化,有达人直播间,产品招商,优惠券招商等等,其中产品招商是咱们体量最大的招商实体。

从 0 到 1 建立亿级产品 ES 查找引擎

招商渠道服务架构

数据中心

数据中心是一个基于 ES 的查找服务,供给可装备化的、可扩展的、通用的数据获取编排服务,是支撑招商渠道数据查询的通用服务。

要害概念了解:

  • 目标:目标是被咱们用来描述一个实体或许对象的某个特点的元数据,比方产品名称,店肆体会分,达人等级,报名记载 ID,一起它也可以是某个对象的最小更新和获取单位,比方产品比价信息。一切有清晰语义的字段咱们都可以定义为目标

  • 调集:表示一组可经过某种共性收敛的调集,比方产品特点调集,店肆特点调集,别离可以用产品 ID,店肆 ID 去获取,也可以是产品报名记载调集,经过报名记载 ID 获取,它在事务上表达一组有相关联系的目标,和目标是1对多的联系。

  • Solution:数据获取计划,咱们抽象出目标和调集两个概念,是为了数据可以以最小单位获取,并且可以不断横向扩展,Solution 帮咱们抽象不同调集下的目标的获取方法。

  • 自定义表头:自定义表头即指任何一个二维行数据列表要展现的 Title,它和目标是 1 对多的联系;

  • 挑选项:挑选项即指任何一个二维行数据列表需求运用的挑选项,它可目标是 1 对 1 的联系;

  • 审阅视图:审阅视图指的是审阅事务场景下,由一组自定义表头和一组挑选项可动态烘托出来的一个审阅页面。

从 0 到 1 建立亿级产品 ES 查找引擎

从 0 到 1 建立亿级产品 ES 查找引擎

数据中心元信息规划

在功能规划中,经过目标–>【挑选项,自定义表头】–>审阅视图–>终究动态烘托出一个审阅页面的进程,因为咱们是多实体多场景招商,不同实体不同场景需求不相同的审阅视图,所以咱们规划出来的这一系列才能,可以动态组合任何需求的审阅视图作用。

数据中心就是为了上层事务供给通用数据获取才能的,包含数据同步,数据查询。数据来历目前有两个,外部 RPC 接口,以及报名记载 ES,数据中心整合了两套数据获取计划,对外彻底无感知,即获取哪个调集下的哪些数据目标即可。

ES 建立的意义就是为了支撑招商报名记载的挑选计算才能的,为上层事务输出它想要的数据内容。

从 0 到 1 建立 ES 集群

从 0 到 1 建立体系,在满意根本事务需求的根底上,稳定性方面需求支撑以下两点;

  • 根本容灾机制,是指当体系因为根底组件,以及读写流量改变使功能受到影响时,事务能及时自我调整。
  • 数据终究一致性,指报名记载 DB –> ES 多机房数据是完好的。

计划调研

ES 集群容量评价

ES 集群容量评价是为了确保集群建立起来以后可以在未来一段时间内供给稳定服务的,首要需求可以处理以下问题:

  1. 每个索引应该设置多少分片,后续预估数据增量有多少,读写流量预估;
  2. 单个集群应该设置几个数据实例,单个数据实例选用什么规格;
  3. 了解垂直扩容和水平扩容的差异,当数据量超预期激增,或许流量超预期激增,咱们的应对战略是什么,以及 ES 集群容灾应该怎样规划。

要害处理办法:

  1. ES 索引分片数一旦设定,不可修改,所以承认分片数很重要,一般分片数和 ES 实例成整数倍联系,确保负载均衡;
  2. 单个分片的大小在 10~30G 是比较合理的,索引过大会影响查询功能;
  3. 流量激增可以依托扩容处理,数据激增可删除存量老旧数据或添加分片数处理;并且必须选用多机房容灾布置计划布置,互为容灾机房。

数据同步链路选型

首要处理 DB 报名记载怎么同步到 ES,其它相相关的目标怎么写入 ES,怎么更新及确保数据的一致性。

  1. DB -> ES 需求是准实时数据流,报名记载等信息的改变必须是准实时可查找到的;
  2. 报名记载除了自身字段还需求补充其报名产品,店肆,达人等特点字段,也写入到 ES,且可以支撑部分更新,所以 ES 写入方法只能是 Upsert 方法;
  3. 单条报名记载更新必须是有序的,且不可抵触的。

ES 索引根本装备调研

了解必不可少的 ES 根本原理和装备。

  1. {“dynamic”: false}避免 es mappings 主动胀大,或新增非预期索引类型;
  2. index.translog.durability=async,异步刷新 translog 有利于提升写入功能,但是有丢数据危险;
  3. ES 默许 refresh interval为 1s,即表示数据写入成功后最快一秒可以查到。

数据同步计划

从 0 到 1 建立亿级产品 ES 查找引擎

数据同步链路图

DB –> ES 数据同步计划,终究选用的是异构数据同步写 RocketMQ Flink 多机房消费的方法,一起当报名记载初次写入时经过 Faas 自定义转换脚本填充扩展目标,扩展目标的更新依靠变更音讯监听和守时使命两种方法。调研的时候,DB -> ES 多机房的计划其实有三种,终究咱们挑选了第三种计划,以下咱们对比下三个计划的差异点:

计划一:经过 异构数据同步(Dsyncer)直接写入 ES 多机房

从 0 到 1 建立亿级产品 ES 查找引擎

缺点:

  1. 直写在满意 ES 同步布置多机房的诉求上是处于弱势的,因为无法确保多机房一起写成功,那布置多个异构数据别离写可以吗?可以的,即工作量添加三倍,大约十几个索引。
  2. 直写 Bulk 的写入才能是相对弱的,跟着流量动摇写入尖刺也会比较明显,对 ES 的写入功能不友好。
  3. 直写无法确保 ES 多更新进口的状况下单条报名记载的有序更新,添加大局 Version 版别可以?可以的,但太重了。

优点: 依靠途径最短,写入推迟低,体系危险最小,对于小流量的事务,以及同步场景简单的事务是彻底没问题的。

计划二:经过 RocketMQ 写 ES 单机房

在 DB 经过 RocketMQ 写 ES 单机房后,经过 ES 供给的数据跨集群复制才能,将数据同步到其它机房。

从 0 到 1 建立亿级产品 ES 查找引擎

计划三:经过 RocketMQ Flink 方法写 ES 多机房

在 DB 经过 RocketMQ 写 ES 集群时,别离起多个独立的 Conusmer Group 使命,体系可选用 Flink 分布式体系,将数据别离写入多个机房。

从 0 到 1 建立亿级产品 ES 查找引擎

计划二和计划三的差异点只有一个:就是写多机房的方法不同,计划二是写到一个机房,然后将数据准实时同步到其它机房,而计划三是其多个独立的 Consumer 别离写多机房。

计划二和计划三的缺点是相同的:依靠途径最长,写入推迟容易受根底组件抖动的影响,但是计划二的致命缺点是体系存在单点危险,假定经过 LF 同步数据到 HL 和 LQ,那么在 LF 挂掉之后体系也就无法运用了。

计划三的优点是多机房写入链路互相独立,相比计划二任何一条链路出问题,都不会对事务形成危险;RocketMQ 能轻松处理单 Key 次序更新问题,这也是计划一不可取的原因

为什么经过 RocketMQ 写入就能处理乱序和抵触问题呢?

  1. 首先 ES 写入是基于 Version 版别号做乐观锁控制的,假如一起并发更新同一条记载,那么咱们一起拿到的 Version 版别是相同的,假定是1,那么咱们都将 Version 更新成2去写入,就会产生抵触,总是产生抵触就会形成丢掉更新的问题;
  2. 一般事务场景都是需求确保基于 Key 有序消费,也是 Partition 有序消费,有序消费需求有两个必要条件:音讯被存储时保持和发送的次序一致;音讯被消费时保持和存储的次序一致。

所以事务想要音讯的有序消费,就需求确保发送音讯同 Key 发送到同一个 Partition,消费音讯确保同 Key 音讯一向被同一个 Consumer 消费。但事实上,上面提到的两个必要条件是理想状态下的,有些状况下是没法彻底确保的,比方 Consumer Rebalance,比方写某 Broker 实例一向失败,详细下面会再剖析呈现原因和处理版别。

从 0 到 1 建立亿级产品 ES 查找引擎

一张图说明 RocketMQ 分区有序

  • 对于指定的一个 Topic,一切音讯依据 Sharding Key 分红多个(Queue)。
  • 同一个 Queue 内的音讯按照严厉的 FIFO 次序进行发布和消费。
  • Sharding Key 是次序音讯中用来区别不同分区的要害字段,和一般音讯的 Key 是彻底不同的概念。
  • 适用场景:功能要求高,依据音讯中的 Sharding Key 去决定音讯发送到哪一个 Queue,一般分区有序就可以满意咱们的事务要求,一起功能高。

这儿需求留意的是 经过 RocketMQ 也许现已帮事务处理 99% 的乱序问题了,但并不是 100%,极点状况下音讯仍可能呈现乱序消费问题,比方产生 ABA 现象,比方 Partiton 故障时音讯被重复发送到其他 Partition 行列等,所以一致性对账必不可少。

多层对账机制

对账机制是处理 DB->ES 的数据一致性问题的,前面说 DB –> ES 是准实时数据流,并且依靠链路比较长,它在不同的状态下,咱们都需求有对应的监控,对账和补偿战略,确保数据终究一致性。

这儿咱们是做了三层对账,经过对账渠道对账,完成分钟级对账,以及离线对账,需求多层对账的原因会在下文一一进行解释。

从 0 到 1 建立亿级产品 ES 查找引擎

DB 同步 ES 链路故障剖析图

事务校验渠道(BCP )秒级对账

参阅上图,会发现 DB –> ES 同步依靠依靠组件比较多,这种状况下咱们更需求一个大局视角的对账来发现同步链路问题,即 BCP 实时对账。

BCP 对账是监听 Binlog 直接查 ES 多机房对账的单流对账,仅依靠 Binlog 流,中间环节呈现的数据同步推迟,或许堵塞都可经过 BCP 对账快速发现;仔细的同学会发现,假如 Binlog 断流,BCP 对账就对不出来了,后边说怎么处理这种状况,但至少可以看出来, 除了 DB->DBus,BCP 对账足以发现大部分同步推迟问题。为什么选用单流而非多流?

  1. 避免多流对账的数据流链路较长,会带来的不可控推迟问题,导致校验准确性偏低。

  2. BCP 对账的维护成本会大大降低,因为选用多流的话,多机房对账咱们需求维护多份 BCP 对账,这其中依靠维护的根底组件更多。

分钟级对账

上节说到事务校验渠道(BCP)对账掩盖不到的途径是 DB->DBus,也就是 Binlog 断流的状况。一般 Binlog 断流可能现已意味着更严重的事故,但咱们要做到的就是方方面面。

从 0 到 1 建立亿级产品 ES 查找引擎

分钟等级对账是直接查询 DB 和 ES 进行对账,不依靠任何组件,当产生纷歧致时则主动补偿。分钟等级对账一方面弥补 BCP 对账的缺乏,第二点则是加入了补偿机制。BCP 不补偿的原因是因为 BCP 首要还是为了发现问题,所以要保持轻量快速,还有就是它仍然依靠 RocketMQ,DBus 等根底组件,这种补偿仍然掩盖不住一切反常场景。

三分钟一次的对账默许状况下咱们会认为组件功能完好,只是某节点呈现短暂推迟而产生补偿,假如频频产生补偿报警就需求进一步剖析链路到底是哪里出了问题?此刻在咱们的场景下我会把链路一分为二,承认下 RocketMQ 之前链路出问题了,还是 RocketMQ 以及后续消费链路呈现的问题。经过故障剖析图,假如是 RocketMQ 之前链路出问题,比方 Binlog 断流、异构数据同步渠道组件挂了等,则补偿数据直接写到 RocketMQ 中,消费到多机房的,此刻读流量不必切流,且可以确保多机房数据的一致性。但假如 RocketMQ 挂了就会直接去写 ES 了,因为此刻咱们无法确保多机房一起写成功,所以咱们的决策是只写单机房,将一切流量切换到单机房。

RocketMQ挂掉是个十分不好的信号,这儿状况是比较复杂的。因为直写 ES,假如写流量高,体系此刻失去了限流维护,ES 纷歧定扛得住;单机房纷歧定可以一起承受一切读流量;假如频频产生写入抵触还需求做事务写进口降级。所以 RocketMQ 挂掉,可以理解为写链路的中枢体系瘫痪了,这是最不想看到的状况,所以 RocketMQ 的 SLA 是事务的基线。

T 1 离线对账

离线对账,是将 DB 和 ES 的数据天级同步到 Hive,增量数据校验终究一致性,假如纷歧致则主动发起补偿,离线对账是同步链路数据一致性的底线,数据最迟 T 1 补偿成功。

总结

以上咱们现已完成了第一阶段的建立,完成了容灾布置,一致性对账,以及根本体系反常应对战略。此刻 ES 可以支撑千万等级的产品索引的读写请求,单机房流量在 500 ~ 100 QPS 之间动摇,写流量根本维持在 500 QPS 左右。

但跟着事务的开展,ES 集群多次呈现 CPU 暴涨,一个或多个机房一起被打满,查询推迟突然添加,但是读写流量却动摇不大,或远不及体系峰值的景象,这种危险归源于 ES 集群呈现的功能问题,以及事务的运用姿势问题。这部分内容咱们将在下篇 ES 查找引擎的稳定性办理中为咱们继续介绍。

文章来历|字节跳动商业渠道 王丹