计算机在互联网中的应用,主要就是对于业务数据的存储,加工,以及展示。存储对应着大数据,加工对应着Web服务,至于展示则对应着包括H5,PC,iPhone&Android在内的各端开发

就单单针对于Web服务来说,它是复杂业务的主要承担者,因为互联网的飞快发展,所以Web服务也发展的很快,从单点到集群到Microservices再到ServerLess和ServerMesh。但无论怎么发展,都离不开单一职责——将服务按照业务职责细分,每个服务对应一个业务节点,从而实现解耦合的能力

那么,对于Microservice中的一个节点,它在完成对应的业务逻辑的过程中,从技术的层面讲,它的一个重要的作用就是承上启下,而承上启下的核心,则是与上下游之间的交互

一. 协议和约定

在交互过程中,首先就需要对交互的规范进行确定,譬如交互协议,状态码,返回值等case

异常约定

理论上来讲,下游的服务提供方是不能给上游的消费者抛出异常的,这样会不仅会使得消费者付出额外的代价去捕获异常,同时还需要额外约定各种异常case,增加交互和沟通成本

但是在RPC调用中,消费者却必须关于超时异常,这种异常是服务提供方难以干预和阻止的问题。所以,在RPC调用的过程中,消费者只需要捕获超时异常,然后进行重试。而其他问题,则一律通过返回值来约定并解决

返回值约定

一般来说,交互的返回值会设置四个字段,分别是:success, code, msg,data

  1. success:标志着本次交互是否成功,一般会有true和false两种结果
  2. code:标志着本次交互的响应码,一般在success=false的时候起作用。常见的code范围有:非法参数,状态异常,并发异常,系统异常等
  3. msg:标志着本次交互的解释,一般在success=false时候起作用,用于对code详情的解释说明
  4. data:标志着本次交互的具体数据

幂等约定

幂等的概念来源于数学,指的是在其他条件不变下,无论消费者请求多少次,对下游服务造成的影响以及获得的服务结果都保持不变。

如:对于HTTP的Restful协议来说,get方法应该实现幂等

对于修改或者创建操作来说,一定要保证provider的系统数据不会因为消费者的多次请求而改变,同时返回值也尽量和第一次保持相同(具体是否相同可以根据双方协定)。一般来说,有以下两种情况:

  1. 本次交互导致provider开始创建单据。如果第一次交互使得单据创建成功,那么第二次同样的请求过来,provider应该不做任何处理,直接返回
  2. 本次交互推进了provider之前创建单据的状态。那么当第二次同样的请求过来是,provider应该检查本地单据的状态,如果单据状态已经流转,也应该不做任何处理,直接返回

重试约定

在交互的过程中,当发生异常或者下游提供方出问题时,会导致本次交互不能生效,那么就需要有定时任务来进行重试,一般的重试case如下:

  1. 下游抛出超时异常
  2. 下游发生并发且本次请求被丢弃
  3. 下游服务不可用

二. 调度方案

交互的调度也是比较重要的。在基础的微服务操作中,常见的调度有两种,一种是实时的同步调度,一种是非实时的异步消息调度

同步与异步

这里的同步交互跟我们平时说的同步异步,阻塞非阻塞,还是有些区别的。在本文中,同步交互是对于provider来说的,当provider收到一个请求之后,它会立刻处理,之后立刻返回结果给调用者。常见的同步交互一般是RPC,当然,HTTP也属于同步交互的一种(不包括长链接)

而异步交互指的是基于MQ的、以消息驱动的交互模型。常见的交互链路通常是:上游服务给MQ发送一条消息,然后MQ再将消息转发给下游,下游进行处理,处理完毕后,下游可以选择发送一条消息给MQ,MQ再将消息转发给消费该条消息的其他服务。可以看出,基于MQ的异步交互将上下游完全解耦,这种交互相比于同步交互,它的时延是比较高的,一般用来推动上下游状态机的运转

实时与定时

所谓的实时交互,是和定时交互相对来说的。实时交互就是即刻发生的,而定时交互则是给定一个时间点或者时间短,才会去触发一次交互。定时交互通常会使用cron表达式来表明定时执行的时间点

在日常的业务场景中,会经常用到定时调度。譬如,定时重试失败的调度,定时进行文件的更新,定时刷新缓存等等

PS:没有说到docker和k8s,也没有讲到大数据和存储(Hadoop,Flink,Spark,Hbase)相关的东西,同时对各个部分也剖析的不够深刻,不断更新中….