配合《【后端】了解常见的软件架构》阅读更佳。

1)网关

1.1 什么是网关?

广义上,只要是进入某个网的"入口",都可以叫做网关,即只要连接两个不同的网络都可以叫网关

在软件架构中,网关这个词的含义已被扩展到了应用与服务层面

  • 比如,在提供 Restful API 的服务接口,一般被称作“应用网关”。
    • 这里,网关作为一个对外提供应用服务的媒介,一方面对外提供接口服务,接受请求并给予应答,另一方面,又屏蔽内部实现细节,只暴露黑盒调用方式与函数,保护了内部逻辑与结构。
    • 和网络中的 NAT 网关功能类比一下,可以发现有类似的设计思想。

*注意区分网关和网桥

  • 网桥:工作在数据链路层,在不同或相同类型的 LAN 之间存储并转发数据帧,必要时进行链路层上的协议转换。可连接两个或多个网络,在其中传送信息包。
  • 网关:是一个大概念,不具体特指一类产品,只要连接两个不同的网络都可以叫网关。
  • 网桥一般只转发信息,而网关可能进行包装。

1.2 为什么需要网关?

  • 注意,这里的网关通常指的是 API Gataway,即将所有API的调用统一接入API网关层,由网关层负责接入和输出

随着单体应用程序架构分布式架构 / 微服务等架构演变,对网关的需求逐渐产生:

  • 单体架构(或称分层架构)

    单体架构比较初级,典型的三级架构是:前端(Web/手机端)+ 中间业务逻辑层 + 数据库层
    • 这是一种典型的Java Spring mvc或者Python Drango框架的应用。
    • 架构图: 在这里插入图片描述
    • 单体架构的应用比较容易部署、测试, 在项目的初期,单体应用可以很好地运行。
  • 然而,随着需求的不断增加, 越来越多的人加入开发团队,代码库也在飞速地膨胀。慢慢地,单体应用变得越来越臃肿,可维护性、灵活性逐渐降低,维护成本越来越高
  • 分布式应用

    中级架构,分布式应用:中间层分布式 + 数据库分布式

    • 是单体架构的并发扩展,将一个大的系统划分为多个业务模块,业务模块分别部署在不同的服务器上,各个业务模块之间通过接口进行数据交互。
    • 数据库也大量采用分布式数据库,如redis、ES、solor等。
    • 通过LVS/Nginx代理应用,将用户请求均衡的负载到不同的服务器上。
    • 架构图: 在这里插入图片描述
    • 该架构相对于单体架构来说,提供了负载均衡的能力,大大提高了系统负载能力,解决了网站高并发的需求。

  • 微服务架构

    微服务架构主要是中间层分解,将系统拆分成很多小应用(微服务),微服务可以部署在不同的服务器上,也可以部署在相同的服务器不同的容器上。

    • 单应用的故障不会影响到其他应用,单应用的负载也不会影响到其他应用,其代表框架有Spring cloud、Dubbo等。
    • 架构图: 在这里插入图片描述

API Gateway的出现:

举例来说:

  • 微服务将原来的单体应用进行微服务化。将原来集中于一体的功能(如商品、订单服务)进行拆分,每个功能模块又有各自的自成体系的发布、运维等功能:
    在这里插入图片描述
  • 原先IOS、Android、PC客户端调用服务的地方,需要多个URL地址,有订单的、商品的、用户的。微服务化后就必须有统一的出入口,这种情况下,API Gateway就出现了

API Gateway很好的解决了微服务下调用、统一接入等问题,如下图所示:
在这里插入图片描述

  • 有了API网关之后,各个API服务提供团队可以专注于自己的业务逻辑处理,而API网关则更专注于安全、流量、路由等问题。

    • 网关作为系统的唯一入口,也就是说,进入系统的所有请求都需要经过 API 网关。
    • 当系统外部的应用或者客户端访问系统的时候,都会遇到这样的情况:
      • 系统要判断它们的权限
      • 如果传输协议不一致,需要对协议进行转换
      • 如果调用水平扩展的服务,需要做负载均衡
      • 一旦请求流量超出系统承受的范围,需要做限流操作
      • 针对每个请求以及回复,系统会记录响应的日志
  • 因此只要是涉及到对系统的请求,并且能够从业务中抽离出来的功能,都有可能在网关上实现。

    • 例如:协议转换,负载均衡,请求路由,流量控制等等。

*代理和网关的区别

  • 代理是纯粹的数据透传,协议不会发生变化;
  • 网关在数据透传的背景下,还会设计协议的转换
  • 比如上图中用户请求传输到网关的协议是HTTP,通过网关透传到下游则可能已经转换成企业内部的RPC了(比如JSF、Dubbo等企业自研的RPC框架)。


2)API网关架构

2.1 API网关服务定位

API 网关拥有处理请求的能力,从定位来看分为 5 类:

  • 面向 WebApp:

    这部分的系统以网站和 H5 应用为主。
    • 通过前后端分离的设计,将大部分的业务功能都放在了后端,前面的 Web App 只展示页面的内容。

  • MobileApp:

    这里的 Mobile 指的是 iOS 和 Android,设计思路和 WebApp 基本相同。
    • 区别是 API 网关需要做一些移动设备管理的工作(MDM)。
      • 例如:设备的注册,激活,使用,淘汰等,全生命周期的管理。
    • 由于移动设备的特殊性,导致了我们在考虑移动设备请求的时候,需要考虑请求、设备、使用者之间的关系

  • 面向合作伙伴的 OpenAPI:

    通常系统会给合作伙伴提供接口。
    • 这些接口会全部开放或者部分开发,在有条件限制(时间,流量)的情况下给合作伙伴访问。
    • 因此需要更多考虑 API 网关的流量和安全以及协议转换的管理。

  • 企业内部可扩展 API:

    给企业内部的其他部门或者项目使用,也可以作为中台输出的一部分,支持其他系统。
    • 这里需要更多地考虑划分功能边界,认证和授权问题

  • 面向 IOT 设备:

    会接收来自 IOT 设备的请求,特别是工业传感器等设备。
    • 这里需要考虑协议转换和数据过滤

2.2 API网关构成

API 网关可以拆分成为 3 个系统:Gateway-Core(核心)、Gateway-Admin(管理)、Gateway-Monitor(监控)。
在这里插入图片描述

  • Gateway-Core 核心网关:

    负责接收客户端请求,调度、加载和执行组件,将请求路由到上游服务端,并处理其返回的结果。
    • 大多数的功能都在这一层完成,例如:验证、鉴权、负载均衡、协议转换、服务路由、数据缓存
    • 如果没有其他两个子系统,它也是可以单独运行的。

  • Gateway-Admin 网关管理:

    可以进行 API、组件等系统基础信息的配置。
    • 例如:限流的策略,缓存配置,告警设置。

  • Gateway-Monitor 监控:

    监控日志、生成各种运维管理报表自动告警等。

管理和监控系统主要是为核心系统服务的,起到支撑的作用。



3)API网关的功能

3.1 基本功能

一个API网关的基本功能包含了统一接入、协议适配、流量管理与容错、以及安全防护。

在这里插入图片描述

  • 统一接入:

    • 作为对外的门面,网关应该拥有统一且简洁的规范,以减少接入的成本。

  • 协议适配 / 转换:

    • 对外提供的都是HTTP接口,但内部系统是使用Dubbo来相互调用的,所以网关势必要能够完成协议转换,并通过负载均衡等手段将请求高效的分发到内部系统中去。

  • 流量管控:

    • 系统的承受能力都有限,例如:当营销活动做得好时,系统请求量超过系统的服务能力的极限,如果放任不管,势必压垮内部系统,此时应该对内部系统提供一定的保护。
    • 作为服务能力的出口,一旦不可用,在外部看来所有的服务都不可用,所以应该网关必须高可用、高并发
    • 常见的手段有:限流、降级、熔断

  • 安全防护:

    网关需要验证请求信息,屏蔽非法请求,确保接口的安全性,保证所有达底层业务系统的请求都是安全、可靠地。

    • 常用的手段有:
      • 防篡改(例如参数加签)
      • 请求安全(请求端加密,网关层解密)
      • 身份校验(必须是合法的用户,必须是合法的第三方)
      • 接口安全级别(例如:接口不需要登录即可访问;需要登录方可访问;接口仅提供给app,H5不能使用等)
      • 接口权限限制
      • 黑白名单
      • HTTPS

3.2 功能细分

  • 路由选择:网关可以根据请求的 URL 地址解析,知道需要访问的服务。再通过路由表把请求路由到目标服务上去。

  • 服务注册:为了能够代理后面的服务,并把请求路由到正确的位置上,网关应该有服务注册功能,也就是后端的服务实例可以把其提供服务的地址注册、取消注册。
    • 一般来说,注册也就是注册一些 API 接口。
      • 比如,HTTP 的 Restful 请求,可以注册相应 API 的 URI、方法、HTTP 头。
      • 这样,Gateway 就可以根据接收到的请求中的信息来决定路由到哪一个后端的服务上。

  • 负载均衡:因为一个网关可以接收多个服务实例,所以网关还需要在各个对等的服务实例上做负载均衡策略。
    • 简单点就是直接 Round-Robin 轮询(随机算法)
    • 复杂点的可以设置上权重进行分发(权重算法)
    • 再复杂一点还可以做到 session 粘连

  • 流量控制:限流是 API 网关常用的功能之一。
    • 当上游服务超出请求承载范围,或者服务因为某种原因无法正常使用,都会导致服务处理能力下滑。这个时候,API 网关作为“看门人”,就可以限制流入的请求,让应用服务器免受冲击。
    • 限流实际上就是限制流入请求的数量,其算法不少,有令牌桶算法,漏桶算法,连接数限制等等。

  • 统一鉴权:可以把权限认证放到 API 网关来进行。
    • 访问应用服务器的请求都需要拥有一定权限,如果说每访问一个服务都需要验证一次权限,这个对效率是很大的影响。
    • 目前比较常见的做法是Tocken,关于token可移步《【接口测试】鉴权初了解》
    • 如果要实现多个系统的 OSS(Single Sign On 单点登录),API 网关需要和 CAS(Central Authentication Service 中心鉴权服务)做连接,来确定请求者的身份和权限。

  • 熔断降级:当应用服务出现异常,不能继续提供服务的时候,作为 API 网关需要做出处理,把请求导入到其他服务上,或者对服务进行降级处理。
    • 例如:用兜底的服务数据返回客户端,或者提示服务暂时不可用。同时通过服务注册中心,监听存在问题的服务,一旦服务恢复,随即恢复路由请求到该服务。

  • 发布测试:在发布版本的时候会采用:金丝雀发布和蓝绿发布。作为 API 网关可以使用路由选择和流量切换来协助上述行为。
    • 这样对于软件质量的提升,甚至产品试错都有非常积极的意义。

  • 缓存数据:可以在 API 网关缓存一些修改频率不高的数据。
    • 例如:用户信息,配置信息,通过服务定期刷新这个缓存就行了。

  • 日志记录:通过 API 网关上的过滤器我们可以加入日志服务,记录请求和返回信息,同时可以建立一个管理员的界面去监控这些数据。

  • API 聚合:可以将多个单独请求聚合成一个请求。
    • 在微服务体系的架构中,因为服务变小了,所以一个明显的问题是,客户端可能需要多次请求才能得到所有的数据。这样一来,客户端与后端之间的频繁通信会对应用程序的性能和规模产生非常不利的影响。
    • 于是,我们可以让网关来帮客户端请求多个后端的服务(有些场景下完全可以并发请求),然后把后端服务的响应结果拼装起来,回传给客户端(当然,这个过程也可以做成异步的,但这需要客户端的配合)。

  • API 编排:同样在微服务的架构下,要走完一个完整的业务流程,我们需要调用一系列 API,就像一种工作流一样,这个事完全可以通过网页来编排这个业务流程。
    • 我们可能通过一个 DSL 来定义和编排不同的 API,也可以通过像 AWS Lambda 服务那样的方式来串联不同的 API。


4)API网关技术原理

4.1 协议转换

  • 每个系统内部服务之间的调用,可以统一使用一种协议,例如:HTTP,GRPC。
  • 假设每个系统使用的协议不同,那么系统之间的调用或者数据传输,就存在协议转换的问题了。
  • API 网关通过泛化调用的方式实现协议之间的转化。

协议转换实际上就是将不同的协议转换成“通用协议”,然后再将通用协议转化成本地系统能够识别的协议。

  • 这一转化工作通常在 API 网关完成。
  • 通用协议用得比较多的有 JSON,当然也有使用 XML 或者自定义 JSON 文件的。
    在这里插入图片描述

4.2 链式处理

消息从第一个“处理步骤”流入,从最后一个“处理步骤”流出,每个步骤对经过的消息进行处理,整个过程形成了一个链条。

以 Zuul 网关过滤器链式处理为例,当消息出入网关需要经历一系列的过滤器:

在这里插入图片描述

  • PRE:前置过滤器,用来处理通用事务,比如鉴权,限流,熔断降级,缓存。并且可以通过 Custom 过滤器进行扩展。
  • ROUTING:路由过滤器,在这种过滤器中把用户请求发送给 Origin Server。它主要负责:协议转化和路由的工作。
  • POST:后置过滤器,从 Origin Server 返回的响应信息会经过它,再返回给调用者。在返回的 Response 上加入 Response Header,同时可以做 Response 的统计和日志记录
  • ERROR:错误过滤器,当上面三个过滤器发生异常时,错误信息会进到这里,并对错误进行处理。

4.3 异步请求

为什么需要异步请求?

所有的请求通过 API 网关访问应用服务。

  • 拿 Zuul 为例,Zuul1 采用:一个线程处理一个请求的方式
    • 线程负责接受请求,然后调用应用返回结果。
    • 如果把网络请求看成一次 IO 操作的话,处理请求的线程,从接受请求,到服务返回响应,都是阻塞状态。

一旦吞吐量上去了,如何高效地处理这些请求?

  • 同时,如果多个线程都处在这种状态,会导致系统缓慢。因为每个网关能够开启的线程数量是有限的,特别是在访问的高峰期。

为了解决这个问题,Zuul2 启动了异步请求的机制

  1. 每个请求进入网关的时候,会被包装成一个事件,CPU 内核会维持一个监听器,不断轮询“请求事件”。
  2. 一旦发现请求事件,就会调用对应的应用。
  3. 获取应用返回的信息以后,按照请求的要求把数据/文件放到指定的缓冲区,同时发送一个通知事件,告诉请求端数据已经就绪,可以从这个缓冲获取数据/文件。

这个过程是异步的,请求的线程不用一直等待数据的返回。它在请求完毕以后,就直接返回了,这时它可以做其他的事情。

  • 当请求数据被 CPU 内核获取,并且发送到指定的数据缓冲区时,请求的线程会接到“数据返回”的通知,然后就直接使用数据,不用自己去做取数据的操作。

在这里插入图片描述

异步处理请求的两种模式

实现异步处理请求有两种模式,分别是:

  • Reactor:

    通过 handle_events 事件循环处理请求。
    在这里插入图片描述

    • 用户线程注册事件处理器之后,可以继续执行其他的工作(异步),而 Reactor 线程负责调用内核的 Select 函数检查 Socket 状态。
    • 当有 Socket 被激活时(获取网络数据),则通知相应的用户线程,执行 handle_event 进行数据读取、处理的工作。

  • Proactor:

    在这里插入图片描述

    • 用户线程使用 CPU 内核提供的异步 IO 发起请求,请求发起以后立即返回。
    • CPU 内核继续执行用户请求线程代码。此时用户线程已将 AsynchronousOperation(异步处理)和 CompletionHandler(完成获取资源)注册到内核。
    • 之后操作系统开启独立的内核线程去处理 IO 操作。
    • 当请求的数据到达时,由内核负责读取 Socket(网络请求)中的数据,并写入用户指定的缓冲区中。
    • 最后内核将数据和用户线程注册的 CompletionHandler 分发给内部 Proactor,Proactor 将 IO 完成的信息通知给用户线程(一般通过调用用户线程注册的完成事件处理函数),完成异步 IO。


5)常见网关

按照使用数量、成熟度等来划分,主流的开源网关有 4 个:

  • OpenResty(语言:Nginx+lua)
  • Kong(语言:Nginx+lua)
  • Zuul/Zuul2(语言:Java)
  • Spring Cloud Gateway(语言:Java)

5.1 OpenResty

OpenResty基于 Nginx 与 Lua 的高性能 Web 平台.

  • 其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。
  • 用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
  • 官网:https://openresty.org/cn/

通过揉和众多设计良好的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的 Web应用服务器。

  • 基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种 Nginx C模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用。

5.2 Kong

Kong基于OpenResty开发,也是流量层网关, 是一个云原生、快速、可扩展、分布式的Api 网关。

  • 继承了OpenResty的高性能、易扩展性等特点。2
  • Kong通过简单的增加机器节点,可以很容易的水平扩展。
  • 同时功能插件化,可通过插件来扩展其能力。
  • 官网:https://konghq.com/

5.3 Zuul

  • Zuul1.0

    Zuul是所有从设备和web站点到Netflix流媒体应用程序后端请求的前门。
    • 作为一个边缘服务应用程序,Zuul被构建来支持动态路由、监视、弹性和安全性。
    • 它还可以根据需要将请求路由到多个Amazon自动伸缩组。

Netflix宣布了通用API网关Zuul的架构转型。

  • Zuul原本采用同步阻塞架构,转型后叫作Zuul2,采用异步非阻塞架构。
  • Zuul2和Zuul1在架构方面的主要区别在于,Zuul2运行在异步非阻塞的框架上,比如Netty。
  • Zuul1依赖多线程来支持吞吐量的增长,而Zuul 2使用的Netty框架依赖事件循环和回调函数。
  • Zuul2.0

    Zuul2开始采用了异步模型。
    • 前端用Netty Server代替Servlet,目的是支持前端异步。后端用Netty Client代替Http Client,目的是支持后端异步。
    • 过滤器换了一下名字,用Inbound Filters代替Pre-routing Filters,用Endpoint Filter代替Routing Filter,用Outbound Filters代替Post-routing Filters。

5.4 Spring Cloud Gateway

SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

  • SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul。

  • 为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

  • Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

  • 官网:https://spring.io/projects/spring-cloud-gateway

5.5 网关对比

网关 限流 鉴权 监控 易用性 可维护性 成熟度
Spring Cloud Gateway 可以通过IP,用户,集群限流,提供了相应的接口进行扩展 普通鉴权、auth2.0 Gateway Metrics Filter 简单易用 spring系列可扩展强,易配置,可维护性好 spring社区成熟,但gateway资源较少
Zuul2 可以通过配置文件配置集群限流和单服务器限流,亦可通过filter实现限流扩展 filter中实现 filter中实现 参考资料较少 可维护性较差 开源不久,资料少
OpenResty 需要lua开发 需要lua开发 需要开发 简单易用,但是需要进行的lua开发很多 可维护性较差,将来需要维护大量lua脚本 很成熟资料很多
Kong 根据秒,分,时,天,月,年,根据用户进行限流。可在原码的基础上进行开发 普通鉴权,Key Auth鉴权,HMAC,auth2.0 可上报datadog,记录请求数量,请求数据量,应答数据量,接收于发送的时间间隔,状态码数量,kong内运行时间 简单易用,api转发通过管理员接口配置,开发需要lua脚本 "可维护性较差,将来需要维护大量lua库 相对成熟,用户问题汇总,社区,插件开源


【部分内容参考自】

  • 网关到底是什么?:https://www.zhihu.com/question/67671731
  • 四种软件架构,看看你属于哪个层次:https://www.jianshu.com/p/e7b992a82dc0
  • 初识API网关 / API Gateway:https://www.jianshu.com/p/7baab672b822
  • API网关作用:https://www.jianshu.com/p/8cbf97b40c26
  • API网关系统架构:https://www.cnblogs.com/duanxz/p/4919158.html
  • 亿级流量架构之网关设计思路、常见网关对比:https://www.cnblogs.com/Courage129/p/14446586.html
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐