说一说微服务开发中的设计要点
一、背景
本文只讲述一些我们在实际开发和联调走过的弯路,在这里及时做个总结,所以不定期地更新。
当然,我们说的设计要点,都是针对重要的功能,切不可过度设计。
二、目标
- 1、业务对接的双方都可以洞悉整个流程的具体动向。
- 2、相互依赖的同时又低耦合。
三、设计要点
微服务团队中,我们往往是侧重于自己的业务实现,容易忽视其他团队,缺少全局思维。所以我们在做大型业务的开发设计,一定要有一个架构师对服务之间的协作做一个架构设计。
相信很多人都经常被其他团队的人追问,为什么两边的数据或状态不一致,当时的请求是怎么样的,为什么还没回调过来,等等一系列问题随之而来。
往往最后会抛出一句,你们服务最近有发版修改过这一块代码吗?
话外之音,问题不在他那,指向你这里。所以你得拿出证据,翻找日志和数据库,证明他是对的。
1、无处不在的任务
- 异步且耗时较长的操作
- 支持分布式,且可并行操作
2、跨服务调用的日志打印
- 打印当时的入参和出参,以及上下文信息
3、交互一定要形成闭环
- 调用方要对结果负责
- 回调外加上主动查询
- 业务对账
4、本地日志表替代分布式事务
- 在feign调用出错的情况下
- 非查询类且是重要的操作
- 要求被调用方的接口是幂等的
5、合理使用业务类型区分不同的业务
- 基础服务
- 可用于A/B测试
四、设计举例
4.1、无处不在的任务
有意思的是,我发现好多系统都定义了任务这么一个领域。或者说xx计划,其实也是一个“任务”。视频转换的请求,也可以看作是一个转换任务。延迟回调业务方,被看成是一个回调任务。明天上午9点要给一批私域用户发送sms短信,对于消息网关来说,就是一批发消息的任务。
要成为“任务”的前提是:该操作的结果是非实时的,允许一定的延迟。
而本文要讲的任务,可能还是耗时长的,可能是支持并发操作的。
调用方不仅可以查询任务的状态,且对已分发的任务进行重试。
下面举例说明:
-
任务分发平台,是一个接收各种转换任务的平台。视频转换工具会定期从任务分发平台拉取任务,然后自己按部就班地执行转换,待转换完成会回调任务分发平台,告知它已转换完成。
-
xx商城是一个销售电子课程的商品展示系统,商品是包括一系列的课程,多的时候有100堂课。在管理后台上架商品的时候,会调用课堂服务预先生成好100多堂课。对于课堂服务来说,生成100多堂课,就是接收了100多个“任务”。课堂服务可以把某个商品的一批课堂,分发到多个课堂Jvm节点去完成“任务”。等任务完成后,课堂服务回调给管理后台,告知它“任务”完成了。
-
延时任务回调,会让你很容易想到,这是一个任务。webhook回调,也很容易理解,无疑是一个任务。给一批目标用户发送通知短信,消息网关把这些请求当做任务,然后尝试不同的第三方短信渠道将之发送出去。这个很支付网关很像,第三方短信渠道给用户发送短信成功后,会调用消息网关,后者将更新消息状态和任务状态,最后回调业务方,告知业务方发送短信的任务已完成。
下面总结下,既然这些业务都抽象出了任务这么一个领域,那么有哪些共性呢?
- 任务的状态机
- 回调业务方,告知任务结果
- 任务的重试(xxl-job定期对失败状态的任务进行重试)
- 任务是比自身业务更上一层的抽象(比如一个任务对应消息发送记录是一对多的关系)
- 第一步都是新增任务,再把任务分发
- 更新自身业务实体,再更新任务的状态
4.2、跨服务调用的日志打印
前提是非查询类的请求!! 这是解决跨服务之间调用的问题排查,从日志可以给出直接证据。
- 如果你使用的feign,也建议你在调用处,把方法的入参和出参打印出来。
4.3、交互上的闭环
- 支付相关的接口,第一步是支付请求,拉起第三方支付界面,等待用户付款。第二步是等待第三方支付的回调,这一步是不定的。(可能因为网络等其他的问题,第三方支付回调不到;也可能程序自己的错误,导致回调处理发生异常)第三步,需要支付系统主动向第三方支付发起主动查询支付结果。 这当然就形成了支付的闭环,还建议你对接对账接口,隔天把前一天的支付记录和第三方支付给的对账单进行对账。有了这四步,会让你的支付数据变得更加安全,不等用户反馈,程序就已自动处理Ok或发现了bug然后认为介入处理。
如果你对上面的支付流程所有了解的话,相信会对你业务对接中怎么做到闭环,会有相当大的帮助。
-
调用方要对结果负责。订单系统作为调用方,在创建订单后,就会等待支付系统的回调,而支付系统在等待第三方支付的回调。这是在微服务开发中典型的链路变长。所以我们也建议支付系统提供根据订单号/支付流水号查询支付结果的接口,订单系统定期来查询待支付的订单。当然,支付系统还提供按时间段查询已支付的订单列表,供订单/财务系统的业务对账。
主动查询支付结果.png
业务对账.png