第1章 网关之道
1.1 认识API网关
1.1.1 API 网关是什么
工作中提及的网关特指 API 网关(API Gateway)。字面意思是将所有 API 的调用统一接入 API 网关层,由网关层负责接入和输出
什么情况下需要一个 API 网关?
单体应用时代,业务简单,功能都集中在一个应用中,统一部署、统一测试,随着业务发展组织成员日益增多。将多有的功能集中在一个Tomcat中的时候,每更新一个功能模块,势必要更新所有的程序。系统难以维护
微服务出现,将原来的单体应用进行微服务化。将原来集中于一体的功能(如商品功能、订单功能)进行拆分,每个功能模块有各自的自成体系的发布、运维等功能。解决了单体应用下的弊端
微服务化后,原来iOS、Android、PC客户端调用服务端的地方,需要多个URL地址,商品的、订单的、用户的。为服务化后就必须有统一的入口和出口,在这种情况下, API Gateway就出现了。
API Gateway 很好地解决了微服务下客户端调用、统一接入的问题。如下图
有了API网关之后,各个API服务提供团队可以专注自己的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。
网关与代理的区别:
代理是纯粹的数据透传,协议不会发生变化;
网关在数据透传的背景下,还会涉及协议的转换,比如上图中用户请求传输到网关的协议是 HTTP,通过网关透传到下游则可能已经转换成企业内部的 RPC了(比如 JSF、Dubbo等企业自研的 RPC框架)
1.1.2 API 网关的基本功能
一个API网关的基本功能包括:统一接入、协议适配、流量管控与容错,以及安全防护,这四大基本功能构成了网关的核心能力。
网关首要的功能是负责统一接入,然后将请求的协议转换成内部的接口协议,在调用的过程中还要有限流、降级和熔断等容错的方式来保护网关的整体稳定,同时网关还要做到基本的安全防护(防刷控制),以及黑白名单(比如 IP 地址白名单)等基本的安全措施。如下图所示。
1.1.3 API 网关架构示例
除了基本的四个功能,网关运行良好的环境还包括注册中心(比如通过 ZooKeeper 读取已发布的 API 接口的动态配置)。为了实现高性能,将数据全部异构到缓存(比如 Redis)中,同时还可以配合本机缓存来进一步提高网关系统的性能。
为了提高网关的吞吐率,可以使用 NIO+Servlet 3 异步的方式,还可以利用 Servlet 3 的异步特性将请求线程与业务处理线程分开,为后续的线程池隔离做好基本的支撑。
访问日志的存储可以放到 HBase 中,如果要作为开放网关使用,需要一个支持 OAuth 2.0 协议的授权中心。同时还可以引入 Nginx+Lua 的方式,将一些基本的校验判断前置到应用系统之上,这样可以更轻量化地处理接入的问题。
整体的网关架构(涵盖开放网关)示例如下图所示
1.2 一个传统网关系统的几种“死”法
传统网关,是按照网关技术演进的阶段划分的,从同步到半同步,再到全异步。将同步和半同步技术下的网关称为“传统”网关。
同步网关的意思是从接收请求到调用API接口提供方的过程都是同步调用;
半同步则是指将 I/O 请求线程和业务处理线程分开,但业务线程内部还是同步调用 API 接口;
全异步是整个链路都是异步请求。
传统网关会在什么情况下 down 掉?
API 网关系统的两大特点:一个是访问量大,另一个是依赖系统多。如下图所示,“单纯”的情况下(比如系统A提供的接口只供网关调用)网关系统要承受比被依赖的系统多数倍的流量,因为 API网关是所有依赖 API的集合。
网关还会通过 RPC 调用很多底层系统,每个系统的稳定性水平参差不齐,接口的性能也会间接影响网关整体的运行稳定性。因此我们再做防范的时候就要从这两个特点入手。
上面介绍的 API网关的两大特点是外部因素,下面是内部因素。程序都是运行在计算机上面的,计算机的每个部件的利用率和负载水平直接影响程序的运行,比如 CPU、内存、磁盘等。另外系统之间的交互还需要网络,这些因素都需要考虑。
一段程序在计算机中运行依赖部件如下图:
1.2.1 关注CPU
用户请求在进入网关的时候从技术上已经把 I/O请求线程和业务处理线程隔离开了,这一点可以利用 Servlet3 异步特性实现。如下图所示
业务线程池是在 CPU中运行的,线程是计算机 CPU 最宝贵的资源,我们一定要重点关注 CPU 的利用率和 CPU 负载
CPU利用率:显示的是程序在运行期间实时占用的 CPU百分比
CPU负载:显示的是一段时间内正在使用和等待使用 CPU 的平均任务数。在 Linux系统中,我们可以使用 uptime 或 top命令查看系统的负载情况
top - 14:17:13 up 19 days, 3:27, 1 user, load average: 1.19, 1.39, 1.33
load averages 的意思是系统平均负载,包括三个数字,分别表示 1分钟、5分钟、15分钟内系统的负载平均值。可以按照 1 分钟的粒度取一个数字,从而判定系统负载的大小。
19 days 说明此台机器已经有23 天没有重新启动过了
CPU利用率高并不意味着负载就一定大,两者没有必然联系。线上生产环境需要重点监控CPU利用率和负载。
API 网关访问量大、依赖系统多,如果调用的 API 性能突然变差,在大访问量的情况下,线程数会逐渐升高,直至将 CPU 资源耗尽。蔓延到整个网关集群,这就是雪崩效应。
1.2.2 关注磁盘
磁盘有两个比较重要的指标分别是 磁盘使用率 和 磁盘负载百分比。
磁盘负载百分比:在Linux下查看该指标的命令是 iostat -x 110
%util 值接近 100%,说明产生的 I/O 请求太多, I/O系统已经满负荷,该磁盘可能存在瓶颈。
程序运行的过程中,我们可能都不会关注磁盘的使用,如果处理不当,则有可能成为一个'定时炸弹'。网关的特性访问量大,再加上有的程序里面的日志打印不规范,比如日志的级别设置的不合理,把 info 日志打印出来。
即使在日志级别合理的情乱下,比如 error 日志,这时又涉及网关的第二个特性,依赖系统多。当有 API 返回失败错误的时候,就会有大量的 error 日志写入磁盘,很容易把磁盘资源耗尽,尤其在容器时代,每台服务器分配的磁盘容量相对物理机来说都比较小,如果集群的所有机器的磁盘资源耗尽,那么对网关系统来说就是一场灾难。
1.2.3 关注网络
在微服务架构下,应用离不开网络,尤其是网关系统,它的特点之一就是依赖系统多。依赖就是 RPC 调用和网络。
在一个 RPC 环境下,网络占据了一次 RPC 调用所耗时间的很大比重。网络质量的好坏直接影响了一次请求从进入 API网关到返回给用户响应的时间长短。
如下入所示,网关到依赖系统B之间得网络突然变差,调用时长增加,在请求访问量多得时候,一请求一线程得模式下,会直接导致 API 网关系统的任务线程数增多,如果短时间内不能恢复,则整个 API网关的集群所有机器的 CPU 资源都会被线程耗尽。
同时现有的线上生产环境部署并不能保证同机房调用,甚至还有跨地区调用,因此网络是我们要考虑的一个重要因素,同时网络的因素需要和上面讲到的 CPU 的线程资源相关联去考虑。
总结一个传统 API 网关系统的几种 死法:
1.因为依赖的某个系统的 API 性能突然变差导致请求线程数量逐渐升高直至线程占满了 CPU,也就是 API 网关依赖系统多的特点因素,可以认为是被其他系统 拖死的。
2.线上生产环境日志打印不规范,过度打印日志,再加上请求量突然变大,导致清理工具来不及清理日志,最后磁盘满了。
3.网络一直是一个除系统本身外最不稳定的因素,在系统之间调用的时候,网络发生故障导致请求变慢,这一点和第一条被其他系统 拖死类似,只是这次是网络。