微服务之间的最佳调用方式( 三 )


另一种是其他微服务也关心的,是颗粒度比较粗的,这种事件会放到另外一个或几个stream中,被多个微服务使用,是用来做服务之间集成的 。这样做的好处是限制了事件的作用范围,减少了不相关事件对程序的干扰 。详见"Domain Events vs. Event Sourcing" 。
事件溯源出现已经很长时间了,虽然热度一直在上升(尤其是这两年),但总的来说非常缓慢,谈论的人不少,但生产环境使用的不多 。究其原因就是应为它对现在的体系结构颠覆太大,需要更改数据存储结构和程序的工作方式,还是有一定风险的 。
另外,微服务已经形成了一整套体系,从程序部署,服务发现与注册,到监控,服务韧性(Service Resilience),它们基本上都是针对RPC的,虽然也支持消息,但成熟度就差多了,因此有不少工作还是要自己来做 。
有意思的是Kafka一直在推动它作为事件驱动的工具,也取得了很大的成功 。但它却没有得到事件溯源圈内的认可 。
多数事件溯源都使用一个叫evenstore的开源Event Store,或是基于某个数据库的Event Store,只有比较少的人用Kafka做Event Store 。
但如果用Kafka实现事件通知就一点问题都没有 。总的来说,对大多数公司来讲事件溯源是有一定挑战的,应用时需要找到合适的场景 。如果你要尝试的话,可以先拿一个微服务试水 。
虽然现在事件驱动还有些生涩,但从长远来讲,还是很看好它的 。像其他全新的技术一样,事件溯源需要大规模的适用场景来推动 。例如容器技术就是因为微服务的流行和推动,才走向主流 。
事件溯源以前的适用场景只限于记账和源代码库,局限性较大 。区块链可能会成为它的下一个机遇,因为它用的也是事件溯源技术 。
另外AI今后会渗入到具体程序中,使程序具有学习功能 。而RPC模式注定没有自适应功能 。事件驱动本身就具有对事件进行反应的能力,这是自我学习的基础 。因此,这项技术长远来讲定会大放异彩,但短期内(3-5年)大概不会成为主流 。
RPC方式RPC的方式就是远程函数调用,像RESTFul,gRPC, DUBBO 都是这种方式 。它一般是同步的,可以马上得到结果 。在实际中,大多数应用都要求立刻得到结果,这时同步方式更有优势,代码也更简单 。
服务网关(API Gateway)熟悉微服务的人可能都知道服务网关(API Gateway) 。当UI需要调用很多微服务时,它需要了解每个服务的接口,这个工作量很大 。
于是就用服务网关创建了一个Facade,把几个微服务封装起来,这样UI就只调用服务网关就可以了,不需要去对付每一个微服务 。下面是API Gateway示例图:

微服务之间的最佳调用方式

文章插图
 
服务网关(API Gateway)不是为了解决微服务之间调用的紧耦合问题,它主要是为了简化客户端的工作 。其实它还可以用来降低函数之间的耦合度 。
有了API Gateway之后,一旦服务接口修改,你可能只需要修改API Gateway,而不必修改每个调用这个函数的客户端,这样就减少了程序的耦合性 。
服务调用可以借鉴API Gateway的思路来减少RPC调用的耦合度,例如把多个微服务组织起来形成一个完整功能的服务组合,并对外提供统一的服务接口 。这种想法跟上面的API Gateway有些相似,都是把服务集中起来提供粗颗粒(Coarse Granular)服务,而不是细颗粒的服务(Fine Granular) 。
但这样建立的服务组合可能只适合一个程序使用,没有多少共享价值 。因此如果有合适的场景就采用,否侧也不必强求 。虽然我们不能降低RPC服务之间的耦合度,却可以减少这种紧耦合带来的影响 。
降低紧耦合的影响什么是紧耦合的主要问题呢?就是客户端和服务端的升级不同步 。服务端总是先升级,客户端可能有很多,如果要求它们同时升级是不现实的 。它们有各自的部署时间表,一般都会选择在下一次部署时顺带升级 。
一般有两个办法可以解决这个问题:
同时支持多个版本:这个工作量比较大,因此大多数公司都不会采用这种方式 。
服务端向后兼容:这是更通用的方式 。例如你要加一个新功能或有些客户要求给原来的函数增加一个新的参数,但别的客户不需要这个参数 。这时你只好新建一个函数,跟原来的功能差不多,只是多了一个参数 。这样新旧客户的需求都能满足 。它的好处是向后兼容(当然这取决于你使用的协议) 。
它的坏处是当以后新的客户来了,看到两个差不多的函数就糊涂了,不知道该用那个 。而且时间越长越严重,你的服务端可能功能增加的不多,但相似的函数却越来越多,无法选择 。


推荐阅读