通讯标准
- 确定协议 Http/Https
- 确定参数传输格式 json/x-www-form-urlencoded/…
- 具体接口参数的数据类型(弱类型对接强类型语言时容易踩坑)
- 确定身份校验方式
- token
- 参数签名:单一Key、交换公钥
- 证书校验
- 确定响应结构(统一成功响应码等等)
异常处理
一般情况下,异常结构应该区分为三大类:
- RpcException:调用异常
- BusinessException:业务异常
- Exception:其他程序异常
对于不同的第三方服务,什么情况下对应什么异常,可能会有不同的划分标准,一般情况下有以下规则:
- Http StatusCode == 500 时为RpcException
- 业务响应码 != 统一成功响应码 时为BusinessException
- 其他异常不作归类
一致性
对于涉及到支付、退款等有下单概念的接口或涉及到状态问题时,则需要考虑到一致性的问题。一般情况下有以下要求(第三方服务也叫上游):
- 上游有的数据,本地一定要有
- 上游状态与本地每条数据的状态相同 (或者状态可以相对来说一一映射)
由于第三方服务一般不受控,这里说的一致性往往只能是最终一致性
事务发起
- 确定接口当中的唯一标识是哪个字段,通常是requestNo,这个字段的值将上游数据和本地数据进行一一对应,上游存在的requestNo,本地必须存在
- 划分状态:
- PENDING:本地数据已创建,未发起接口请求
- UNCONFIRMED:本地数据已创建,不知道接口请求发起了没有,等待回查
- PROCESSING:接口请求已发起,并且上游已响应,等待回查确认最终状态
- SUCCESS:终态,业务已成功
- FAIL:终态,业务已失败
- DEAD:终态,本地数据已创建,接口死活请求不了,上游也查不到对应数据,不要了,根据实际情况也可以归类为FAIL
这里的流程可以概述为:
- 发起上游接口前,生成一个全局唯一的requestNo,该条数据的状态为PENDING,并且入库提交。
- 请求上游接口没有异常的情况下:
- 如果允许的话,同步处理状态,更新状态入库。
- 否则,直接更新为PROCESSING,表示请求上游已成功,等待进一步确认状态。
- 请求上游接口遇到RpcException,更新为PROCESSING,表示请求上游已成功,等待进一步确认状态。
- 请求上游接口遇到BusinessException,更新为FAIL,表示请求上游已成功,等待进一步确认状态。(这里可能根据不同的业务返回码,处理为PROCESSING,等待进一步确认)
- 处理过程中遇到其他Exception,更新为UNCONFIRMED,不能确定是否已请求上游,等待进一步确认状态,这里可以概述为本地事务处理失败,即保存到本地数据库时失败。
如果你对上游的信任度较低,可以直接将PROCESSING状态也合并为UNCONFIRMED通一由事务回查处理
下面用一段伪代码来描述接口调用的流程:
1 | 复制代码// 开启本地事务 |
事务回查(重试)
经过上面的流程,数据会剩下UNCONFIRMED 和 PROCESSING 两种状态,因此对这两种状态进行进一步确认,保证数据到达终态。
事务回查有几种实现方式:
- 利用定时器扫描数据库状态为UNCONFIRMED或PROCESSING的数据
- 保证数据库有索引
- 如果requestNo字段也有索引,则可利用覆盖索引机制缩短查询时间,查询上游数据状态一般只需要requestNo
- 把UNCONFIRMED或PROCESSING数据的requestNo存入Redis,再利用定时器处理
- 利用队列,将UNCONFIRMED 和 PROCESSING塞在回查队列中
实际上,假如你的rpc请求不需同步返回出去,推荐使用具有事务机制的消息队列,否则利用队列方案需要考虑复杂度的上升程度
那么UNCONFIRMED 和 PROCESSING分别怎么处理呢
- 对应PROCESSING,处理思路很简单,因为这种状态上游肯定能够返回对应的状态(实际上有的上游并不一定),只要查询到对应状态更新为SUCCESS或FAIL即可
- 对应UNCONFIRMED需要区分上游数据不存在的情况,也就是说上面的事务发起流程当中,上游没有收到我们的请求,那么我们需要根据业务情况进行处理:
+ 重新发起这个请求(要确保上游接口是否幂等,否则要自己处理)
+ 更新为DEAD,抛弃这个请求如果上游存在该记录,则视为PROCESSING情况处理即可
如果你的上游提供异步处理通知,则可按照同样的思路完成事务回查这个阶段
总结与思考
本文简单总结了一下对接第三方服务接口时需要考虑的几个问题:通讯标准、异常处理、一致性,实际处理时通常会分为RPC层与Service层来处理,RPC封装通讯标准、异常处理的问题,Service层处理一致性问题。最后留下了一个问题还未进行讨论,在入库前、重新发起请求前、异步通知时都需要考虑幂等的问题,下一篇文章针对幂等再来分享几种处理方案吧。
本文转载自: 掘金