建设微服务API网关的一些实践

原文地址:https://fredal.xin/build-api-gateway
原文作者:fredal的博客
 
随着这些年微服务的流行 , API网关已经成为微服务架构中不可或缺的一环 。一方面它承担着服务对外的唯一门户 , 一方面它提取了许多应用的共性功能 。
整体架构

建设微服务API网关的一些实践

文章插图
【建设微服务API网关的一些实践】 
我们的Api网关目前的架构如上所示 , 可以看到Api网关处于一个什么位置 , 往上承接所有的南北流量 , 往下会分发流量到微服务应用或者BFF聚合应用 , 在BFF规范化之前我们仍然将其视为一个普通微服务应用 。
目前Api网关实现的功能包括请求分发、条件路由、Api管理、限流隔离、熔断降级、安全策略、监控报警以及调用链追踪等 。
建设微服务API网关的一些实践

文章插图
 
我们的Api网关基于RxNetty开发 , 整个流程是异步响应式的 , 可以达到较高的单机并发 。基于少造轮子的理念 , Api网关的大部分功能都是结合现有平台实现 。包括请求分发、条件路由基于微服务框架 , 限流隔离、熔断降级基于稳定性平台 , 监控报警基于监控平台等 , 安全策略基于大数据分析平台等 。注册中心与配置中心则分别负责服务注册核心信息与第三方配置信息的下发 。
请求分发请求的分发路由应该是一个网关最基本的功能 , 在绝大多数基于Nginx开发的网关上 , 这部分功能通常基于动态更新代理的upstream 。而在我们的实现中 , 认为网关是一个只订阅不注册的微服务而已 , 区别是微服务应用发起rpc调用指定了调用服务 , 而网关接收请求分发只有url信息 。这可以通过简单的改造来复用已有微服务框架的服务发现功能 。
经过一系列url规范化行动后 , 我们的url目前不同的应用都会采取不同的前缀 , 同时这个前缀信息会随着应用注册到注册中心 。这样网关进行服务发现时会给不同的url前缀以及微服务应用构建不同的namespace对象 , 在进行请求匹配时候只需根据url前缀选取到对应的namespace即可匹配到对应微服务应用 , 后续就是现有微服务框架sdk的功能:路由、负载均衡直至完成整个调用 。
建设微服务API网关的一些实践

文章插图
 
这里还涉及到另一个问题 , 网关选择服务发现的应用是哪些?即我需要拉取哪些应用信息以构建namespace?我们这里对服务发现对象进行了管理 , 用户可在管控平台上控制微服务应用在网关层的上下线 , 这会通过我们的配置中心推送到网关并进行一次热更新 , 刷新内存缓存 , 这样就做到了请求分发服务的动态增减 。
建设微服务API网关的一些实践

文章插图
 
条件路由条件路由意味着可以对具有特定内容(或者一定流量比例)的请求进行筛选并分发到特定实例组上 , 是实现灰度发布、蓝绿发布、ABTest等功能的基础 。
同样的 , 在基于nginx开发的网关中 , 一般是维护多套upstream列表 , 然后通过某种策略将不同请求代理到不同upstream 。
在我们的实现中 , 条件路由依然是复用现有的微服务框架 , 避免重复造轮子 。每个应用都可以根据一些规则创建一些分组 , 分组中有若干实例 。在网关进行服务发现初始化时会给每个应用创建Invoker代理对象 , Invoker内会根据不同的分组创建不同的Space空间 , 请求调用时会对这些Space空间进行规则匹配 , 从而决定是否路由到特定分组上 。整个过程都是微服务框架完成的 , 没有额外的开发工作 。
目前我们支持按照特定内容或者流量比例两种方式进行请求来源规则的匹配 , 特定内容包括http请求的header、attribute等等 。我们目前的实例分组主要是根据"版本"这个标来区分的 , 所以分配规则主要是支持"版本"维度 , 未来考虑支持到k8s的pod label 。
Api管理Api网关为什么前面要有Api几个字 , 我觉得其中一个很重要的原因就是具有Api管理功能 。当我们的大部分应用还是裸连网关 , 而不是经过BFF聚合时 , 我们有必要对每个api接口都进行管理 , 以区分哪些是微服务间内部调用 , 哪些是暴露给前端/客户端调用 。


推荐阅读