首页 > 编程知识 正文

网关,api网关和前端网关

时间:2023-05-03 11:21:03 阅读:161086 作者:1078

内容简介API网关API注册协议转换服务发现服务呼叫优雅的离线性能现金流限制稳定性熔断降级日志隔离网关管控平台其他汇总

前言

假设你正在开发一个电子商务网站,这里包含很多后端的微服务,包括会员、商品、推荐服务等。

这里发生了问题。 APP/Browser如何访问这些后端的服务? 如果业务比较简单的话,可以为每个业务分配独立的域名(https://service.api.company.com),但这种方法存在一些问题。

每个业务都需要鉴证、限流、权限检查等逻辑。 每个业务各自战斗,自己做车轮实现一次,会很痛。 完全可以提取出来,放在统一的地方做。 如果业务量比较简单的话,这种方式前期没有问题,但是随着业务越来越复杂,比如淘宝、亚马逊打开一个页面就有可能有几百个微服务器协同工作。 给每个微服务器分配域名,客户端代码很难维护,一方面涉及数百个域名,另一方面会成为连接数的瓶颈。 打开APP,想象一下包中涉及数百个远程呼叫。 每次上线新服务时,这都需要运行时参与。 在线、离线服务,如域名申请、Nginx配置等,也需要运行时参与。 另外,如果采用域名这种方式,对环境的隔离也不太友好,调用者需要自己根据域名自己进行判断。 此外,每个后端微服务器都用不同的语言编写,可能采用不同的协议,例如HTTP、Dubbo和GRPC,但不可能适应客户端这么多协议。 这是一项非常困难的工作,项目非常复杂,难以维护。 后期需要重构微服务器的话,会非常麻烦,需要客户根据你进行改造。 例如,商品服务器随着业务的复杂,后期需要分割为多个微服务器。 这个时候,对外提供的服务也需要分成多个,同时客户端需要针对你进行改造,非常痛苦。 API网关

更好的方法是采用API网关来实现一个API网关接管所有的入口业务。 与Nginx类似,网关负责将所有用户的请求传输到后端服务器,但不仅仅是简单的传输,还包括验证、限制、权限、熔断、协议转换、统一错误代码、缓存和日志

部署API网关意味着客户端只需与API网关进行交互,而不是与每个运营商的接口分别进行通信,但部署更多组件会引入更多潜在的故障点,从而提供高性能、稳定的网关

API注册运营商如何访问网关? 一般有几种方法。

通过插件扫描业务端的API,如Spring MVC的注释,结合Swagger的注释,实现参数校验、文档SDK的生成等功能,扫描完成后网关的存储服务器手动输入。 例如,接口路径、请求参数、响应参数、调用方式等信息,但这种方式相对比较麻烦。 参数过多的话,前期的输入会很费工夫。

导入配置文件。 在例如SwaggerOpenAPI等中,将例如AlibabaCloud (阿里巴巴云)的网关:

协议转换内部的API可能通过各种不同的协议实现,例如HTTP、Dubbo和GRPC,但许多协议对用户非常不友好,或者不能像Dubbo服务那样向外部公开。 虽然需要在网关层将用户的HTTP协议请求转换为对应的协议,例如HTTP - Dubbo,但是还需要注意很多问题,如参数类型。 如果类型错误,导致转换出现问题,并且日志不够详细,则很难确定问题。

服务发现网关作为流量的入口,负责转发请求,但首先需要知道转发给谁以及如何寻址。 这里有几种方法。

写在代码/配置文件中。 这个方式虽然比较受挫,但是可以使用。 例如,在线上还在使用物理机。 虽然IP变更不频繁,但是包括可扩展性、APP应用程序的上下线在内很麻烦。 网关本身需要实现健康监测机制。 网域名称。 采用域名也是个好方案。 虽然适用于所有语言,但就内部服务而言,走域名效率低下。 此外,由于预发送和联机通常是同一个数据库,所以网关读取的可能是同一个域名。 此时,预发送的网关会调用在线的服务。 注册中心。 如果采用注册中心就没有上述问题。 即使在容器环境中,节点的IP更改也相对频繁,但节点列表的实时维护由注册中心处理,对网关是透明的。 另外,注册中心的运行状况检查机构还会检测APP故障的正常上下线、异常停机时间等,并实时反馈给网关。 此外,采用注册中心的性能也不会造成额外的性能损失。 采用域名方式,需要一次性进行DNS分析、Nginx转发等,中途会出现很多跳,性能会大幅下降,而采用注册中心后,网关与业务端直接进行点对点通信,没有额外的损失。 由于服务呼叫网关与许多不同的协议对接,因此可能需要实现各种调用方法,如HTTP、Dubbo等。 出于性能原因,希望采用异步方法,但HTTP、Dubbo支持异步,例如apache提供了基于NIO的异步HTTP客户端。

由于网关涉及许多异步调用,例如拦截器、HTTP客户端、dubbo和redis,因此必须考虑异步调用的方式。 基于回调或future时,代码嵌套会变深,可读性会降低。 请参考zul

和 spring cloud gateway 的方案,基于响应式进行改造。

优雅下线

优雅下线也是网关需要关注的一个问题,网关底层会涉及到很多种协议,比如 HTTP、Dubbo,而 HTTP 又可以继续细分,比如域名、注册中心等,有些自身就支持优雅下线,比如 Nginx 自身是支持健康监测机制的,如果检测到某一个节点已经挂掉了,就会把这个节点摘掉,对于应用正常下线,需要结合发布系统,首先进行逻辑下线,然后对后续Nginx的健康监测请求直接返回失败(比如直接返回500),然后等待一段时间(根据Nginx配置决定),然后再将应用实际下线掉。另外对于注册中心的其实也类似,一般注册中心是只支持手动下线的,可以在逻辑下线阶段调用注册中心的接口将节点下线掉,而有些不支持主动下线的,需要结合缓存的配置,让应用延迟下线。另外对于其他比如Dubbo等原理也是类似。

性能

网关作为所有流量的入口,性能是重中之重,早期大部分网关都是基于同步阻塞模型构建的,比如Zuul 1.x。但这种同步的模型我们都知道,每个请求/连接都会占用一个线程,而线程在JVM中是一个很重的资源,比如Tomcat默认就是200个线程,如果网关隔离没有做好的话,当发生网络延迟、FullGC、第三方服务慢等情况造成上游服务延迟时,线程池很容易会被打满,造成新的请求被拒绝,但这个时候其实线程都阻塞在IO上,系统的资源被没有得到充分的利用。另外一点,容易受网络、磁盘IO等延迟影响。需要谨慎设置超时时间,如果设置不当,且服务隔离做的不是很完善的话,网关很容易被一个慢接口拖垮。
而异步化的方式则完全不同,通常情况下一个CPU核启动一个线程即可处理所有的请求、响应。一个请求的生命周期不再固定于一个线程,而是会分成不同的阶段交由不同的线程池处理,系统的资源能够得到更充分的利用。而且因为线程不再被某一个连接独占,一个连接所占用的系统资源也会低得多,只是一个文件描述符加上几个监听器等。而在阻塞模型中,每条连接都会独占一个线程,而线程是一个非常重的资源。对于上游服务的延迟情况,也能够得到很大的缓解,因为在阻塞模型中,慢请求会独占一个线程资源,而异步化之后,因为单条连接所占用的资源变的非常低,系统可以同时处理大量的请求。
如果是JVM平台,Zuul 2、Spring Cloud gateway 等都是不错的异步网关选型,另外也可以基于Netty、Spring Boot2.x的webflux、vert.x或者servlet3.1的异步支持进行自研。

缓存

对于一些幂等的 get 请求,可以在网关层面根据业务方指定的缓存头做一层缓存,存储到 Redis 等二级缓存中,这样一些重复的请求,可以在网关层直接处理,而不用打到业务线,降低业务方的压力,另外如果业务方节点挂掉,网关也能够返回自身的缓存。

限流

限流对于每个业务组件来说,可以说都是一个必须的组件,如果限流做不好的话,当请求量突增时,很容易导致业务方的服务挂掉,比如双11、双12等大促时,接口的请求量是平时的数倍,如果没有评估好容量,又没有做限流的话,很容易服务整个不可用,因此需要根据业务方接口的处理能力,做好限流策略,相信大家都见过淘宝、百度抢红包时的降级页面。
因此一定要在接入层做好限流策略,对于非核心接口可以直接将降级掉,保障核心服务的可用性,对于核心接口,需要根据压测时得到的接口容量,制定对应的限流策略。限流又分为几种:

单机。单机性能比较高,不涉及远程调用,只是本地计数,对接口RT影响最小。但需要考虑下限流数的设置,比如是针对单台网关、还是整个网关集群,如果是整个集群的话,需要考虑到网关缩容、扩容时修改对应的限流数。分布式。分布式的就需要一个存储节点维护当前接口的调用数,比如 redis、sentinel 等,这种方式由于涉及到远程调用,会有些性能损耗,另外也需要考虑到存储挂掉的问题,比如 redis 如果挂掉,网关需要考虑降级方案,是降级到本地限流,还是直接将限流功能本身降级掉。另外还有不同的策略:简单计数、令牌桶等,大部分场景下其实简单计数已经够用了,但如果需要支持突发流量等场景时,可以采用令牌桶等方案。还需要考虑根据什么限流,比如是IP、接口、用户维度、还是请求参数中的某些值,这里可以采用表达式,相对比较灵活。 稳定性

稳定性是网关非常重要的一环,监控、告警需要做的很完善才可以,比如接口调用量、响应时间、异常、错误码、成功率等相关的监控告警,还有线程池相关的一些,比如活跃线程数、队列积压等,还有些系统层面的,比如CPU、内存、FullGC 这些基本的。
网关是所有服务的入口,对于网关的稳定性的要求相对于其他服务会更高,最好能够一直稳定的运行,尽量少重启,但当新增功能、或者加日志排查问题时,不可避免的需要重新发布,因此可以参考 zuul 的方式,将所有的核心功能都基于不同的拦截器实现,拦截器的代码采用 Groovy 编写,存储到数据库中,支持动态加载、编译、运行,这样在出了问题的时候能够第一时间定位并解决,并且如果网关需要开发新功能,只需要增加新的拦截器,并动态添加到网关即可,不需要重新发布。

熔断降级

熔断机制也是非常重要的一项。frddp一个服务挂掉、接口响应严重超时等发生,则可能整个网关都被一个接口拖垮,因此需要增加熔断降级,当发生特定异常的时候,对接口降级由网关直接返回,可以基于 Hystrix 或者 Resilience4j 实现。

日志

由于所有的请求都是由网关处理的,因此日志也需要相对比较完善,比如接口的耗时、请求方式、请求IP、请求参数、响应参数(注意脱敏)等,另外由于可能涉及到很多微服务,因此需要提供一个统一的traceId方便关联所有的日志,可以将这个traceId 置于响应头中,方便排查问题。

隔离

比如线程池、http连接池、redis等应用层面的隔离,另外也可以根据业务场景,将核心业务部署带单独的网关集群,与其他非核心业务隔离开。

网关管控平台

这块也是非常重要的一环,需要考虑好整个流程的用户体验,比如接入到网关的这个流程,能不能尽量简化、智能,比如如果是 dubbo 接口,我们可以通过到git仓库中获取源码、解析对应的类、方法,从而实现自动填充,尽量帮用户减少操作;另外接口一般是从测试->预发->线上,如果每次都要填写一遍表单会非常麻烦,我们能不能自动把这个事情做掉,另外如果网关部署到了多个可用区、甚至不同的国家,那这个时候,我们还需要接口数据同步功能,不然用户需要到每个后台都操作一遍,非常麻烦。
这块个人的建议是直接参考阿里云、aws等提供的网关服务即可,功能非常全面。

其他

其他还有些需要考虑到的点,比如接口mock,文档生成、sdk代码生成、错误码统一、服务治理相关的等,这里就不累述了。

总结

目前的网关还是中心化的架构,所有的请求都需要走一次网关,因此当大促或者流量突增时,网关可能会成为性能的瓶颈,而且当网关接入的大量接口的时候,做好流量评估也不是一项容易的工作,每次大促前都需要跟业务方一起针对接口做压测,评估出大致的容量,并对网关进行扩容,而且网关是所有流量的入口,所有的请求都是由网关处理,要想准确的评估出容量很复杂。可以参考目前比较流行的 ServiceMesh,采用去中心化的方案,将网关的逻辑下沉到 sidecar 中,
sidecar 和应用部署到同一个节点,并接管应用流入、流出的流量,这样大促时,只需要对相关的业务压测,并针对性扩容即可,另外升级也会更平滑,中心化的网关,即使灰度发布,但是理论上所有业务方的流量都会流入到新版本的网关,如果出了问题,会影响到所有的业务,但这种去中心化的方式,可以先针对非核心业务升级,观察一段时间没问题后,再全量推上线。另外 ServiceMesh 的方案,对于多语言支持也更友好。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。