花名:长文
部门:算法中心搜索业务组
入职时间:2016年
主要从事蘑菇街搜索引擎实时增量商品信息补全以及搜索业务接入
一、引言
搜索引擎作为电商平台的主要入口之一,承载了大量的用户访问,也孕育了大量业务发展。引擎中的数据作为电商展示的基础,主要分为实时与非实时部分。非实时部分包括算法分数等定时产出的数据;实时部分包括商品各个维度的信息变化,包括商品标题、价格等等。而实时数据与非实时数据同步到引擎的过程是通过dump系统实现的。
根据被处理数据的实时性不同,dump系统可以笼统的分为:增量dump系统(实时)与全量dump系统(非实时)。入职后主要从事与增量dump系统相关的商品数据补全以及搜索业务接入。
增量dump系统:如图1.1所示,商品信息发生变动的时候,增量框架服务通过监听binlog、业务消息等方式感知商品信息的变动,进行消息主键的提取,消息体数据格式化后,请求补全服务进行商品信息补全。在接收到补全结果后,传入消息队列供引擎、hbase以及其他业务方进行消费。举例来说,从蘑菇街app进行商品搜索“碎花连衣裙”,会出现一个列表页,列表页中有每个商品的价格、标题等属性。其实价格和标题对应着引擎中的两个字段:price、title。那么,怎么保证商家修改了商品的价格或者标题的时候,能及时的更新引擎中的这两个字段呢?其实就是通过增量dump来做的:商家修改标题->数据库中title字段产生变更->数据库产生binlog数据->binlog数据被消息队列收集->dump系统监听到这条binlog消息,解析出商品主键,调用商品补全服务获取商品最新的标题->将最新的标题数据放入消息队列并最终更新到引擎。最终引擎的数据就和数据库中商家的修改结果保持了一致。
图 1.1
二、从PHP到JAVA服务化
入职的时候,适逢蘑菇街架构从PHP转为JAVA服务化的过程之中。当时PHP版本的补全服务处理流程大致为:接收并解析增量框架的传入参数->调用PHP服务进行商品所有信息的补全->边界状况处理->封装输出数据格式。
作为当时的重要且紧急的任务,将补全服务从PHP迁移至JAVA并进行服务化,面临的主要挑战有:
1. 涉及业务接口30+;
2. 涉及业务字段100+;
3. 推动尚未迁移的依赖服务进行服务化迁移
服务化方案如图2.1所示:
图 2.1
主要的改造点为:
1.首先将补全服务进行拆分:服务A与服务B。服务A主要进行商品业务字段的补全,变更消息来自消息队列ms1;服务B主要负责算法字段的补全,变更消息来自消息队列ms2。这么做的原因是:商品补全服务A进行商品所有业务数据的补全,调用30+ rpc服务接口,对引擎进行insert操作。商品补全服务B进行商品部分算法字段的补全,对引擎进行update操作。避免因为算法数据的变更导致商品业务数据字段的全部更新,进而减少业务rpc接口的调用量。
2. 增强监控报警
3. 增强对业务rpc接口的容错、容灾
在这次改造中,通过补全服务搭建并对接各个业务方的rpc服务,加速了对增量、全量dump系统的理解。在后续的上线流程中,更是经过了新引擎实例(使用新的补全服务)的搭建、数据比对、灰度上线、线上回归等诸多步骤。对线上数据,我们充满着敬畏知心,谨慎操作。
三、从JAVA服务化到拼装平台化
进行JAVA服务化改造之后,运行稳定,但是其实并没有在当前增量架构下做到最优,主要原因有:
1. 商品补全服务A需要对商品的所有业务数据进行补全,这个过程需要调用30+rpc业务接口,最终形成一个100多个字段的doc数据,最终插入到引擎中。
2. 整体链路较长:增量框架服务与商品补全服务都搭建了2套。这对于数据更新的实时性、运维、问题排查等多个方面,都会带来诸多不方便
3. 业务数据的每一次变更,都会对引擎进行insert操作,对引擎不够友好。
针对以上可以优化的点,我们制定了新一轮的优化目标
进行字段级更新:每一次补全过程,会根据变更的来源补全指定的字段。比如:当接收到商品价格变动的binlog数据时,调用商品价格接口以及相关接口,进行价格相关的商品业务数据的拼装。改造调用方式为异步调用,缩短处理时延。
协同引擎进行改造,对业务字段和算法字段进行隔离,将算法字段的处理从补全服务中剥离出来,缩短处理链路。
由于第一点,绝大部分的业务数据变更都为update操作,对引擎更加友好。
为解决补全服务中rpc接口以及业务字段的管理问题,开发统一的补全服务配置管理控制台,处理补全服务的实例、接口、字段的管理问题。
针对优化目标1,通过下图可以更加形象的理解补全服务依赖的rpc服务间的依赖关系:
图3.1
图3.1中共有5个接口分别是:
表 3.1
通过图3.1以及表3.1 可以发现:
根据接口间的输入/输出参数的关系,最终会形成一个接口间的依赖图。有依赖关系的接口需要确认其依赖接口已经被调用。举例来说,当系统接收到商品折扣信息的binlog更新消息的时候,我们认为discountPrice需要进行变更,系统需要调用的rpc接口序列为:ItemInfoService->ItemUserService->ItemPriceService->itemTagService。接口ItemCateService不必调用。
其中ItemTagService因为会被discountPrice影响,需要进行调用并获取tag字段,进行更新。而price和userId这两个字段并没有产生变动,因此可以不必进行rpc接口实时调用,可以使用缓存进行优化。
需要确保接口的依赖图中,不会存在依赖环,否则无法对接口间的依赖关系进行解析。
增量dump链路架构如图3.3所示:
改造之后,我们不再需要增量框架服务B以及商品补全服务B,并将商品补全服务A拆分为:atom、cora。
cora完成对所有业务rpc服务的对接以及业务迭代,并且与atom通过rpc服务进行对接;通过缓存来较少接口调用量以及提升补全拼装效率,降低处理时延,减少接口调用量。
atom是一个与具体业务无关的通用拼装平台,经过atom处理完成的绝大部分数据为update类型的数据。
原有的接收增量消息的大量业务方只对inset操作进行了适配,基于这一点考虑,我们搭建了新的补全服务,将ms3产出的update类型的消息(仅包含产生变更的字段)通过cache补全为包含一个商品所有字段的insert消息,原有的业务方不需要作调整进行适配。新接入的业务方可以接入消息队列ms3,也可以接入消息队列ms2。
图 3.3
通用拼装平台atom架构如图3.4所示:
图 3.4
项目被细分为多个模块:
Schema Console:增量补全服务配置管理控制台。在这里针对补全服务进行实例、接口、字段的管理以及与增量来源相关的配置信息的管理,实例与接口、接口与字段均为一对多的关系。最终数据存储在mysql中。可以方便的通过控制台进行接口上下线、字段管理、补全服务reload等操作。
PreLoader:配置数据加载模块。配置信息包括实例、rpc接口、字段、容灾策略、消息变更动作等信息。PreLoader通过读取Schema Console所维护的原始配置数据,解析、校验并格式化为配置。atom通过热加载来load配置数据,完成服务依赖环校验、服务可用性校验等并存储于内存中供使用。
PlanFactory:执行计划工厂。基于配置数据,根据不同的策略解析,最终生成一份执行计划,计划指出:来自各个消息队列的消息,分别需要执行哪些接口,哪些接口的入参可以从缓存获取,每个接口的输出字段是哪些,字段的容灾策略是什么样的,等等信息,指导进行rpc服务调用。只在服务reload时执行。
PlanContainer:执行计划容器。我们一共使用了4种策略进行执行计划的生成:全部为insert操作的doc级更新执行计划;不使用缓存并生成update消息的字段级更新执行计划;使用缓存并生成update消息的缓存字段级更新执行计划;不使用缓存补全指定字段的字段配置计划。执行计划在每次reload之后进行生成并存储与内存中。生成多种执行计划的目的是为了减少对缓存的强依赖,避免因为缓存不稳定或缓存脏数据的问题导致拼装服务不可用。计划的选用通过开关控制。
PreTeatService:预处理服务,作为补全拼装主流程的一个依赖模块。他将缓存服务进行了完整的封装,每一次补全拼装的流程中,校验是否有接口可以使用缓存,读取缓存,校验缓存数据的正确性。如果因为key失效等原因导致未读取到指定字段数据,则直接通过“字段配置计划”进行指定字段的拼装。保证拼装主流程中不需要关心繁琐的预处理流程。
Dump主流程:处理商品信息补全。根据消息队列中商品变更数据的来源以及执行计划配置开关,确定需要执行的执行计划,对执行计划进行商品主键填充,生成一份可执行的执行计划,并传递给预处理模块进行缓存相关的优化处理。补全的商品字段数据都存储在内存中的一个字段容器中,按照执行计划生成请求参数、调用指定rpc服务、处理rpc服务容错容灾、字段容灾(容灾模块)、将返回数据提取、校验、监控并放置在字段容器中,按照增量dump协议对消息体进行封装,并最终返回给增量框架服务指定数据格式的消息体。
进行到这里,我们已经将上文提及的优化目标全部实现,包括使用控制台解决配置管理问题、仅补全发生变动字段的字段级更新;使用缓存来降低rpc服务调用量、加快接口处理速度;所有rpc服务都采用异步方式进行调用,提升处理效率;去除了冗余的系统以及服务;超过95%的消息为update消息,对引擎更加友好。
目前这套解决方案已经平稳运行并经过了多次大促消息量激增的考验。得益于atom项目与业务的无关性,目前已经被使用在包括蘑菇街主搜dump在内的多个应用场景。
四、总结
从刚入职时候毫无经验地接手补全服务的JAVA服务化,进而到拼装平台化的改造,其中有业务对接,也有系统搭建、改造、优化的过程,每一步都会带来新的挑战与成长。作为仅有1年多经验的职场新人,简单概括下这1年多来的工作感受,与大家共勉。
1. 多问
新入职或者新接手一个陌生的项目,对于上下游影响、处理流程以及业务逻辑等诸多问题很难快速的熟悉,特别是其中一些业务上的妥协、为规避风险而进行的特殊处理等。这些是学长、学姐们都经历过的事情,不需要顾虑,多问一问我们耐心的学长、学姐们,他们会很nice的和你诉说当时这么设计的来龙去脉,也会和你补充上如果这里发生变动,对上下游会造成什么影响,帮助你一起尽快hold住项目~
2. 多做
共事中我们秉持“互相成就”的想法,所以不用太在乎这个事情是不是在我的职责范围内,“脏活累活”也可能会有发光的一天。做的事情越多,接触的东西也就越多,这个对自己、对团队都有很好的影响。
3. 保持激情
工作中难免会有遇到难题,保持激情可以帮助我们想法设法的解决他们。大胆的说出你的想法,你会感受到全世界的帮助。其实只要心态对了,很多事情都可以迎刃而解,适时的转变想法,感受曲径通幽带来的愉悦~
领取专属 10元无门槛券
私享最新 技术干货