1、应用程序中包含微服务治理逻辑
在微服务架构中,服务间不再是在朴素的进程内通信,取而代之的是通过轻量级的网络协议进行通信。那么,如何找到服务提供方?如何超时重试?当存在多个服务提供方时如何实现负载均衡?许多复杂的微服务治理问题逐步涌现出来。
倘若上述问题都需要微服务本身通过代码去解决,这样的解决方案无疑会消耗开发人员的时间和精力。类似的问题在大部分的微服务场景中都会出现,显然也会带来更多的代码重复。
在分布式服务早期,许多互联网企业就经历过这一过程,微服务之间的调用是通过硬编码对方的服务地址来实现的。如果有多个地址,调用端往往会自己编写一个简单的负载均衡算法、接口路由策略等,配合一些超时重试功能来实现微服务间的调用。这种方式的扩展性很差,一旦服务提供方的实例进行扩缩容或地址变更,服务调用方就需要通过更新服务的提供方节点列表并重新发布服务来保证正常通信。而且当一个基础服务被多个调用方依赖时,变更将是一场灾难。
2、将微服务治理逻辑封装成SDK
硬编码的微服务治理方式有很大的弊端,比如重复的代码、额外的工作量,并且每个微服务的开发人员不同,对微服务治理的逻辑和理解也不同,导致微服务治理的方案也参差不齐,因此第一种微服务治理方式的效果并不理想。此时在各大互联网公司中逐步演化出了一种新型微服务治理方式。
第二种微服务治理方式是将微服务治理逻辑封装成SDK,开发人员使用统一的SDK或框架来实现服务发现、负载均衡、限流和熔断等微服务治理功能。一些微服务框架开始流行,这其中比较著名的当属Dubbo和Spring Cloud了。Dubbo和Spring Cloud都是优秀的微服务框架,配套组件功能齐全。由于局限于Java语言(Dubbo后来发布了Go版本,可以实现与Java版本的互相通信),很多其他语言的开发者抱怨跨语言的微服务治理成为盲区。
Nginx成为跨语言的微服务之间通信的首选,无成熟微服务治理框架的微服务之间或者跨语言的微服务之间使用HTTP这个应用最广泛的网络协议进行通信,通过域名访问并使用Nginx代理来做转发、负载均衡和健康检查。通过Nginx可以收集微服务之间调用的日志,并对日志做访问和调用分析。微服务的扩缩容等功能通过变更Nginx的配置来实现,这是现在很多互联网公司的做法。
3、将微服务治理逻辑独立到应用进程之外
第二种微服务治理方式虽然解决了重复代码和维护成本的问题,但还是有以下缺点。
- 对业务进程有侵入。虽然统一封装成了SDK,但微服务治理逻辑还是与业务代码在一个应用程序内,当SDK升级时,应用也需要发布更新。
- 存在跨语言问题。
- 虽然很多微服务治理框架号称开箱即用,但也有一定的接入和学习成本,每个开发人员学习和理解的程度不同,使用起来并不能达到理想的效果。
为了解决上述问题,诞生了一种新的方案:将微服务治理逻辑彻底从业务进程中剥离出来,这就是Sidecar模式。在Sidecar模式下,开发人员的业务代码进程和微服务治理进程是互相独立的,不需要耦合,并且与开发语言无关,业务应用的升级和治理逻辑的Sidecar升级互相不影响。尤其是在微服务改造过程中,原有的老旧系统不需要做任何更改,搭配Sidecar即可。
在微服务容器化的今天,Istio凭借Sidecar的无侵入式接入以及和Kubernetes相结合的特点迅速成为微服务治理的首选。
此外,Nginx作为一款由C++编写的高性能代理,也具有一定的Sidecar属性,但它在微服务治理方面的功能还是有些欠缺。例如,Nginx的访问日志仅记录请求到达Nginx和Nginx请求到达上游节点的情况,调用方的请求到达Nginx之前的访问情况并无记录,如果网络出现抖动,请求可能无法到达Nginx,或者从Nginx发出的请求无法到达上游服务,这时就无法判断客户端调用超时是因微服务的性能问题引起还是因网络问题引起。Nginx支持基于令牌桶的限速,但不支持灵活的限流和熔断机制等高级的服务治理功能。