高校能力开放平台中的API网关设计与实现
2021-03-12冯骐沈富可
冯骐 沈富可
摘 要:能力开放已经成为高校信息化建设的重点,API体系的构建是能力开放的前提。传统的API构建模式依赖数据仓库,难以支持实时性、数据写入等需求,基于API网关的模型能够更好地解决这些问题。文章提供了API网关的设计方案,给出了具体的网关架构并解释了在API网关的架构下如何解决传统API构建模式面临的困难;明确了API网关需要支持的授权模型;列举了API网关在安全上需要实现的关键点。文章还通过开源和自研两个角度提供了API网关的实现方案,对主流的开源API网关进行了比较和讨论并在自研方案中对API网关关键技术的实现进行了描述,通过测试验证了实现方案的可行性。
关键词:API网关;能力开放;认证;授权;限流;熔断
中图分类号:TP311.5 文献标志码:A 文章编号:1673-8454(2021)03-0061-06
一、能力开放平台概述
近年来随着信息技术的不断发展,尤其是互联网服务在生活中的普遍应用,用户的信息素养也随之提高并养成了“互联网”式的使用习惯,因而对高校的信息化建设提出了更高的要求。传统信息系统的用户体验如何满足互联网时代用户的要求,成为当下高校信息化建设的痛点之一。而能力开放、引入竞争、共同开发是解决该痛点的有效手段。[1]能力开放是指通过数据的治理和业务的梳理,将核心数据与核心服务通过API[2]的形式开放,降低应用提供方参与信息化建设的门槛,引入更多的竞争,吸引各方面的开发者共同参与信息化建设,形成良性的信息化建设生态,提升信息化水平。
能力开放平台在互联网领域已经比较成熟,阿里、百度、腾讯等知名互联网企业都建设有自己的能力开放平台,并且建立了良好的开发者生态体系。例如阿里旗下有阿里云开发者平台、蚂蚁金服开放平台等;百度旗下有百度地图开放平台、百度AI开放平台等;腾讯旗下有微信开放平台和QQ开放平台等。以微信开放平台为例,根据2018年的《微信就业影响力报告》[3],2018年基于微信的小程序数量超过100万个,第三方服务商超过3万家,覆盖细分行业200余个。由于开放平台大幅降低了应用开发的门槛,大部分第三方服务商的规模不超过50人,近50%的小程序都能够在2周以内完成开发。可见能力开放能够显著地帮助开发者更简单更高效地参与应用建设。
实现能力开放平台的基础是各项数据和服务的API构建。传统的API构建模式大多基于全域的数据整合,核心是抓取各条线的业务系统数据,统一整合。本质上是先构建数据仓库,[4]再基于数据仓库构建API,其结构如图1所示。
这种模式的优点在于数据集,因此很容易实现跨业务的聚合API,API开发速度比较快,API风格也会比较统一。然而这种模式存在几个问题:①由于存在同步周期,API无法实时反馈数据,通常存在1天左右的延迟。②只支持数据查询API,不支持写入,因此多业务联动式(比如一站式平台)的API需求无法得到支持。③业务系统无法感知API调用过程,调用日志仅API模块可查。④当下高校信息化环境中,由于业务系统大多由业务部门主导建设,结合第三条,在业务系统升级变更时,容易导致数据同步失效,从而导致API失效。
本文观点是将API建设聚焦在认证、授权、限流、熔断等核心功能上,即构建API网关。具体的业务API交由业务系统本身实现,由API网关提供安全可控的转发。因此能够解决传统方案存在的问题。文章详述了API网关的架构设计并给出了具体的实现方案。
二、设计
本章将详述API网关的架构设计、授权模型和安全问题,给出了API网关的关键要素和参考模型。
1.API网关架构
每一个提供数据的业务系统都可以视为数据的“生产者”,每一个需求数据的业务系统也可以视为数据的“消费者”。连接“消费者”与“生产者”之间的是API网关。这看起来有点像企业服务总线(ESB),然而ESB更侧重企业内部的数据通讯,更注重协议转换、数据转换、服务编排、消息机制等,对应用的侵入性更强。而API网关更侧重接口的外部开放,更注重认证、授权、限流、熔断等,接口遵循REST API转发,对应用没有侵入性。典型的API 网关架构如图2所示。
对于接入API网关的业务系统,都必须提供REST API接口,但不必考虑认证、授权、限流等安全控制问题,这部分工作交由API网关来完成。无论外部应用请求还是内部应用请求,均通过API网关来统一授权。回顾传统模式下我们面临的4个问题,API网关模型的方案都能够很好地解决。①由于业务系统直接提供API,因此数据必然是真实的。②由于业务系统直接提供API,因此可以支持写入类的API服务。③所有通过授权的API请求都会转发到业务系统的API上,因此业务系统能够拿到全部合法的API调用日志。而不合法的请求部分已经被API网关拦截,事实上也降低了后端API的负担。④由于API由业务系统直接提供,因此在业务系统升级时,如果API发生变更,只需要重新发布API网关的路由即可,无需重新对接数据。事实上业务系统升级通常会考虑API向前兼容性(例如老版本API以/api/v1发布,新版本以/api/v2发布),因此这一切过程通常不会影响API服务的可用性。
2.授权模型
API网关的重要意义之一在于提供统一的授权模型,使不同后端API调用的开放模式保持一致,从而降低应用开发者的接入负担,也简化了权限管理的运维。从授权模式上来讲,应当尽可能选用互联网中公认的事实标准,简化应用的开发。根据OpenAPI[5]规范,授权方式大致可以分为4类:①HTTP authentication schemes,即HTTP header中含有Authorization字段。②API keys。③oAuth2 。④OpenID Connect Discovery。这其中前两种主要面向应用直接授权,即应用方作為客户端(后简称客户端)调用API时只需要携带约定的Authorization字段或者Key,后两种则需要用户进行授权允许之后,才能够获取token,并且该token只能查询授权用户相关的内容。API网关应该至少实现APIkeys和oAuth2这两种授权模式。
(1)APIKeys授权
APIkeys授权通常用于内部的数据交互,API网关通过实现约定的密钥直接授权给客户端,客户端在请求中携带事先约定的授权密钥即可以调用允许的API。可以放在查询参数或者Header中。图3展示了请求的示例。
每个接入API网关的客户端必须分配独立的密钥,由于密钥通常不设有效期,相当于一个永久性授权,因此从安全上考虑,通常对客户端再增加IP地址限制。即独立唯一的“密钥+合法的IP地址”才能合法地得到授权。
(2)OAuth2授权
OAuth2[6]是在互联网应用中广泛使用的授权模式。其特点是客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了4种授权方式:①授权码模式;②简化模式;③密码模式;④客户端模式。
授权码模式是标准的用户授权结构,客户端必须经过用户授权才能获取token;简化模式直接通过浏览器请求token,因此token对用户是可见的,存在一定的token泄露风险;密码模式中用户需要直接向客户端输入密码,而客户端必须承诺不会储存用户密码,通常不会采取这种模式;客户端模式无需用户授权就可以直接获取token,与APIkeys场景相类似,但是token存在有效期。API网关应该至少要实现授权码模式和客户端模式的oAuth2支持。
授权码模式(authorization code)的流程示意如图4所示。
其步骤如下:
(A)用户访问客户端,后者将前者导向认证服务器。
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客戶端事先指定的“重定向URI”(redirection URI),同时附上一个授权码。
(D)客户端收到授权码,附上早先的“重定向URI”,向认证服务器申请令牌。这一步是在客户端后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
客户端模式(Client Credentials Grant)的流程如图5所示。
其步骤如下:
(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
(B)认证服务器确认无误后,向客户端提供访问令牌。
3.安全问题
API网关与一般的反向代理的重大差别就在于他集成了授权和安全的功能,从而简化了后端API开发工作,可以更专注于业务本身。安全方面,API网关需要支持以下三个部分:①WAF防护;②请求限流;③超时熔断。
(1)WAF防护
REST API基于Web服务,因此也容易遭受各种Web上的攻击。尤其是注入类的攻击对后端API的危害较大,API网关层面的保护对提高整个API体系的安全性至关重要。我们可以在API网关内嵌入WAF模块来对请求的流量进行清洗。例如在一些基于lua和nginx的API网关结构中,可以直接为nginx增加一些第三方WAF模块来实现WAF防护支持。
另一种方案则是在API网关之前再叠加一层反向代理模式的WAF节点。这种模式会存在一个额外的节点,但是WAF本身能够与API网关松耦合,因此可以任意选择或者更换WAF,比如选择一些经过市场验证的商用化WAF产品。
(2)请求限流
API网关容易遭受的另一类攻击是各种拒绝服务(DoS)攻击,因此请求限流必不可少。同时请求量过高超过了后端服务能够承载的上限,也可能导致服务不可用,需要对服务进行降级限流。另一方面,由于应用的开发用途不同,限流的控制力度也有差异,因此需要对不同的应用提供区别的限流控制。
常见的限流算法有计数器、漏桶、令牌桶等,计数器算法限定一段时间内的请求总数,但是如果请求总数被提前耗尽,则剩余时间内无法完成任何请求,即“突刺现象”。漏桶算法[7]将所有请求先临时放在“桶”里,然后以恒定的速度处理请求,但是无法应对短时间的突发流量。令牌桶算法[8]以恒定的速率生产令牌放到“桶”中,处理请求时先获取令牌,再完成请求处理。因此如果“桶”本身是满的,那么就可以快速消耗掉所有令牌,从而支持突发流量请求。在令牌消耗完以后,由于令牌依然保持恒定速率生产,因此还可以继续保持一定的速率处理请求。
因此,API网关的请求限流必须要实现以下3点:①限流可以基于应用(即开发者账号)做区分限制。②支持令牌桶等限流算法以提供更好的响应服务。③限流算法中的数据存储基于外部服务(比如redis),API网关只做调用检查,保持网关本身无状态。④支持服务降级,在服务能力不足时降低服务等级以避免异常扩大化。
(3)超时熔断
熔断一词源于电子工程中的熔断器,即保险丝。当负载过大时保险丝烧毁断开电路以避免电路电器受损坏。由于API网关承载了整个能力开放平台的所有API服务,某一个后端API服务异常超时的时候必须不影响到其他的API服务。因此API网关也需要熔断的支持,在检测到某个后端API服务异常超时后,停止继续转发数据,避免因大量的超时堆积线程而导致网关服务不可用。这样也能够降低故障后端的负载,从而帮助其更快地恢复服务。熔断的算法模型如图6所示。
当后端API的超时越过一定阈值之后,进入熔断打开模式,在熔断时间内所有转发给该服务的请求都直接返回500错误。当熔断时间结束后,进入熔断半打开模式,随机的挑选部分请求进入后端,如果请求返回成功,则进入熔断关闭模式,完全恢复服务。如果请求依然超时失败,则回到熔断打开模式继续阻断请求。
三、实现
API网关作为微服务整合的重要组件,在互联网领域已经有许多实现方案,其中部分已经开源。本文从功能、性能等方面对比了一些主流的开源API网关,讨论了在高校应用开源方案的可行性;也给出了自研API网关中的关键技术实现方案,并提供了测试数据验证了可行性。
1.开源实现方案
由于API网关在互联网服务中的普遍应用,业内已经存在一些开源方案,这里选取了比较典型且风格差异较大的三种讨论:①基于OpenResty的Kong。②基于Go语言的Tyk。③基于JVM的Zuul。
Kong是一个基于OpenResty[9]的开源API网关。OpenResty是一个基于Nginx和Lua的高性能Web平台。其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依賴项。它能够让业务逻辑通过Lua动态脚本的方式直接运行在Nginx内部,利用Nginx的非阻塞I/O模型和各种现有模块,实现高性能且灵活的Web开发。Kong就是在OpenResty基础上通过lua脚本实现网关功能,并且通过插件机制能够实现很好的扩展支持。其中API反向代理转发部分通过Nginx实现,认证授权、限流、熔断、WAF等均通过对应的插件实现。但插件通常并不能100%符合实际需求,比较好的应用还是需要能够对lua脚本进行一些二次开发。例如oAuth插件只负责了授权部分,当出于客户端授权码模式,用户认证的部分还是需要自己实现一个认证接口。Kong的商业版本提供了一个Dashboard的UI,开源版本则必须通过API进行配置。
Tyk是一个基于Go[10]语言开发的API网关,也有相当好的性能。Tyk也支持插件模式,插件可以用Lua、Python或者JavaScript等解释性语言来写,通过插件可以扩展后端服务支持gRPC。Tyk的主要功能都通过主程序直接支持,插件主要用于额外的功能,比如为oAuth授权中的认证添加认证接口。Tyk也有商业版本,其免费版本限制只能部署一个单机节点,不支持多机部署。但是Tyk的免费版本也提供Dashboard UI。
Zuul是由Netflix公司开源的API网关,是Netflix开源的SpringCloud微服务框架中的一个组件。它实际上不是一个完整的产品,需要结合SpringCloud中的其他组件共同开发完成。如果项目本身采用SpringCloud,那么结合Zuul会非常简单和快捷。
表1对比了三种API网关的主要差异。
2.自研实现方案
开源的API网关方案虽然基本都能够满足需求,然而由于开源软件需要综合考虑绝大部分用户的需求,因此设计会比较复杂,配置比较繁重,导致学习曲线比较陡峭。同时有些偏个性化内容,开源软件通常也无法直接支持,需要编写插件或自己二次开发实现,因此即便选用开源方案,也还是需要有一定的软件开发基础,否则很难发挥出软件的优势。
另一方面,如果我们只需要简单实现一个API网关,不需要考虑过多的全面性,自研开发也是一种选择。实际上基于Zuul的API网关方案已经非常接近基于SpringCloud进行开发了,由于技术栈偏好的差异,本文讨论通过Go语言自研开发API网关的一些关键技术。
我们使用Go语言中的Gin框架开发API网关的Web服务,使用MySQL储存配置信息,使用redis作为外部组件提供缓存,并配合限流算法进行限流。
API网关首先是一个HTTP服务的反向代理服务器。因此我们需要先实现API请求的反向代理。Go语言的HTTP标准库对http服务有非常完整的支持,其中就自带了反向代理的功能。而Gin框架是net/http包的一个封装,兼容Go的HTTP标准库,因此只需要调用httputil.ReverseProxy就能够完成反向代理API请求的功能。
Gin可以通过中间件(middware)的方式对HTTP路由增加授权支持。我们只需要将授权的代码通过中间件的形式加载到每一个需要授权的路由上即可。其中APIKeys用于授权的Key、oAuth2分配的client_id和client_secret存在MySQL中,生成的token则放在redis内,通过redis的key有效期自动实现token的过期。在oAuth2的授权码模式中,认证部分与学校的统一身份认证进行集成。
限流算法采用令牌桶算法,令牌计数器和时间计数器均储存在redis中。由于redis是单线程的,天然拥有并发下的原子性,可以确保多台水平扩展的API网关的限流策略一致。
熔断在SpringCloud中有一个知名的开源组件hystrix,现在它也有Go语言的版本hystrix-go,所以只需要用hystrix-go嵌入代码就能很快实现熔断功能。
由于目前Golang生态中尚缺乏优秀的WAF模块,所以我们没有在网关中嵌入WAF,而使用外置WAF反向代理API网关的模式发布服务。这样实际上https卸载和IP黑名单也可以由WAF来完成,API网关本身可以简化。在我们的生成环境中,我们采用了一款商用WAF产品作为API网关的服务发布。
整个开发架构如图7所示。
3.性能测试
API网关由于需要承载所有后端API的请求,因此性能不可以存在瓶颈。我们使用一台4核心CPU、16G、50G硬盘的服务器对自研的API网关和开源API网关进行了性能对比。由于Zuul需要开发集成才能使用,因此这里只对比了Kong和Tyk。所有的软件都基于Docker部署。测试对比了无认证授权下的性能与APIkeys下的性能对比。由于oAuth2需要另外开发认证接口,未测试oAuth2部分的性能,但由于换取到access_token后,oAuth2下的令牌检查与APIkeys没有实质差异,因此其性能应该与APIkeys相仿。
测试基于wrk,采用60秒100个并发请求。结果如图8所示。
基于Nginx的Kong性能还是最好的,自研的性能略低一些,但比Tyk的性能好,能够满足生产环境的性能要求。当然原因是自研方案结构简单,功能相对Tyk比较少。后续加入更多的功能模块,例如性能埋点、格式化日志等之后,性能可能会随之有所下降。但是轻量化开发、快速迭代本来就是自主研发的特点。先搭建框架,实现基本功能,后续根据实际需要增加功能模块是比较务实的自研模式。
四、结语
API网关是高校构建能力開放平台的核心,也是进一步实现高校信息化互联互通、一站式服务的基础。基于API网关的方案可以很好地解决传统模式下面临的一些问题:
(1)API数据的实时性问题——由于API网关方案直接转发业务方API接口,不存在数据同步。所以能够天然支持数据实时性。
(2)数据写入问题——由于API网关方案直接转发业务方API接口,因此只要业务API提供数据写入功能,API网关即可以将其发布。
(3)业务方调用日志问题——API网关采取反向代理模式,业务方无需依赖网关也能够获取完整的请求日志。
(4)升级变更的问题——API网关提供了强的用户感知度。并且给予的反向代理模式能够很快切换API路径,因此能够快速响应业务接口的升级变更影响。
本文详述了API网关的设计模式和关键要素,并给出了包含开源和自研两种实施方案。对高校API网关的构建具有一定的参考价值,对商业API网关产品的服务定位和开发也有一定的参考意义。
本文给出的自研实现方案基于Golang语言、redis和MySql技术栈,对其他技术栈的开发者参考价值相对较小。但是实现的算法和思路没有技术栈绑定,使用任何技术栈开发都可以重新实现。
参考文献:
[1]马琳,宋俊德,宋美娜.开放平台:运营模式与技术架构研究综述[J].电信科学,2012(6):125-140.
[2]冯骐,马晨辉,沈富可.基于Metadata的监控数据 API设计与实现[J].四川大学学报(自然科学版),2019(3):431-436.
[3]中国信息通信研究院,腾讯.微信就业影响力报告[R/OL]. http://www.caict.ac.cn/kxyj/qwfb/ztbg/201903/P020190304620742061060.pdf.
[4]张宁,贾自艳,史忠植.数据仓库中ETL技术的研究[J].计算机工程与应用,2002(24):213-216.
[5]Luis López-Fernández,Boni García,Micael Gallego,et al.Designing and evaluating the usability of an API for real-time multimedia services in the Internet[J]. Multimedia Tools and Applications,2017,76(12):14247-14304l.
[6]时子庆,刘金兰,谭晓华.基于OAuth2.0的认证授权技术[J].计算机系统应用,2012(3):260-264.
[7]蒋志刚,李乐民.ATM网络中突发业务的漏桶算法分析[J].电子学报,1995(1):8-14.
[8]李晓利,郭宇春.QoS技术中令牌桶算法实现方式比较[J].中兴通讯技术,2007(3):56-60.
[9]靳莹.基于缓存技术的内容管理系统研究[D].长春:吉林大学,2014.
[10]Peter H.Welch,Adam T.Sampson,Jan B,et al.Serving Web Content with Dynamic Process Networks in Go[J].Concurrent Systems Engineering Series,2011:68.
(编辑:王天鹏)