1、封装统一的http请求工具类
. 集成apache httpclient开源框架
. 集成okhttp开源框架
2、打印请求接口入参、出参、耗时日志(可以在请求工具类统一打印)
. 在请求工具类统一打印,例如:
public static void main(String[] args) {
//方式一:
long start = System.currentTimeMillis();
// todo 请求接口返回result结果
log.info("post json data finish!耗时:{}ms, url:{}, data:{},result:{}", (System.currentTimeMillis()-start),reqUrl, data, result);
//方式二:
Stopwatch stopwatch = Stopwatch.createStarted();
// todo 请求接口返回result结果
log.info("执行业务总耗时:{}", stopwatch.stop());
}
3、参数合法性校验(减少对下游无效的调用)
. 数据格式的校验(例如非空、合法性判断)
. 业务合法性的校验
4、接口设置超时时间(不同的业务场景设置不同的超时时间)
. http工具类提供配置的超时时间参数,供其他业务场景传递,另外不传递给一个默认的超时时间,禁止不设置超时间
. 评估超时时间,要结合业务,不能拍脑袋,比如可以根据接口监控,看一下P95、P99的响应时间,然后在这个基础上放大一点
5、接口调用失败是否需要重试以及重试次数要慎重(要考虑下游接口提供的能力,另外事务接口不要重试,否则容易多发)
. 事务类接口不要随便重试,如果下游没做好接口幂等容易超发,像活动的奖品发放。但是一定要有业务告警,通过人工接入的方式,进行补发处理
. 查询类接口的重试,也要慎重考虑,如果下游接口支持的QPS有限,重试放量,容易把下游的接口打垮,所以如果决定重试,要调研下游接口的并发能力,酌情处理
6、事务一致性保障(上下游确定唯一的ID字段、下游提供回查接口、本地事务消息表、job重试)
自身服务:
. 调用下游事务类的接口(例如新增或创建订单、修改订单),上游根据下游接口的要求构造该字段。
. 调用下游接口失败根据业务需要判断是否回滚其他的业务或者记录业务数据到本地事务消息表,然后启动一个job定时补偿数据。
. 管理后台提供一个事务消息表查询的功能,可以在界面上手工点击进行人工补偿数据
下游服务:
. 提供的接口定义一个唯一值的字段,接口做好幂等处理
. 提供一个根据唯一值的字段查询业务数据的接口,便于上游对账
7、接口实现熔断返回兜底值及降级(自动或手动降级,注意不管是哪种方式实现,都需要配置业务告警)
. 自动熔断实现方案。接入开源的Hystrix或sentinel框架,配置合理熔断的阀值(例如:1分钟接口100个报错,熔断30s),实现超时或接口报错自动熔断,同时跟业务商量给出一个默认的兜底值
例如调用大数据客群接口,如果第三方提供的客群接口大量报错或服务超时,为了保护我们自己的系统,框架自动熔断同时返回默认不命中的兜底值
. 手动熔断实现方案。接入开源的动态配置中心apollo或nacos,配置熔断开关,当收到大量业务告警,动态秒级关闭,恢复后打开开关。
8、多次调用改为单次批量调用
. for循环根据id调用外部接口改为单次批量根据id调用,减少多次网络io带来的时间消耗
. 要考虑单次批量调用参数的大小,比如单次传10个id参数,这个也不行,可能导致接口直接超时,所以要对参数进行分组切割批量调用,比如10个参数,1次传5个,分2次调用,代码如下:
public static void main(String[] args) {
List<Integer> totalList = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
List<List<Integer>> partitionList = Lists.partition(totalList, 5);
System.out.println(partitionList);
partitionList.forEach(vo->{
//todo 调用第三方
});
}
9、接口返回的数据考虑是否缓存(防止对下游接口造成流量冲击)
. 查询客户命中的客群标签,同一人一天内理论上都是不变的,可以使用redis缓存,但是过期时间不适合太长,因为同一个人使用系统的时间不长