自己的模块,常常要对接上下游,如何在上下游对接的过程中,保证正确性呢?
一般和上下游对接的有两种方式:
一:接口对接
在接口对接中,需要注意下面的点。
1,和上下游约定接口的功能是什么,要准确描述该接口要做哪些事情,什么情况下返回成功,什 么情况下返回失败。
在接口暴露的地方做好这些注释,
2,定义好接口中的参数的数据结构,确定参数中哪些是必传的,哪些是不必传的,他们的传值范围是什么?
在接口impl层面的第一件事情,先打印请求参数日志(可以写个aop按照类名+方法名打印日志)
紧接着第二件事就是按照约定的数据结构进行参数校验,对错误的参数请求做好拦截,防止他们捣乱系统,破坏数据。
第三,对于非必传参数,接口应该如何处理,也需要明确,这一点一般反应在该接口在不同的场景中使用。
3,明确返回值和错误信息:如果处理成功返回success。如果失败,不能仅仅返回失败就完事了,必须在返回信息明确的告知上下游是什么原因导致这次请求处理失败,是参数校验不通过,缺省哪些值?还是要操作的数据,在数据库中不存在?等等。
4,对接口进行单元测试:根据步骤1的注释,必须按照这些预期功能进行测试,如果预期提供的功能,在单元测试中都成功通过,那么说明该接口提供的功能是可靠的,可以放心的和上下游对接了。
一般来说,接口对接做好上面的四件事就足够了,但是还远远不够 !接口设计的时候还必须考虑以下事情:
a,请求是否要支持幂等,也就是说相同的请求来了(可能是多线程并发请求,也可能是重复请求),该接口如何定义自己的功能,这一般反应在增删改等接口。
比如,有个接口支持插入用户信息,那么相同的用户是成功插入,还是应该提示该用户已存在呢?假设要求手机号唯一,那么大部分的做法是,先检查手机号是否存在,然后写入数据库,这种处理方式是不能解决问题的,因为,当第一个线程检查还未写入,第二个线程来检查会发现记录不存在,最终导致产生两条手机号重复的数据,,因此在定义这样的接口时,要么上层加分布式锁,要么在关系型数据库中,对该表加上对应的唯一索引。
另外如果是让数据库来保证业务唯一性,那么还要分析,重复的请求,在代码执行中,是否节外生枝。
b,是否有分布式事务?比如该接口是一个扣减库存的接口,那么在和上下游对接的过程中,需要注意如何处理分布式事务。
c,如果在接口impl中,要调用上下游接口,那么一定要打印好入参和全部返回信息的日志,日志信息要便于理解,方便排查问题。
综上:一般来说,在利用接口实现上下游对接中,那么就差不多了。
二:消息对接
利用mq等中间件消息
消息对接和接口对接大部分都是相同的。
不同之处在于,消息处理完毕不会立刻返回上下游,此次消息的处理结果是什么。因此当前系统,必须对处理失败的消息,做好响应。
1,首先处理消息有个小技巧,接消息的类,不要进行进行任何业务逻辑处理,仅仅打印消息日志就好了。应该有单独的一个类的方法,来实现消息的处理。这样做的好处,在于把消息也看成一次普通的接口请求。所以设计消息的处理,大部分可以参照接口的设计。
2,对重要的消息,做好记录,后续可查,中间件上的消息一般保存7天,如果某天被告知前7天的某条数据处理有问题,如果没有记录,就不得而知了。
3,消息处理做好幂等,这里比较重点。
4,处理失败的消息,记录好失败的原因,根据业务判断是否需要进行重试。
如果做到以上,消息对接不会有太大的问题,但是还需要考虑以下事情:
a,消息是否需要延迟处理
b,消息是否需要按照顺序来处理
综上:一般来说,在利用消息实现上下游对接中,那么就差不多了。
当一个功能中,接口较多时,还要注意在和上下游对接中,需要梳理不同接口和消息
的请求时机,否则就会导致数据混乱。
重中之重是,一定要做好单元测试!!!
最后,记录点非技术的问题:
1,在和上下游对接中,要和同事搞好关系,在生产环境遇到问题不要甩锅,要及时帮忙排查产生 问题的原因和提供技术解决方案。
2,以自己负责的业务为中心,梳理好所有相关的功能,这样当出现问题时,才能第一时间察觉到是哪个环节出现问题了。