一、先聊聊需求
说起这次优化,有点奇葩,从耗时12小时到1分钟,优化经历了三次,和自己纠结了N次,看看结果还算安慰。
1.故事背景
恰逢大促东风,不如顺势来个商品破盘,运营、技术、产品联手一搏提升商品的丰富度。那这次的问题就从这个需求开始了。。。
2.需求描述:快速提升商和品的数量,从现有的商品池中捞出符合规则的数据。
3.功能实现:功能很简单,就是后台通过定时JOB的方式将疑似商品表的数据进行状态更新。over~
二、再聊聊方案
1. 第一种方案(标签:单线程执行、无缓存、有三方依赖)
(1)方案图
- 疑似商品总数:180w+
- Page数(50条上限,后面会解释原因):3w+
- Thread池数:1
- 是否有缓存:无
(2)执行逻辑
类似的小任务也写过不少,自以为轻车熟路,方案也很顺手,顺手就是一坨代码:
step1:从ODPS表中将疑似商品数据同步到应用的DB表中,做好数据准备
step2:分页获取offer数据,每页必须按照50条数据来执行逻辑。之所以定死这个页数上线,是由于标第三方HSF的接口的限制,用过的童鞋都知道,性能上限每次最多传入50条Id。先忍一忍,继续实现功能。
step3:循环遍历每页,通过第三方接口check是否打上标。然后把已打上标的商品放到一个list集合中。
step4:将list里offer依次循环回写状态
至此coding结束,迫不及待的将任务Run起来。又看看表已凌晨1点多,算了,睡上一觉明天收割数据。早上醒来,蛋疼是事情发生了,才跑了100w的数据,并且一直在报超时。异常显示“HSF TimeOut:OfferQueryServiceException:xxxx”,很显然批量接口不行了,必须优化。
(3)执行结果
本次执行task处理offer数量180w+条,总耗时739分钟,虽然能顺利跑完,但已吐血。简单总结下~
本方案满足了三无条件:
- 无缓存
- 无多线程
- 无延时策略。
本方案暴露的问题:
- 第三方的接口依赖成为性能瓶颈,多频次的循环调用会造成应用的强依赖和性能瓶颈
- 本次处理的数据量还是比较大,单Thread方案肯定不合适,
- ODPS表同步DB每周才执行一次,数据的实时性比较弱,完全可以缓存调用offerQueryService的接口,提升性能
- hsf超时严重,需要增加sleep降低调用频次的时间间隔
2.第二种方案(标签:多线程执行、有缓存、有三方依赖)
(1)方案图
- 疑似offer总数:180w+
- Page数(50条上限,后面会解释原因):3w+
- Thread池数:6
- 是否有缓存:增加offer接口调用1小时的缓存
- 并发策略:根据线程池数量动态分配数数据的起止页,并发执行
(2)执行逻辑
按照方案一的暴漏问题,逐一优化:
- step1:增加线程和数据页数的动态分配策略
- step2:多个线程并发执行,并增加sleep降低访问依赖频率
- step3:增减读取offerQueryService的tair存储。
(3)执行结果
本次执行task处理offer数量180w+条,总耗时127分钟,时间提升82%,期间无任何异常抛出,终于可以静静的吃瓜了。但又想了想,是不是还有更好的思路可以解决这个问题呢:
- 能不能将时间控制在分钟级别?
- 能不能不依赖第三方接口?
- 能不能不用缓存降低数据丢失或未被命中的概率?
本方案也暴露一些问题:
- 始终在围绕解决方案一暴漏问题在优化,思路没有打开
- 最大的瓶颈还是依赖第三方接口,必须降级去掉
- tair已经做到常态化演练,申请空间又是MDB模式,数据丢失成为一种风险。
3.第三种方案(标签:嵌套SQL、无三方依赖、批量优化)
(1)方案图
- 疑似offer总数:180w+
- Page分页:不需要
- Thread池数:不要要
- 是否有缓存:不需要
(2)执行逻辑
从头开始理解需求,无非就是想把疑似商品找出来,然后回写状态。能不能找到替代调用三方接口的方案来验证结果。脑暴一番,果然有。。。
- step1:替换掉接口依赖,使用odps中的离线xxx表中的数据,然后同步到DB中。这不看起来比较麻烦,但一劳永逸,为后续的性能优化起到关键行作用,直接将时间降级至分钟级。
- step2:求交集,将DB表1和DB表2联合查询,结果即为已经完成升级的offer列表
- step3:优化update方法为批量更新,至此over
(3)执行结果
本次执行task处理offer数量180w+条,总耗时<<1分钟,时间提升100%,期间无任何异常抛出。
三、小结
回头想想这次优化的经历,总结有三点:
- 来一个需求先不要着急码代码,分析好场景和数据基础,然后选择最优的技术方案。避免后续的返工
- 思路方向很重要,往往很复杂的方案背后,换种思路会更爽
- 事情搞完后和自己纠结下,往往会有新的发现