可编程网关设计和实践

Posted by WZhong on Tuesday, January 21, 2020

TOC

网关和BFF是如何演化出来的

  1. 接入

    • 网关即Gateway,是整个微服务的集中入口,是实现前后分离的关键
    • 网关的可编程性对微服务的升级及部署灵活性非常重要
    • 所以需要设计一款轻量级的可编程网关,以应对不断变化的业务需求
  2. 网关和BFF(Backend For Frontend)的演化进程

    • MyShop SOA V1,2011年左右

      • 外网:浏览器 -> Nginx:反向代理+负载均衡 -> 服务端web应用 -> 微服务:认证、用户、购物车、商品、支付
    • MyShop SOA V2,2012年,移动端发展

      • 移动端 -> Nginx -> 微服务
      • 浏览器 -> Nginx -> 服务端web应用 -> 微服务
    • MyShop SOA V2.5,移动端添加无线BFF层

      • 移动端 -> Nginx -> 无线BFF -> 微服务
      • 浏览器 -> Nginx -> 服务端web应用 -> 微服务
    • MyShop SOA V3,移动端添加无线网关层

      • 移动端 -> Nginx -> 无线网关 -> 无线BFF -> 微服务
      • 浏览器 -> Nginx -> 服务端web应用 -> 微服务
    • MyShop SOA V4,统一网关层

      • 用户体验层 -> 网关层 -> BFF层 -> 微服务层
      • 用户体验层:第三方应用、H5前后分离应用、无线应用、浏览器
      • 网关层:开放平台网关、H5网关、无线网关、Web应用网关
      • BFF层:开放平台BFF层、H5 BFF层、无线BFF层、服务器端Web应用
      • 微服务层

网关(Gateway)和反向代理(Reverse Proxy)是什么关系

  1. Web1.0/2.0时代,应用以web网站形式呈现

    • 前置反向代理,作用是返乡路由和负载均衡,也承担安全认证、日志监控、限流熔断、缓存等功能
    • 产品有Nginx、HAProxy
    • 网站升级频率不高,反向代理采用静态配置方式,由运维团队单独配置
  2. Web3.0/微服务时代

    • 应用形态出现了提供大量api的服务,api的升级更新频率很高,对路由、安全的动态配置能力要求很高
    • 出现的矛盾
      • 传统反向代理的静态配置不灵活,缺乏动态配置能力
      • 传统运维配置方式效率低效,研发无法做到自助配置
    • API Gateway作为补充因运而生
    • API Gateway和反向代理功能大同小异,不过是主要面向api和微服务,提供更灵活的、可供研发自助配置的动态配置能力
    • 产品有Netflix Zuul
    • 网关和反向代理共存,运维成本高
  3. 云原生时代

    • 对服务灵活升级有更高的要求,需要灰度、金丝雀、蓝绿部署等,对网关不仅要求可动态配置,而且要求可动态编程
    • 网关和动态代理融合的趋势:面向云原生的统一代理,或称统一网关
    • 产品有envoy、Traefik,是云原生组织CNCF(Cloud Native Computing Foundation)推荐的产品

网关需要分集群部署吗

  1. 反向代理 + 网关部署架构

    • 架构:共存
      • API流量 -> 网关(可按不同api场景分集群部署) -> 微服务
      • 网页流量 -> 反向代理 -> 单页应用 + Web应用
    • 分析
      • 部署架构相对复杂,需维护两套体系
      • 如果网关和反向代理不在同一个域,还要解决跨域问题
      • 适合业务和团队规模大,应用场景多的场合
  2. 统一网关部署架构

    • 架构:统一
      • 流量 -> 统一网关 -> 微服务 + 单页应用 + Web应用
    • 分析
      • 所有应用可统一部署,没有跨域问题,只要应用和微服务都在同一个根域下
      • API和Web/SPA场景有一些差异化需求,如:对网关统一错误处理,web错误需展示错误页面,api错误提供错误消息;认证方式差异;对于差异,统一网关不易区分,需要在网关层添加区分逻辑
  3. 统一网关 + 分集群部署架构

    • 网关层
      • 开放平台网关 + H5网关 + 无线网关 + Web应用网关

Faraday网关(自研)内核设计

  1. 设计

    • 核心
      • ReverseProxyFilter,是一个Servlet Filter
    • 组件
      • 路由解析器

      接收到http请求时,取出其中的host域名信息,通过查询路由映射表找到对应的目标服务,包括服务名、地址和其他配置,然后将请求交由下个环节进行处理

      • 路由映射表

      网关关键。常见路由方式有:基于域名的路由、基于请求path的路由、基于Http头请求参数的路由等。此处采用基于域名的路由,路由映射表存储的是Http的Host头和service之间的映射关系。表可静态配置,如使用本地文件配置,也可动态配置,如从服务注册表里动态获取并定期更新。动态配置需要对接Eureka、Zookeeper或Consul这种服务发现的产品

      • HttpClient映射表

      存储service服务和实际访问该服务的HttpClient的映射关系,这个映射关系是基于路由表信息构建,根据路由表更新而更新;采用提前加载(eager loading)的机制。在网关初始化和后续路由表异步更新时,提前初始化每个服务所使用的httpClient,这样实际访问服务时,就可以重用已经创建好的httpClient,不需要再按需创建,从而提升服务访问的性能

      • 请求转发器

      负责转发请求的组件,当获得请求和目标服务的信息,通过查询httpClient映射表找到对应的httpClient,就可以通过httpClient将请求转发到目标服务,并接收服务产生的响应,并最终将响应返回给调用方。如果网关启用了LB的能力,请求转发还要根据一定规则计算出实际要访问的服务实例的地址,再进行转发。若使用K8s,则无需开启LB,因K8s已经支持服务发现和负载均衡的能力

      • 请求截获器

      可以在请求上添加必要的http header,认证鉴权,日志监控等等,扩展网关能力

      • 响应截获器

      可以在响应上添加必要的http header,认证鉴权,日志监控等等,扩展网关能力

  2. 静态路由配置

    • 举例:本地开发环境的静态路由配置
      • 路由名称 + 主机头 + 对应目标服务的地址
      • 目标服务可以是域名、ip列表
      • 路由配置还可包括超时配置等信息

Faraday网关代码解析

  1. MappingsProvider
    • 路由映射表实现的超类
    • 主要方法:resolveMapping(),updateMappings()
    • 子类:ConfigurationMappingsProvider通过读取配置文件方式、ProgrammaticMappingProvider通过可编程方式
  2. HttpClientProvider
    • HttpClient映射表的实现
    • 主要方法:updateHttpClients(),getHttpClient()
  3. ReverseProxyFilter
    • 主流程,继承自OncePerRequestFilter
    • 主方法:doFilterInternal(request, response, filterChain)
  4. RequestForwarder
    • 请求转发器
    • 主方法:forwardHTTPRequest()

生产级网关需要考虑哪些环节(生产扩展点)

  1. 限流熔断:集成resilience4j或hystrix

  2. 动态路由和负载均衡:集成eureka

  3. 基于Path的路由,如api.xxx.com/pathx

  4. 截获器链

  5. 日志采集和Metrics埋点

  6. 响应流优化

主流开源网关

支持公司 实现语言 亮点 不足
Nginx (2004) Nginx Inc C/Lua 高性能,成熟稳定 门槛高,扁运维,可编程弱
Kong (2014) Kong Inc OpenResty/Lua 高性能,可编程API 门槛较高
Zuul1 (2012) Netflix/Pivotal Java 成熟,简单门槛低 性能一般,可编程一般
Spring Cloud Gateway (2016) Pivotal Java 异步,配置灵活 早期产品
Envoy (2016) Lyft C++ 高性能,可编程API/ServiceMesh集成 门槛较高
Traefik (2015) Containous Golang 云原生,可编程API/对接各种服务发现 生产案例不多

「真诚赞赏,手留余香」

WZhong

真诚赞赏,手留余香

使用微信扫描二维码完成支付