|
利用流量保障搜索质量的实践
359 一 背景的搜索服务是基于 Elasticsearch 的在线分布式搜索,为内部业务提供结构化和非结构化数据的多条件检索,支撑PC端、APP端、小程序端的搜索能力。搜索以中间件形式提供服务,由于无法感知外部业务在哪用、怎么用,导致搜索测试一直沿用人工梳理场景,接口测试覆盖场景的方式。可通过人工去做,一是效率不高,二是场景覆盖不全。所以搜索的质量工作一直被如下问题所困扰:搜索对外提供了 171 个检索条件,不同条件的组合,会流转到不同代码分支。一旦改动公共层代码,不确定回归场景是否全面?若回归场景覆盖不全,如何自动识别未覆盖的场景?识别到未覆盖场景,如何自动转化成场景用例?转成场景用例,如何快速实现自动化?基于上述问题,实践了一套基于流量的质量保障方案。二 搜索质量保障方案2.1 整体保障方案目标:借助流量区分活跃和非活跃代码,针对活跃代码,使用场景计算,自动识别和构建场景用例。针对非活跃代码,通过人工覆盖,补齐场景用例。接下来分别介绍:活跃代码保障策略,非活跃代码保障策略,自动回归策略。2.2 活跃代码保障2.2.1 保障策略核心思想:借鉴流量录制回放的思路,通过采集 Dubbo 调用日志,清洗出场景数据,针对场景数据进行计算,生成场景用例。策略包含 3 个节点:日志采集节点外部应用通过 Dubbo 调用搜索,搜索会输出一条日志,日志内容包含入参等信息。数据清洗节点此节点会根据指定格式清洗 Dubbo 日志,生成场景数据。场景计算节点此节点是整个策略中最核心的节点,主要包含 3 块功能:1)入参模板化;2)生成模板指纹;3)根据指纹对流量去重。接下来详解实现方式。2.2.2 场景计算入参模板化外部应用传给搜索的入参是一个 JSON(图1到图2),搜索会把 JSON 转化成 ES 的查询语句(图2到图3),只要捕获业务传入多少种入参(图2),就能统计出有多少种搜索场景。入参模板化方式有2种 :按字段方式生成模板// 仅供说明,非真实业务字段搜索条件:{ "bussinessScope": "", "status": true, "keywords": "打印机"}生成的模板:{ "bussinessScope": "@", "status": @, "keywords": "@"}上述示例对 bussinessScope、status、keywords 三个字段进行限定查询,类似 MySQL 的 where bussinessScope='' and status=true and keywords='打印机'。只要查询字段相同,无论值怎么变,对搜索来说都是一类查询。按字段方式生成模板,只需替换掉 value,保留 JSON 骨架即可。按字段和值的方式生成模板// 仅供说明,非真实业务字段如上图所示:查询已上架的黑色数据线,搜索条件:{ "attribute": "颜色:黑色", "status": true, "keywords": "数据线" }生成的模板:{ "attribute": "颜色:黑色", "status": @, "keywords": "@"}上述示例对 attribute、status、keywords 字段进行限定查询,还需根据 attribute 的值进行数据匹配。针对有业务含义的搜索条件,需要保留对应的 value 值。生成具有业务含义的 JSON 骨架。生成模板指纹模板生成后,会根据模板算 MD5,生成唯一指纹。为什么要生成唯一指纹?因为搜索日均调用百万+,里面包含了大量重复查询。为了快速识别出重复查询,本方案会对每一个模板生成指纹,只要指纹相同,就属于一类查询。// 仅供说明,非真实业务字段描述:查询已上架的打印机搜索条件:{ "status": true, "keywords": "打印机"}生成的模板:{ "status": @, "keywords": "@" }模板指纹:D8AD32393C65D62C8658A9D699A8C190去重采集到新流量,生成新指纹,新指纹与已有指纹进行匹配,若相同则跳过。通过指纹匹配,相同指纹的搜索会被归为一类(如下图示例)。这样既能快速发现新场景,又能识别出重复流量。// 仅供说明,非真实业务字段描述:查询已上架的打印机搜索条件1:{ "status": true, "keywords": "打印机"}生成的模板1:{ "status": @, "keywords": "@" }模板指纹1:D8AD32393C65D62C8658A9D699A8C190////////////////////////////////////////////描述:查询已上架的三星手机搜索条件2:{ "status": true, "keywords": "三星手机" }生成的模板2:{ "status": @, "keywords": "@" }模板指纹2:D8AD32393C65D62C8658A9D699A8C190模板1和模板2生成的指纹是一致的,通过对每一个模板的指纹进行对比,就能识别出相同搜索条件。流量计算产出的结果基于搜索现有流量,通过场景计算,自动生成线上P1场景用例 618 条,P2场景用例 516 条,P3场景用例 58 条,P4场景用例 161 条,总计 1353 条。2.3 非活跃代码保障2.3.1 保障策略流量覆盖不到的代码是非活跃代码,保障策略采用人工覆盖。搜索的非活跃代码主要有:1)开关;2)异常场景;3)未使用的方法。分别通过如下方式保障:开关,打开和关闭开关,人工调用接口,形成用例。异常场景,通过阅读代码,人工构造参数,形成用例。2.4 自动回归通过流量和人工方式构建了场景用例,就得让用例产生价值。产生价值的方式是让用例自动“活”起来。搜索自动回归的流程如下,重点在:「预期结果池」和「校验规则」的建设。2.4.1 预期结果池目的:同一查询条件,一定命中相同预期结果 优化前:固定关键字即时搜索。优化后:测试用例首次执行的结果,自动复制到预期结果池,非首次执行将查询预期结果池。为什么要建立预期结果池?原因1:线上同一个搜索条件,间隔一段时间后再次搜索,存在返回结果不相同的情况。造成该情况的原因:用户操作或定时任务导致状态变更。如:A条件,第一次搜索返回 3 个商品 A、B、C,一段时间后,商品 B 下架。相同条件二次搜索返回 A、C、D。动态的预期结果不能很好的做校验,为了消除变动带来的影响,所以建立预期结果池。原因2:线上索引数据 1亿+,若每条用例执行都扫 1亿+的数据,易产生慢SQL。预期结果池是独立索引,数据量几十万,相比查线上索引,速度快且不易产生慢SQL。预期结果池里数据的新增和失效新增数据:用例库新增一条场景用例,首次执行会查询线上索引,同时把搜索结果复制到预期结果池。当用例第二次查询,自动路由到预期结果池。失效数据:逻辑变更测试通过,删除原有数据,重新走新增数据流程。2.4.2 校验规则目的:根据使用场景,建立不同的校验规则。 优化前:自动化脚本里硬编码校验点。优化后:脚本与用例、校验规则解耦,根据使用场景,建立不同的校验规则。当前自动化落地在2个场景:接口测试、重构测试,分别建立了2套校验规则。接口测试规则校验重点:准确性。分为:总数准确和字段准确。总数准确:结合预期结果池,对比预期总数与实际总数。用例库新增一条场景用例,首次执行会查询线上索引,记录搜索结果总数(预期结果),同时把搜索结果复制到预期结果池。当用例第二次执行,自动路由到预期结果池。若二次搜索结果总数不一致,说明代码逻辑存在问题。字段准确:按字段维度进行校验。比如:校验区域字段,校验内容:「区域=」。会校验每一个返回结果的区域字段是否等于,或者包含。重构测试规则校验重点:全量对比返回结果和结果顺序。即同一搜索条件,新老接口返回值和返回顺序必须强一致。结果:沉淀2套场景校验规则,总计 37 个。其中接口测试规则 36 个(8个P1场景规则,19个P2场景规则,8个P3场景规则,1个P4场景规则),重构测试规则1个。三 保障方案在项目中的落地23年搜索代码将整体重构,要求测试人员对全场景进行保障。上半年分别进行了2次重构工作,内容如下:改动点以业务Id 作为分表键,数据分表存储。4个P2服务重构。风险点路由逻辑。路由出错,将导致搜索结果为空。业务逻辑。场景覆盖不全,将导致搜索结果不准确。质量保障的挑战全场景覆盖,人工回归成本高。服务重构前后,同一搜索条件,返回结果和结果顺序必须强一致,采用人工对比既痛苦又容易漏测。保障方案场景覆盖:采集 Dubbo 调用日志,清洗出场景数据,针对场景数据进行场景计算,最终生成场景用例。用例执行:自动执行用例,自动校验返回结果。结果预发环境,自动构建基础服务测试用例 4128 条,协议服务测试用例 6322 条,全量服务测试用例 4174条。自动化发现Bug:7例。剖析其中 1 例Bug,阐述人工测试,会产生的漏测点。该Bug发现于搜索重构项目,使用重构校验规则(全量对比返回结果,以及结果顺序)。Bug描述:搜索结果顺序不一致,导致对比失败 Bug根因:老索引的id字段是 long 类型(左图),新索引的id字段是 keyword 类型(右图),字段类型变更,引发字段排序变化易漏测点:在海量数据对比时,容易忽视顺序变化引发的问题,继而发生漏测。因为新老接口都返回相同数据,仅商品位置发生了变化。业务影响:上游业务搜索出商品,并按商品id排序,然后放到定时任务里执行。当商品位置变化,会造成已执行过的商品被重复执行,导致任务报错。四 未来规划线下环境使用流量录制回放系统。探索录制回放(mock形式)与本方案(真实调用)的相互结合。探索基于代码覆盖率的场景覆盖。
|
|