一次推荐系统线上事故的排查与修复经历分享

ProLightsfx 2024-11-4 332 11/4

这是2020年6月29日在另外一个平台写的文章,记录笔者在推荐系统开发工作中的第二年发生的一次线上事故。

虽然算不上有分级的重大事故,但依然是一次让人惊心动魄的事故。

现在回过头去看,新手工程师遇上一次线上事故之后,可以快速成熟起来。

一、现象:

2020年623端午节专题,突然发现所有sku都已经下架或者卖完的spu被曝光出来。

 

二、背景:

spu就是俗称的“款”;sku就是商品的“件”。 spu是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。 通俗点讲,属性值、特性相同的商品就可以称为一个spu。

一次推荐系统线上事故的排查与修复经历分享

在推荐系统这边是对于spu粒度进行逻辑处理的,但是后台和大数据那边是同时管理spu和sku粒度的,主要还是sku粒度。此时有三个case:

1、如果是spu下架那么ok,推荐这边不会曝光

2、如果sku全部下架,spu的状态依然是上架状态,但对于推荐场景这样的spu是不应当被正常曝光的。

3、如果sku全部上架,但是没有库存,spu的状态依然是上架状态,对于推荐场景,这样的spu是不应当被正常曝光的。

4、综合2和3,部分sku下架同时所有上架中的sku的库存都是0,spu的状态依然是上架状态,对于推荐来说这样的spu是不应当被正常曝光的。

因此我们是通过监听消息队列获取sku和spu的状态变化,两个消息队列,分别监听sku表和spu表的变化,有更新就会把这条消息写过来。对于spu的状态监听,即上面所述的case1,只要正常的入库即可。但对于sku的监听,由于推荐侧是不处理sku只关心spu的,所以此时根据sku查出spuid,然后查后台的即可,实时查出该sku所属spu下的所有sku的状态和库存,然后计算出一个“xx基于所有sku的spu状态”入特征正排。

 

三、历程:

1、2020年6月23日,下午上了xx端午节专题,但是傍晚发现好多spu无法展示,直观原因是很多sku状态没有正常入库,按照之前的解法,我提议改成如果读不到这个状态就不过滤。然后出现了新case,部分没有库存或者sku被下架但spu没有下架的spu被正常的曝光了。

此处临时方案存在至少三个问题,一、没有找到问题的根本原因就上了临时方案,对于为什么很多sku状态没有正常入库,有很多个原因,“延迟”或者“查库存和status”或者“入dcache”失败了(后来查明是cmq堵了)。 二、临时方案有问题,引入了新的问题 三、所谓的“读不到这个状态就忽略这个状态”是错误的解决问题方式,纯粹是打了一个后患无穷的补丁。

2、2020年6月23日,晚上,由于使用了错误了临时方案,延后了找到根本原因的时间,浪费了解决问题的时间。

通过几个服务的日志发现,对于那几个case的spuid并没有“查库存和status”或者“入dcache”失败日志,甚至没有从消息队列读到消息的日志,然后看看消息队列的监控,发现生产者出了异常,总共几十万sku却生产了了四百万的消息。

此时我的解法是扩容节点和go程数量上限,来提高消费速度,可惜“查库存和status”依赖的是一个基于查sql的后台服务。我依然使用了鲁莽的解决方案,扩容上下游节点,加快消费。然而可叹基于sql的服务顶不住这么高的qps。然后我提出了先开放上面的“读不到这个状态就忽略这个状态”同时加上黑名单来过滤不该出现的spu。

此处临时方案存在至少二个问题,一、对基于查sql的后台服务以前没有直观的了解或者经验,只是知道并发量瓶颈很低,但并没有特别直观的认识,因此根本就不应当使用扩容上下游节点加快消费方案。二、这个加黑名单覆盖一个bug,然后引入一个bug,因为当时考虑的很局部不全面,纯粹考虑了当时使得异常曝光的spu不在这个专题页曝光,但之后如果商家又补充了库存或者上架spu,那么这个spu就被我的黑名单封死了,无解。

3、2020年6月23日,近凌晨,找到了根本原因,之前我们推荐侧是监听的后台的主库sku表,上周切换成了从库,有定时把主库全量同步到从库的逻辑,导致生产者想消息队列写入了大量的消息,生产的速度远大于消费,最终消费队列堵塞非常严重。与大风哥讨论后决定先清空消息队列,然后导一遍全量的几十万sku。腾讯云cmq没有找到清除功能,由于此cmq的生产者写topic,消费者是消费队列监控topic,消费组监控消费队列,因此申请了新的消费队列监听之前的topic,忽略几百万的堆积消息。

4、2020年6月24日,早晨,由于依然有很多请求“查库存和status”失败,故使用工具,基于db从库sku状态表和库存表,直接计算出“xx基于所有sku的spu状态”,局部快速重刷,写入dcache。大风哥临时优化了查询接口作为临时方案,后台长期方案端午节后实施。

 

四、解决方案:

1、短期:首先清空消息队列,fix导致消息队列暴增的bug。基于db从库sku状态表和库存表,直接计算出“xx基于所有sku的spu状态”,局部/全量快速重刷。(省掉在线查sku状态和库存的网络耗时)

2、长期:修改消息同步机制,只订阅库存从0变非0、从非0变0消息和spu/sku上下架消息,以加速状态同步。或将辅以定时从刷。

3、长期:继续完善监控和日志,探寻真正的心中有数,尽在掌控中。

 

五、总结:

1、要考虑本次临时的修改对整体流程的影响,要有整体观念,不能为了解决局部问题,而贸然改动整体流程。

2、遇到问题要先找到根本原因,再尝试解决,而不是先用不成熟的短期方案快速解决并同时排查根本原因,因为这样很可能会引入新的问题,使得问题的排查变的困难,且导致找到根本原因的时间点延后。

3、不必急于求成,遇到问题多思考长期方案,而不是想着如何快速解决。比如xx的产品同学一言不合加个排序规则,一直打补丁。应当是请求他们思考和实验出一个完整并且稳定的人工排序规则,至少是属于短期来不再变的规则。

4、完善好监控和日志,做到尽早发现和解决问题,探寻真正的心中有数,尽在掌控中。

5、准备好各个环节的客户端或者小工具,如果出现问题,无法快速解决,可以快速矫正。

6、熟悉上下游的大致原理与设计,多思考,有利于当前模块/系统的优化,以及问题的排查。

7、当一个事项,自己虽然不是主要责任方,但对自己关系很大,如果这个事项出问题,自己将受到极大的损失,那么自己需要作出足够的保护。

 

六、鸣谢

感谢carbon、华明、shenquan指出我的问题,并给出建议!

 

 

本博所有文章均为博主原创,未经许可不得转载。

https://www.prolightsfxjh.com/article/recommend-system-online-bug-fix-20200629/

 

Thank you!

                                                                                                                                             ------from ProLightsfx

 

- THE END -

ProLightsfx

11月05日23:05

最后修改:2024年11月5日
2

本博所有文章均为博主原创,未经许可不得转载

共有 0 条评论