【.com原稿】随着互联网技术的飞速发展,各种网上业务蓬勃发展,软件系统如雨后春笋般出现在我们面前。图片来自Pexels为了提高系统的性能和可靠性,将应用服务拆分成微服务。API网关作为系统入口,逐渐成为标配。今天我们就来看看API网关的设计思路。我们需要承载哪些功能?以及如何选择流行的API网关?什么是API网关?由于我需要一个API网关供我使用,所以我们先了解一下什么是API网关。什么是API网关?网关这个词最早出现在网络设备中,比如两个独立的局域网通过路由器进行通信,中间的路由称为网关。任何一个应用系统如果需要被其他系统调用,就需要对外暴露API,这些API一个一个代表功能点。如果两个系统之间存在通信,则在系统之间添加一个中介来辅助API调用。这个中介是一个API网关。连接两个系统的API网关当然,API网关可以放在两个系统之间,也可以放在客户端和服务端之间。连接客户端和服务端的API网关知道了API网关的基本定义,接下来我们来看看为什么要使用它。为什么要使用API??网关网关是系统的唯一入口,即所有进入系统的请求都需要经过API网关。当系统外的应用程序或客户端访问系统时,会遇到这样一种情况:系统需要判断他们的权限。如果传输协议不一致,需要转换协议。如果调用水平扩展的服务,需要做负载均衡。一旦请求的流量超出系统范围,就需要进行限流操作。对于每一个请求和回复,系统都会记录响应日志。也就是说,只要是涉及到对系统的请求,能够从业务中提取出来的,都有可能在网关上实现。例如:协议转换、负载均衡、请求路由、流量控制等,这些功能我们后面会一一为大家介绍。了解了APIGateway的基本功能后,我们来看看它可以服务于哪些系统或客户端。API网关服务定位API网关具有处理请求的能力,从定位的角度可以分为5类:①对于WebApp,这部分系统主要是基于网站和H5应用。通过前后端分离的设计,将大部分业务功能放在后端,前端WebApp只展示页面内容。②MobileApp,其中Mobile是指iOS和Android,设计思路与WebApp基本一致。不同的是APIGateway需要做一些移动设备管理(MDM)。例如:设备注册、激活、使用、淘汰等,全生命周期管理。由于移动设备的特殊性,我们在考虑移动设备请求时,需要考虑请求、设备、用户之间的关系。③OpenAPIforpartners,通常系统会为合作伙伴提供接口。这些接口将全部开放或部分开发,在有条件限制(时间、流量)下供合作伙伴访问。因此,需要更多考虑API网关的流量和安全,以及协议转换的管理。④API可以在企业内部进行扩展,供企业内部的其他部门或项目使用,也可以作为中台输出的一部分,支持其他系统。这里需要考虑更多的是功能边界的划定、认证和授权的问题。⑤对于IOT设备,会接收来自IOT设备的请求,尤其是工业传感器等设备。这里需要考虑协议转换和数据过滤。APIGateway架构说完了APIGateway的功能和定位,接下来说说它的架构:APIGateway系统架构图APIGateway分为3个系统:Gateway-Core(核心)Gateway-Admin(管理)Gateway-监控(Monitoring)网关-Core核心网关负责接收客户端请求,调度、加载和执行组件,将请求路由到上游服务器,处理返回结果。大部分功能都在这一层完成,例如:验证、鉴权、负载均衡、协议转换、服务路由、数据缓存。它也可以在没有其他两个子系统的情况下单独运行。Gateway-Admin网关管理界面,可配置API、组件等系统基础信息;例如:限流策略、缓存配置、告警设置等。Gateway-Monitor监控日志,生成各种运维管理报表,自动告警等;管理监控系统主要服务于核心系统,起支撑作用。上面说的API网关的技术原理就是网关的架构思想。下面是一些技术原理。通常我们在使用网关的时候,更多的是关注它的功能。比如:路由、负载均衡、限流、缓存、日志、发布等。其实这些功能背后都有一些原理我们是可以理解的,这样我们在应用功能的时候就会更有把握。这里有几个原则与大家分享。协议转换各系统内部服务之间的调用可以统一使用一种协议,如HTTP、GRPC。假设各个系统使用的协议不同,那么系统之间的调用或者数据传输就存在协议转换的问题。如何解决这个问题呢?API网关通过泛化调用实现协议之间的转换。其实就是把不同的协议转换成“通用协议”,再把通用协议转换成本地系统可以识别的协议。这种转换工作通常是在API网关完成的。常见协议中常用JSON,当然也有使用XML或者自定义JSON文件的。不同的协议需要转化为通用的语言进行传输。链式处理的设计模式中有责任链模式,将“处理请求”和“处理步骤”分开。对于每个处理步骤,我们只关心这一步需要做的处理操作,有一个处理步骤的顺序。消息从第一个“处理步骤”流入,从最后一个“处理步骤”流出。每一步都对传递过来的消息进行处理,整个过程形成一个链条。API网关中使用了类似的模式。Zuul网关过滤链处理我们以Zuul为例。当消息进入或离开网关时,需要经过一系列过滤器。这些filter之间是有先后顺序的,每个filter需要做的工作也不同:PRE:pre-filter,用来处理一般事务,比如鉴权,限流,降级熔断,缓存。并且可以通过自定义过滤器进行扩展。ROUTING:路由过滤器,其中用户请求被发送到OriginServer。它主要负责:协议转换和路由。POST:后置过滤器,OriginServer返回的响应信息会经过它,然后返回给调用者。在返回的Response中添加ResponseHeader,同时可以做Response的统计和日志记录。ERROR:错误过滤器,当以上三个过滤器出现异常时,错误信息会进入这里,错误会被处理。异步请求所有请求都通过API网关访问应用服务。一旦吞吐量增加,如何高效地处理这些请求?以Zuul为例,Zuul1采用:一个线程处理一个请求。线程负责接受请求,然后调用应用程序返回结果。如果将网络请求视为IO操作,则处理该请求的线程会被阻塞,从接受请求到返回服务的响应。同时,如果多个线程处于这种状态,会导致系统变慢。因为每个网关能开启的线程数是有限的,尤其是在访问高峰期。每个线程处理一个请求为了解决这个问题,Zuul2开启了异步请求的机制。当每一个请求进入网关后,都会被打包成一个事件,CPU内核会维护一个监听器不断轮询“请求事件”。一旦找到请求事件,就会调用相应的应用程序。获取到应用返回的信息后,根据请求将数据/文件放入指定的缓冲区,同时发送一个通知事件,告诉请求方数据已经准备好,可以获取数据/文件了从这个缓冲区。这个过程是异步的,请求线程不必等待数据返回。请求完成后直接返回,然后就可以做其他事情了。当请求的数据被CPU内核获取到并发送到指定的数据缓冲区时,请求线程会收到“数据返回”的通知,然后直接使用数据,而无需自己进行取数据操作。异步请求处理,CPU处理完数据后,通知请求方进行请求的异步处理。有两种模式,分别是:ReactorProactorReactor工作原理流程图Reactor:通过handle_events事件循环处理请求。用户线程注册事件处理程序后,可以继续(异步)执行其他工作,Reactor线程负责调用内核的Select函数查看Socket状态。当一个Socket被激活(获取网络数据)时,会通知对应的用户线程,执行handle_event读取和处理数据。Proactor工作原理流程图Proactor:用户线程使用CPU内核提供的异步IO发起请求,请求发起后立即返回。CPU内核继续执行用户请求的线程代码。此时,用户线程已经向内核注册了AsynchronousOperation(异步处理)和CompletionHandler(完成资源获取)。之后,操作系统启动一个独立的内核线程来处理IO操作。当请求的数据到达时,内核负责读取Socket(网络请求)中的数据,写入用户指定的缓冲区。最后,内核将数据和用户线程注册的CompletionHandler分发给内部的Proactor,Proactor将IO完成信息通知给用户线程(一般通过调用用户线程注册的完成事件处理函数)来完成异步IO。API网关实现功能说起API网关的使用,大家更感兴趣的是具体的功能。让我们来看看它做了什么。负载均衡当同一个应用的多个副本挂载到网关后面时,每个用户的请求都会通过网关的负载均衡算法路由到对应的服务上。例如:随机算法、权值算法、Hash算法等。如果上游服务采用微服务架构,也可以配合注册中心实现动态负载均衡。当微服务动态挂载(动态扩容)时,可以通过服务注册中心获取微服务的注册信息,实现负载均衡。Nginx+Lua+服务注册中心实现动态负载均衡路由选择不言而喻。网关可以分析请求的URL地址,知道需要访问的服务。然后通过路由表将请求路由到目标服务。有时由于网络原因,服务可能会暂时不可用。这时,我们希望再次重试该服务。Zuul充当API网关,将请求路由到上游服务器。例如:Zuul配合SpringRetry完成路由重试。#是否开启重试功能zuul.retryable=true#当前服务ribbon的重试次数。MaxAutoRetries=2流量控制和限流是API网关常用的功能之一。当上游服务超出请求范围,或者服务由于某些原因不能正常使用时,会导致服务处理能力下降。此时,API网关充当“看门人”的角色,限制传入的请求,保护应用服务器不受冲击。限流其实就是限制传入请求的数量。算法有很多,如令牌桶算法、漏桶算法、连接数限制等。这里介绍三个常用的,一般都是通过Nginx+Lua实现的。令牌桶限流统一认证所有访问应用服务器的请求都需要有一定的权限。如果每次访问服务都需要验证权限,这对效率影响很大。可以在API网关上进行授权认证。目前比较普遍的做法是,用户通过登录服务获取Token,存储在客户端,将Token放在每次请求的请求头中,一起发送给服务端。APIGateway要做的就是解析Token,知道访问者是谁(认证),他能做什么/访问什么(权限)。说白了就是看访问者可以访问哪些网址。这里,访问列表是根据权限/角色定义的。如果要实现多系统的OSS(SingleSignOn),API网关需要连接CAS(CentralAuthenticationService)来判断请求者的身份和权限。熔断降级当应用服务出现异常,无法继续提供服务时,即应用服务不可用。作为API网关,需要处理将请求导入其他服务。或者降级服务,例如:返回客户端完整的服务数据,或者提示服务暂时不可用。同时,通过服务注册中心,对出现问题的服务进行监控。一旦服务恢复,路由请求将恢复到服务中。例如:Zuul提供了ZuulFallbackProvider接口来实现熔断。它提供了两种方法,一种是指定融合拦截的服务getRoute,另一种是指定返回内容ClientHttpResponse。publicinterfaceZuulFallbackProvider{/***Theroutethisfallbackwillbeusedfor.*@returnTheroutethefallbackwillbeusedfor.*/publicStringgetRoute();/***Providesafallbackresponse.*@returnThefallbackresponse.*/publicClientHttpResponsefallbackResponse();}我们传递一个自定义,并赋值给一个Fallback方法,使用Route实现Route访问问题的熔断处理。主要通过继承ZuulFallbackProvider接口实现。ZuulFallbackProvider默认有两个方法,一个用来标明哪个服务被断路器拦截,另一个是自定义返回内容。发布版本时会用到API网关熔断降级的发布测试:金丝雀发布和蓝绿发布。路由和流量切换可以作为API网关来辅助上述行为。这里我们以金丝雀发布为例,看看API网关是如何进行路由转换的。假设有4个服务从V1更新到V2,这4个服务的流量请求由1个API网关管理。然后先断开一个服务与API网关的连接,部署该服务的V2版本,然后API网关将流量导入到该服务的V2版本。这里的流量导入可以逐步进行,待V2版本服务趋于稳定后。再次做同样的事情,用V2版本替换其他服务。金丝雀发布一般从一台服务器开始,或者是一小部分,比如2%的服务器,主要是做流量验证,也叫金丝雀(canary)测试(灰度测试)。它的由来是矿工在离开矿井前,放了一只金丝雀,检查是否有毒气,因此金丝雀放生而得名。金丝雀测试需要综合监控设施的配合。通过监控指标的反馈,可以观察金丝雀的健康状态,作为后续发布或回滚的依据。如果金线测试通过,则所有剩余的V1版本将升级到V2版本。如果金丝雀测试失败,金丝雀直接回滚,发布失败。缓存数据我们可以在API网关中缓存一些不经常修改的数据。比如:用户信息,配置信息,通过服务定期刷新缓存就可以了:用户先请求访问API网关,如果有缓存信息,就直接返回给用户。如果没有找到缓存信息,则返回应用服务器获取信息。另外还有缓存更新服务,定时更新应用服务器中的信息到网关本地缓存中。日志记录通过API网关上的过滤器,我们可以加入日志服务来记录请求和返回信息。同时可以建立一个管理员接口来监控这些数据。记录日志后,可以做很多功能扩展。我们整理了以下几点供大家参考:报表分析:提供服务访问状态的可视化展示。实时查询:实时了解吞吐量、并发度等关键信息。将特别注意秒杀活动。异常告警:监控关键参数,支持统计结果阈值告警,连接阿里云通知中心、短信、钉钉告警。日志投递:将日志归档,存放在文件库或数据仓库中,以供后续分析。日志派生功能流行API网关对比介绍完API网关的功能,我们再来看几个流行的API网关项目。看一下它们各自的特点,对它们做一个简单的比较。这些网关目前都是开源的,大家可以在项目中选择性的使用。KongKong是Mashape公司的一个开源项目。它是一个运行在Nginx中的Lua应用,可以通过Lua-Nginx模块进行扩展。因此可以通过插件合集来定制功能,例如:HTTP基础认证、密钥认证、CORS(Cross-originResourceSharing,跨域资源共享)、TCP、UDP、日志、API限流、请求转发和监控,这些都是现有的插件。因为它是基于Nginx的,网关可以横向扩展来处理大量的网络请求。Kong架构图Kong主要有三个组件:KongServer:基于Nginx的服务器,用于接收API请求。ApacheCassandra/PostgreSQL:用于存储运行数据。Kongdashboard:UI管理工具。TraefikTraefik架构图Traefik是一个HTTP反向代理和负载均衡器,可以轻松部署微服务并与现有组件(Docker、Swarm、Kubernetes、Marathon、Consul、Etcd)集成。因为它支持动态配置,所以扩展性很好。不过它只支持HTTP、HTTPS和GRPC。如果需要TCP负载均衡,那么就需要选择其他方案。AmbassadorAmbassador架构图Ambassador是一个基于EnvoyProxy构建的Kubernetes原生开源微服务网关。它是从头开始构建的,旨在支持需??要为最终用户快速发布、监控和更新服务的多个独立团队。Ambassador还具有KubernetesIngress和负载均衡功能。支持KubernetesIngressController、负载均衡等处理功能,可与Istio无缝集成。ZuulZuul2结构图Zuul是SpringCloud全家桶中的一个微服务API网关。来自设备或网站的所有请求都通过Zuul到达后端的Netflix应用程序。作为边界应用程序,Zuul提供动态路由、监控、弹性负载和安全功能。包括Zuul1和Zuul2版本。介绍完几款开源API网关的基本信息后,我们从几个维度进行比较:在开源社区活跃度方面,Kong和Traefik更胜一筹;在成熟度上,Kong和Traefik更好;从架构优势的可扩展性来看,Kong有丰富的插件,Ambassador也有插件但不多,Zuul需要自研。但是由于Zuul是集成了SpringCloud的,如果你使用SpringCloud,可以考虑使用。总结API网关是系统内外通信的中介。在定位上,它服务于WebApp、MobileApp、合作伙伴OpenAPI、企业内部的可扩展API、IOT设备。从架构设计的角度,分为三部分:Gateway-Core(核心)、Gateway-Admin(管理)、Gateway-Monitor(监控)。API网关需要关注的技术原理包括协议转换、链式处理、异步请求等。应用广泛,如:负载均衡、路由选择、流量控制、统一认证、熔断降级、发布测试、缓存数据、日志记录等。比较流行的开源API网关有Kong、Traefik、Ambassador和祖尔。在使用上,它们各有千秋,可根据工程情况选用。作者:崔浩简介:十六年开发架构经验。曾在惠普武汉交付中心担任技术专家、需求分析师、项目经理,后在一家初创公司担任技术/产品经理。善于学习,乐于分享。目前专注于技术架构和研发管理。【原创稿件,合作网站转载请注明原作者和出处为.com】
