当前位置: 首页 > 科技观察

京东购物车性能如何提升30%

时间:2023-03-13 17:03:54 科技观察

01背景购物车面临的挑战:1)新业务:随着业务形态的丰富,购物车不断支持各种新业务,对外接口它的依赖也在增加;2)下沉:前端调用的部分接口下沉到购物车中心;3)前端:结算过程中很多业务都是前端加载到购物车,比如优惠券、京豆;4)扩容:改善购物的用户体验购物车中可容纳的物品数量不断增加;这些导致购物车依赖的RPC接口数量和寻呼次数增加。购物车作为交易流程的开端,本身就有大量的流量。在业务复杂的背景下,如何提升性能、保证用户体验成为购物车面临的一大挑战。02全异步改造方案可以通过增加服务器资源在一定程度上解决问题,但是会带来较大的成本开销,这也有违工匠精神。能否通过技术手段提升性能?通过分析,异步转换成为解决这一问题的有效手段。1)不同的RPC并行购物车依赖数十个接口,接口之间存在复杂的依赖关系。需要梳理接口之间的依赖关系,确定哪些可以并行化。然后把原来的代码拆分成RPC异步请求和结果处理两部分。根据依赖关系,让RPC最大程度的并行执行,减少结果处理阶段异步响应的等待时间,从而达到提升性能的目的。2)批量接口多页面并行购物车依赖接口多为批量接口,单次调用有数据量限制,需要将数据拆分到多个页面调用。那么多个分页也可以并行化。异步分页工具封装在transformation中,让业务层不知道分页逻辑。异步工具自动将超过接口上限的数据拆分成多个分页并行调用,提高单个接口的响应速度。3)底层采用JSF异步调用。异步调用基于JDRPC框架JSF。推荐1.7.5以上版本,支持CompletableFuture。03问题和解决异步改造的总体方案并不复杂,但是在实际实现过程中,遇到了很多细节问题:1)当异常重试需要细化同步调用时,超时重试调用.改成异步后重试会失败,因为调用时一般不会报错,需要在结果处理阶段得到异步响应超时后再重试。另外,当多个页面并行时,当一个页面请求超时时,只重试错误的页面。底层封装了分页调用,上层业务代码在获取数据时无法感知是哪个页面超时,所以异步调用时必须将场景信息保存在封装类中,一起返回给业务层。获取数据超时后,单独重试失败的分页。当异常发生时,并不是所有的情况都需要重试。当遇到限流等异常时,无法进行重试。底层工具需要自动过滤限流异常,当然也支持自定义规则。2)异步RPC监控比较复杂。底层的RPC耗时监控需要拆分成两部分。调用页面时记录为开始时间,异步结果到达后记录为结束时间。如果调用异常或者Get超时,需要将调用标记为失败。对于重试,还需要记录调用时间,正常调用和重试调用需要分开记录。除了监控RPC耗时,还需要监控结果处理阶段Get的等待时间。这个时间才是真正影响应用性能的时间。由于底层是寻呼调用,所以业务调用的次数和底层RPC调用的次数是不一样的。3)Paging异步结果不能合并,否则无法获取Provider信息异常的底层异步调用结果,必须通过包装类原样返回给上层。除了上面提到的需要单页重试之外,还有一个原因就是必须要保留异步结果。超时的Provider信息只有在寻呼超时后才能输出。这是因为Provider信息依赖于JSF框架的JSFCompletableFuture。如果结果在底层合并,信息就会丢失。4)每个页面的超时时间需要单独控制。如上图所示,在处理结果时,需要单独控制每个页面Get的超时时间,因为结果是顺序获取的。获取后续页面时,也应该统计前面页面的等待时间,这样整体获取结果的时间不超过单个页面的最大超时时间。计算公式如下:timeout=RPCtimeout>(当前时间-异步调用开始时间)?RPC超时-(当前时间-异步调用开始时间):05)分页平衡为了避免最后一页数据太少导致数据倾斜,需要将请求数据平均分到每一页,以最大化整个请求的性能.04收入转化完成后,购物车核心界面耗时减少30%,保证用户体验,节省大量服务器资源。后面添加新的RPC接口时,只要在调用拓扑的非关键路径上,对购物车的性能影响不大。另外,当容量增加时,除了少数接口不能被分页调用外,对性能的影响已经比较小了。