这篇文章主要接4月3日的微服务网关和服务注册中心,在这篇文章里面谈到如果只启用了服务注册中心完全是可以实现去中心化的,然后对于需要前端APP或外部系统访问内部API接口场景,通过微服务网关一个重要功能是统一实现服务代理并保证内部微服务模块位置透明,那么在这种情况下是很难去中心化的。

 

这篇文章主要还是想谈如果仅仅是内部多个微服务模块间的接口服务集成,是否能够实现一种去中心化微服务网关,或者也可以理解为实现一种去中心化的轻量服务总线能力。要知道,在微服务模块间的接口服务调用中,涉及到安全,日志,路由,代理,监控,限流等能力,我们还是希望有一个统一的微服务网关来处理。

 

在前面的文章里面我们曾经谈到过,去中心化的一个核心思路就是在微服务架构实施过程中,结合容器化自动化部署过去,在微服务模块部署的时候,自动在容器里面同时部署相应的SDK代理包。这个SDK代理包将传统的服务网关能力下沉到微服务模块本地化容器中去实现和执行。

 

即使这样,我们仍然需要保留中心化的服务中心,本地的SDK服务代理包具备相应的缓存能力,即在服务注册中心宕机的时候仍然可以读取本地缓存信息进行服务地址获取和访问。

 

本地的SDK包是一个本地化的JAR包,我们可以在JAR包里面对Http Rest接口的访问和消费进一步封装,将其封装为本地API方法,同时在本地API方法中进行类似安全,日志等方面内容的拦截处理。在这种实现方法下,我们可以看下整个服务调用过程。

 

举例来说当前有考勤管理A和用户管理B两个微服务模块,考勤管理需要调用用户管理模块的查询用户Rest服务接口。在这种场景下,具体的实现过程如下:

 

1. 考勤管理模块A在自身项目中导入服务代理SDK包的内容。

2. A调用SDK包里面的QueryUserInfo接口方法

3. SDK包获取到调用请求后,调用服务注册中心,获取QueryUserInfo方法的Rest接口地址

4. SDK包发起对远程Rest接口方法的调用并返回结果

5. A模块对返回的结果进行处理。

 

在整个过程中还可以在SDK包中添加安全,日志,流控等各种拦截器插件实现进一步的控制和处理。基于这个基础流程,我们来看实际的服务网关的关键能力实现。

 

服务代理能力

 

考勤管理模块只能看到本地SDK包的查询用户方法,而看不到具体的远程调用地址,而远程调用地址是SDK包通过动态查询服务注册库获取到后,再发起的调用。也就是说在去中心化架构下,传统服务网关的服务代理层前置到了本地微服务模块容器中的SDK代理包。

 

负载均衡和路由转发能力

 

SDK包中本身也不存储具体的远程服务访问地址,而是告诉服务中心我们需要访问哪个服务,服务中心根据服务编码或名称返回具体服务的访问地址,如果一个服务在服务中心注册有多个可访问地址,那么服务中心就可以实现最简单的负载均衡能力。即实际的负载均衡在服务注册中心实现。

 

第二种方法是SDK包调用服务注册中心后,服务注册中心把所有可访问的服务地址全部返回给SDK包,由SDK包在进行负载均衡算法选择和路由。

 

可以看到第一种方法往往更好,因为一个接口服务往往有多个微服务模块都在消费和调用,第二种方法是无法真正做到完全的负载均衡的。但是第一种方法仍然存在问题就是会增加服务注册中心的计算负荷。

 

日志和监控能力

 

在这种架构下,本地的SDK包是完全可以拦截到具体的服务输入和服务输出信息的,而且在这种去中心化的架构下还可以做到对于A模块和B模块各自本地的SDK包分别拦截到服务的输入和输出,以方面后续的日志审计。在SDK包拦截到服务日志后,在这里需要通过另外一个JMS API接口,将日志信息通过异步消息的模式写入到JMS消息中间件中,然后再通过消息中间件对日志进行相关的持久化处理。

 

如果写JMS消息中间件报错,我们可以对异常信息直接写入到本地的磁盘文件中,在JMS消息中间件恢复后再重新写回到消息中间件中。

 

限流和流量控制

 

首先还是需要在服务注册中心设置相应的限流策略,然后将限流策略分发到本地的SDK包中,本地的SDK包对服务调用次数,时间等信息进行计算统计,并将计算统计信息仅缓存,同时对缓存的数据进行实时计算,当满足流量控制策略的时候,则对服务进行限流。

 

由于在服务提供的A模块和服务消费的B模块我们都部署了服务代理SDK包,因此也很容易实现类似服务总线的输入端限流和提供端限流的双向限流能力。

 

服务访问安全控制

 

如果一个服务没有进行授权,首先可以做到SDK包在获取服务地址信息的时候就返回安全校验不通过。

 

那我们再来看额外的服务访问控制场景,基础的需要做到的就是基于IP地址的服务访问控制,只有授权的IP地址才能够访问服务。在这里也是同样的道理,需要将IP访问控制策略信息下发到服务代理SDK包中。

 

同时在去中心化的架构下我们也很容易实现类似动态Token的访问安全控制,比如在A模块,我们完全可以在A模块发起调用的时候通过传递业务系统ID,日期,再传递一个计算出来的MD5码值到服务提供端。提供端根据通用的算法也计算MD5码值,只有当两个值匹配的时候才认为校验通过。

 

去中心化的架构下,可以看到仍然保留了中心化的服务注册中心,同时对于一些管控需要的基础配置元数据也需要在服务注册中心完成。对于各种配置元数据,我们需要实时下发到各个微服务模块。因此最好的做法技术在各个微服务模块都实现一个JMS消息订阅接口,通过消息发布订阅的模式实时下发消息