大报文之道:优化策略与实践

京东云开发者
• 阅读 29

写在前面

在做正常的需求开发时,当我们提供了一个接口或是调用别人接口时,我们需要考虑接口除了正常的逻辑处理外,还需要考虑接口能接收报文的上限,性能,响应时间等一系列非功能性需求。如果不注意这些问题,就可能在某一天的某个时刻收到一系列系统告警,严重者甚至导致系统不可用,引发线上事故。如涉及明细列表相关的接口中没考虑明细的上限,某一时刻上游下发了一个大明细从而可能就引发了上述的问题。这就是日常所说的大报文,其特点就是单次请求的数据量特别大,超出了系统正常的处理能力,需要耗费较长的时间才能处理完成。面对此类非功能性需求,在日常的开发中如何去避免和解决呢,今天主要带来的是主子模型下,明细行过大的处理。

一、识别大报文

大报文一般来源于批量接口或单个接口中入参为主子模型的接口,如果是消息队列,则是一次发送的消息中消息报文里发送了多条业务消息或是消息的报文结构也为主子模型的消息导致。

批量接口模型
Response<List<T>> method(List<T> list);

单个接口入参为主子模型
T method(OrderInfo orderInfo);

class OrderInfo{
   List<OrderDetailInfo> orderDetailInfoList;
}

class OrderDetailInfo{
}

对于批量接口或是消息队列里发送了多条业务消息的情况在这不做过多阐述,通常的逻辑是改为分批调用或分批发送消息就可以。但对于主子模型的报文,如果是正常的业务,则不能要求业务不要这么来下发,尤其是TOB类业务,因此需要从技术的角度加以解决。

二、解决大报文

这里主要讨论针对单个接口,里面的参数是主子模型的场景,因这类场景在日常的开发中最常见,用得很普遍。



大报文之道:优化策略与实践





第一点,先从AppA侧看可优化的点:

从调用方AppA的角度,如果传入的消息报文过大,导致AppB处理失败,那么对AppA来说也是失败,为了确保调用的成功,从AppA的角度看,对其可做如下一些优化。

首先,AppA在调用AppB时,可以和AppB约定接口的超时时间。超时后,AppA需要有重试机制,而对应的AppB需要保证接口执行的幂等性。在超时时间的设置上,如果大报文是个极少发生的场景,还可以考虑对超时时间进行动态设置,针对大报文的请求,把相应的超时时间适当加长,确保调用的成功。

其次,为了保证数据报文能快速达到AppB,AppA在请求调用AppB时,可以对报文进行压缩,确保网络传输能以最快的速度把数据报文发送到AppB。



大报文之道:优化策略与实践





第二点,从AppB侧看可优化的点:

而从AppB侧来看,需要从业务逻辑里分析耗时的逻辑,一般来说这个分析比较靠谱的是压测,搭建一套与线上环境类似的环境,模拟线上场景进行压测,压测出耗时的业务逻辑,针对耗时的业务逻辑进行优化。在这里由于我们的入参是主子模型的,按经验来讲,耗时点一般位于处理明细的逻辑里,所以可以重点关注明细处理相关逻辑。

首先,AppB在接收到请求后,对请求报文中的参数做基本的业务逻辑校验,校验通过后,为了能快速的响应调用方,可以把整个业务处理逻辑转入异步进行处理,确保调用方不超时。业务逻辑进入异步处理后还可能处理的时间比较耗时,此时可根据业务的时效性再进行处理。

其次,在AppB内,如果通过压测最后的耗时的确是在对明细的处理上,那么可以考虑对明细进行分批处理,不同的处理逻辑对于分批大小后得到的处理时长是不一样的,需要经过多轮调整参数的压测,找到适合自己业务逻辑的参数值。在我经历的大明细保存数据库实践中,不分批一次直接保存1万条明细到数据库与分批保存数据库及每批次的大小不同最终导致所有明细保存完数据库的时间也是有天壤之别的。



数据条数 保存方案 每次保存条数(条) 平均耗时(毫秒)
10000条 一次保存 10000 159005
10000条 分批保存 200 15363
10000条 分批保存 500 18720

再次,在确定了耗时的业务逻辑后,针对耗时的业务逻辑可以启用多线程处理。在使用多线程时,核心线程数的设置建议与CPU的核数相同,确保有较好的性能输出。在本文所述的此类场景中,用到了多线程就需要对批量的明细进行分批,结合上面说的不同的批次大小会有不同的性能表现,所以设置的参数建议还是通过压测获取,确保参数的最优。



大报文之道:优化策略与实践



还是刚才保存10000条明细进数据库的案例,在使用多线程并结合分批保存的方案后,在相同硬件及网络条件,单次保存的耗时降低至1秒左右,最终所有明细保存完成的总耗时在10秒左右,此时应用的压力有所上升,但数据库的压力几乎没什么变化。



数据条数 保存方案 每次保存条数(条) 单次平均耗时(毫秒) 总耗时(毫秒)
10000条 分批+多线程保存 100 1103 10184

三、经验沉淀

在进行大报文优化时,没有一个通用可行的方法能解决各类问题,本文阐述的仅是在主子模型下,明细过大的一些可行方法及在实际中的实践。而在实际的开发中,结合具体的业务场景,大报文的处理会更加复杂,需要结合具体业务具体分析。但我们日常积累的分批,多线程,异步,调整超时时间等手段都可在解决大报文中发挥各自应有的作用,可结合具体场景进行多种技术手段的综合运用,最终把大报文场景消灭在上线前,确保生产环境的稳定、可靠。

点赞
收藏
评论区
推荐文章
把帆帆喂饱 把帆帆喂饱
1年前
登陆时间的优化
登陆时间的优化这是一个登陆的请求,在项目启动后首次调用,耗时近800ms,而第二次调用改接口时则只花费了29ms,性能有较大的提升空间。下面针对此问题进行一系列的优化。耗时排查项目启动后清空日志,然后调用接口,发现会创建一个dispatcherServle
Stella981 Stella981
2年前
Spring Cloud之Feign 转发请求头(header参数)
在做接口请求时,我们经常会在header头中增加一些鉴权信息,如token或jwt,那么在通过fegin从Aserver去调用Bserver的接口时,如果Bserver的接口需要header信息,我们需要将Asever获取的header转发到B上。解决方式我们需要实现Feign提供的一个接口RequestInterc
Wesley13 Wesley13
2年前
Java8并行http请求加快访问速度
背景1.通常我们在获取到一个list列表后需要一个挨着一个的进行遍历处理数据,如果每次处理都需要长时间操作,那整个流程下来时间就是每一次处理时间的总和。2.Java8的stream接口极大地减少了for循环写法的复杂性,stream提供了map/reduce/collect等一系列聚合接口,还支持并发操作:parallelStream。例子
Stella981 Stella981
2年前
Python 接口自动化测试
1\.接口基础知识1.1接口分类接口一般来说有两种,一种是程序内部的接口,一种是系统对外的接口。(1)webservice接口:走soap协议通过http传输,请求报文和返回报文都是xml格式的,我们在测试的时候都要通过工具才能进行调用,测试。(2)httpapi接口:走http协议,通过路径来区分
Caomeinico Caomeinico
2年前
华为交换机常见QinQ操作
1.配置基本QinQ:基本QinQ又称为普通QinQ,是基于接口方式实现的,接口开启基本QinQ功能后,设备会为该接口接收到的报文添加上本接口缺省VLAN的Tag;如果接收到的是已经带有VLANTag的报文,该报文就成为双Tag的报文;如果接收到的是不带VLANTag的报文,该报文就成为带有接口缺省VLANTag的报文。提供更多建站及源码交易信息请见GoodMai
Stella981 Stella981
2年前
SpringBoot(20)
  我们在写单元测试的时候,除了接口直接抛异常而导致该单元测试失败外,还有种是业务上的错误也代表着该单元测试失败。好比我们在测试接口的时候,  该接口返回是1代表成功,如果是0那就代表是失败的,这个时候可以考虑使用断言。  一、原理我们知道,我们可以通过断言来校验测试用例的返回值和实际期望值进行比较,以此来判断测试是否通过。那我们先来看下如果失败的情
浅谈服务接口的高可用设计
作为一个后端研发人员,开发服务接口是我正常不过的工作了,这些接口不管是面向前端HTTP或者是供其他服务RPC远程调用的,都绕不开一个共同的话题就是“高可用”,接口开发往往看似简单,但保证高可用这块实现起来却不并没有想想的那么容易,接下来我们就看一下,一个高可用的接口是该考虑哪些内容,同时文中有不足的欢迎批评指正。
存储接口测试简介与测试方法
接口测试原理是通过测试程序模拟客户端向服务器发送请求报文,服务端接收报文并处理后再把应答报文发送回客户端,客户端接收应答报文的过程测试接口目的就是保证接口调用的正确性和稳定性,测试内容概括为:功能、性能和安全,核心是持续集成
京东云开发者 京东云开发者
10个月前
消失的死锁:从 JSF 线程池满到 JVM 初始化原理剖析 | 京东云技术团队
在一次上线时,按照正常流程上线后,观察了线上报文、接口可用率十分钟以上,未出现异常情况,结果在上线一小时后突然收到jsf线程池耗尽的报警,并且该应用一共有30台机器,只有一台机器出现该问题,迅速下线该机器的jsf接口,恢复线上。然后开始排查问题。
京东云开发者 京东云开发者
3星期前
一次接口的性能优化之旅
一、引言在项目开发过程中,我们经常会遇到接口响应慢的问题。这不仅影响了用户体验,还可能降低了系统的吞吐量。为了提高接口性能,我们需要对整个系统进行全面的优化,包括代码层面、数据库、缓存、异步处理等方面。本文将分享一个接口性能优化之旅,希望能帮助大家掌握Pf