跳转至

美团百亿规模 API 网关服务 Shepherd 的设计与实现

在微服务架构下,服务拆分会让 API 的规模成倍增长,使用 API 网关来管理 API 逐渐成为一种趋势。美团统一 API 网关服务 Shepherd 就是在这种背景下应运而生,适用于美团业务且完全自研,用于替换传统的 Web 层网关应用,业务研发人员通过配置的方式即可对外开放功能和数据。本文将介绍美团统一 API 网关诞生的背景、关键的技术设计和实现,以及 API 网关未来的规划,希望能给大家带来一些帮助或者启发。

一、背景介绍

1.1 API 网关是什么 API 网关是随着微服务(Microservice)概念兴起的一种架构模式。原本一个庞大的单体应用(All in one)业务系统被拆分成许多微服务(Microservice)系统进行独立的维护和部署,服务拆分带来的变化是 API 的规模成倍增长,API 的管理难度也在日益增加,使用 API 网关发布和管理 API 逐渐成为一种趋势。一般来说,API 网关是运行于外部请求与内部服务之间的一个流量入口,实现对外部请求的协议转换、鉴权、流控、参数校验、监控等通用功能

1.2 为什么要做 Shepherd API 网关? 在没有 Shepherd API 网关之前,美团业务研发人员如果要将内部服务输出为对外的 HTTP API 接口。通常要搭建一个 Web 应用,用于完成基础的鉴权、限流、监控日志、参数校验、协议转换等工作,同时需要维护代码逻辑、基础组件的升级,研发效率相对比较低。此外,每个 Web 应用都需要维护机器、配置、数据库等,资源利用率也非常差

美团内部一些业务线苦于没有现成的解决方案,根据自身业务特点,研发了业务相关的 API 网关。放眼业界,亚马逊、阿里巴巴、腾讯等公司也都有成熟的 API 网关解决方案。

因此,Shepherd API 网关项目正式立项,我们的目标是为美团提供高性能、高可用、可扩展的统一 API 网关解决方案,让业务研发人员通过配置的方式即可对外开放功能和数据。

img

1.3 使用 Shepherd 带来的收益是什么?

从业务研发人员的角度来看,接入 Shepherd API 网关,能带来哪些收益呢?简而言之包括三个方面。

  • 提升研发效率

    • 业务研发人员只需要通过配置的方式即可快速开放服务接口。
  • Shepherd 统一提供鉴权、限流、熔断等非业务基础能力。
  • Shepherd 支持业务研发人员通过开发自定义组件的方式扩展 API 网关能力。

  • 降低沟通成本

    • 业务研发人员配置好 API,可以自动生成 API 的前后端交互文档和客户端 SDK,方便前后端开发人员进行交互、联调。
  • 提升资源利用率

    • 基于 Serverless 的架构思想,实现 API 全托管,业务研发人员无需关心机器资源问题。

二、技术设计与实现

2.1 整体架构 我们先来看看 Shepherd API 网关的整体架构,如下图所示

img

Shepherd API 网关的 控制面 由 Shepherd 管理平台和 Shepherd 监控中心组成。管理平台主要完成 API 的全生命周期管理以及配置下发的工作,监控中心完成 API 请求监控数据的收集和业务告警功能。

Shepherd API 网关的 配置中心 主要完成控制面与数据面的信息交互,通过美团统一配置服务 Lion 来实现。

Shepherd API 网关的 数据面 也就是 Shepherd 服务端。一次完整的 API 请求,可能是从移动应用、Web 应用,合作伙伴或内部系统发起,经过 Nginx 负载均衡系统后,到达服务端。服务端集成了一系列的基础功能组件和业务自定义组件,通过泛化调用请求后端 RPC 服务、HTTP 服务、函数服务或服务编排服务,最后返回响应结果。

下面我们将针对这三个主要模块做详细的介绍。

2.1.1 控制面 使用 API 网关的控制面,业务研发人员可以轻松的完成 API 的全生命周期管理,如下图所示

img

业务研发人员从创建 API 开始,完成参数录入、DSL 脚本生成;接着可以通过文档和 MOCK 功能进行 API 测试;API 测试完成后,为了保证上线稳定性,Shepherd 管理平台提供了发布审批、灰度上线、版本回滚等一系列安全保证措施;API 运行期间会监控 API 的调用失败情况、记录请求日志,一旦发现异常及时发出告警;最后,对于不再使用的 API 进行下线操作后,会回收 API 所占用的各类资源并等待重新启用。

整个生命周期,全部通过配置化、流程化的方式,由业务研发人员全自助管理,上手时间基本在 10 分钟以内,极大地提升了研发效率。

2.1.2 配置中心

API 网关的配置中心存放 API 的相关配置信息——使用自定义的 DSL(Domain-Specific Language,领域专用语言)来描述,用于向 API 网关的数据面下发 API 的路由、规则、组件等配置变更。

配置中心的设计上使用统一配置管理服务 Lion 和本地缓存结合的方式,实现动态配置,不停机发布。API 的配置如下图所示:

img

API 配置的详细说明:

  • Name、Group :名字、所属分组。
  • Request :请求的域名、路径、参数等信息。
  • Response :响应的结果组装、异常处理、Header、Cookies 信息。
  • Filters、FilterConfigs :API 使用到的功能组件和配置信息。
  • Invokers :后端服务(RPC/HTTP/Function)的请求规则和编排信息。

2.1.3 数据面 API 路由 API 网关的数据面在感知到 API 配置后,会在内存中建立请求路径与 API 配置的路由信息。通常 HTTP 请求路径上,会包含一些路径变量,考虑到性能问题,Shepherd 没有采用正则匹配的方式,而是设计了两种数据结构来存储。如下图所示

img

一种是不包含路径变量的直接映射的 MAP 结构。其中,Key 就是完整的域名和路径信息,Value 是具体的 API 配置。

另外一种是包含路径变量的前缀树数据结构。通过前缀匹配的方式,先进行叶子节点精确查找,并将查找节点入栈处理,如果匹配不上,则将栈顶节点出栈,再将同级的变量节点入栈,如果仍然找不到,则继续回溯,直到找到(或没找到)路径节点并退出。功能组件 当请求流量命中 API 请求路径进入服务端,具体处理逻辑由 DSL 中配置的一系列功能组件完成。网关提供了丰富的功能组件集成,包括链路追踪、实时监控、访问日志、参数校验、鉴权、限流、熔断降级、灰度分流等,如下图所示:

img 协议转换&服务调用 API 调用的最后一步,就是协议转换以及服务调用了。网关需要完成的工作包括:获取 HTTP 请求参数、Context 本地参数,拼装后端服务参数,完成 HTTP 协议到后端服务的协议转换,调用后端服务获取响应结果并转换为 HTTP 响应结果。

img

上图以调用后端 RPC 服务为例,通过 JsonPath 表达式获取 HTTP 请求不同部位的参数值,替换 RPC 请求参数相应部位的 Value,生成服务参数 DSL,最后借助 RPC 泛化调用完成本次服务调用。

2.2 高可用设计 Shepherd API 网关作为接入层的基础组件,高可用性一直是业务研发人员非常关心的部分。接下来。我们就来探索一下 Shepherd 在高可用设计方面的实践

2.2.1 排除性能隐患 一个高可用的系统,预防故障的发生,首先要排除性能隐患,保证高性能

Shepherd 对 API 请求做了全异步化处理,请求通过 Jetty IO 线程异步提交到业务处理线程池,调用后端服务使用 RPC 或 HTTP 框架的异步方式,释放了由于网络等待引起的线程占用,使线程数不再成为网关的瓶颈。下图是使用 Jetty 容器时,服务端的请求线程处理逻辑:

img

我们通过域名压测网关单机的端到端 QPS,发现 QPS 在超过 2000 时,会出现很多超时错误,而网关的服务端负载与性能却非常富余。调研发现,公司内其他的 Web 应用都存在这个问题,与 Oceanus 团队进行联合排查后,发现是 Nginx 与 Web 应用之间的长连接功能没有打开,且无法配置。Oceanus 团队经过紧急排期,研发并上线长连接功能后,Shepherd 端到端的 QPS 成功提升到了 10000 以上。

另外,我们对 Shepherd 服务端进行了 API 请求预热的优化,使得网关启动时能立刻达到最佳性能,减少毛刺的发生。然后,通过压测时的 CPU 热点排查,将性能瓶颈找出,减少主链路上的本地日志打印,对请求日志进行异步化、远程化改造。Shepherd 端到端的 QPS 再次提升 30%以上。

在 Shepherd 服务上线稳定运行一年以后,我们再次对性能进行优化,并且做了一次网络框架升级,将 Jetty 容器全面替换为 Netty 网络框架,性能提升 10%以上,Shepherd 端到端的 QPS 成功提升到 15000 以上。下图是使用 Netty 框架时,服务端的请求线程处理逻辑:

img

2.2.2 服务隔离 集群隔离 借鉴公司缓存、任务调度等成熟组件的经验,Shepherd 在设计之初,就考虑了按业务线维度进行集群隔离,也支持重要业务独立部署。如下图所示

img 请求隔离 服务节点维度,Shepherd 支持请求的快慢线程池隔离。快慢线程池隔离主要用于一些使用了同步阻塞组件的 API,例如 SSO 鉴权、自定义鉴权等,可能导致长时间阻塞共享业务线程池。

快慢隔离的原理是统计 API 请求的处理时间,将请求处理耗时较长,超过容忍阈值的 API 请求隔离到慢线程池,避免影响其他正常 API 的调用。

除此之外,Shepherd 也支持业务研发人员配置自定义线程池进行隔离。具体的线程隔离模型如下图所示:

img

2.2.3 稳定性保障

Shepherd 提供了一些常规的稳定性保障手段,来保证自身和后端服务的可用性。如下图所示:

img

  • 流量管控 :从用户自定义 UUID 限流、App 限流、IP 限流、集群限流等多个维度提供流量保护。
  • 请求缓存 :对于一些幂等的、查询频繁的、数据及时性不敏感的请求,业务研发人员可开启请求缓存功能。
  • 超时管理 :每个 API 都设置了处理超时时间,对于超时的请求,进行快速失败的处理,避免资源占用。
  • 熔断降级 :支持熔断降级功能,实时监控请求的统计信息,达到配置的失败阈值后,自动熔断,返回默认值。

2.2.4 请求安全 请求安全是 API 网关非常重要的能力,Shepherd 集成了丰富的安全相关的系统组件,包括有基础的请求签名、SSO 单点登录、基于 SSO 鉴权的 UAC/UPM 访问控制、用户鉴权 Passport、商家鉴权 EPassport、商家权益鉴权、反爬等等。业务研发人员只需要简单配置,即可使用

2.2.5 可灰度 API 网关作为请求入口,往往肩负着请求流量灰度验证的重任。灰度场景 Shepherd 在灰度能力上,支持灰度 API 自身逻辑,也支持灰度下游服务,也可以同时灰度 API 自身逻辑和下游服务。如下图所示

img

灰度 API 自身逻辑时,通过将流量分流到不同的 API 版本实现灰度能力;灰度下游服务时,通过给流量打标,分流到指定的下游灰度单元中。灰度策略 Shepherd 支持丰富的灰度策略,可以按照比例数灰度,也可以按照特定条件灰度。

2.2.6 监控告警 立体化监控 Shepherd 提供 360 度的立体化监控,从业务指标、机器指标、JVM 指标提供 7x24 小时的专业守护,如下表

img 多维度告警 有了全面的监控体系,自然少不了配套的告警机制,主要的告警能力包括:

img

2.2.7 故障自愈 Shepherd 服务端接入了弹性伸缩模块,可根据 CPU 等指标进行快速扩容、缩容。除此之外,还支持快速摘除问题节点,以及更细粒度的问题组件摘除

img

2.2.8 可迁移 对于一些已经在对外提供 API 的 Web 服务,业务研发人员为了减少运维成本和后续的研发提效,考虑将其迁移到 Shepherd API 网关

对于一些非核心 API,可以考虑使用 Oceanus 的灰度发布功能直接迁移。但是对于一些核心 API,上面的灰度发布功能是机器级别的,粒度较大,不够灵活,不能很好的支持灰度验证过程。解决方案 Shepherd 为业务研发人员提供了一个灰度 SDK,接入 SDK 的 Web 服务,可在识别灰度流量后转发到 Shepherd API 网关进行验证。

灰度哪些 API、灰度百分比可以在 Shepherd 管理端动态调节,实时生效,业务研发人员还可以通过 SPI 的方式自定义灰度策略。灰度验证通过后,再把 API 迁移到 Shepherd API 网关,保障迁移过程的稳定性。灰度过程 灰度前 :在 Shepherd 管理平台创建 API 分组,域名配置为目前使用的域名。在 Oceanus 上,原域名规则不变。

img 灰度中 :在 Shepherd 管理平台开启灰度功能,灰度 SDK 将灰度流量转发到网关服务,进行验证。

img 灰度后 :通过灰度流量验证 Shepherd 上的 API 配置符合预期后再迁移。

img

2.3 易用性设计 Shepherd API 网关的功能强大且复杂,易用性对业务研发人员来说至关重要,我们着重来看下自动生成 DSL、API 操作提效的解决方案

2.3.1 自动生成 DSL 业务研发人员在实际使用网关管理平台时,我们尽量通过图形化的页面配置来减轻 DSL 的编写负担。但服务参数转换的 DSL 配置,仍然需要业务研发人员手工编写。一般来说,生成服务参数 DSL 的流程是

  1. 引入服务的接口包依赖。
  2. 拿到服务参数类定义。
  3. 编写 Testcase 生成 JSON 模板。
  4. 填写参数映射规则。
  5. 最后手工录入管理平台,发布 API。

整个过程非常繁琐,且容易出错。如果需要录入的 API 多达几十上百个,全部由业务研发人员手工录入的效率是非常低下的。解决方案 那么能不能将服务参数 DSL 的生成过程给自动化呢? 答案是可以的,业务 RD 只需在网关录入 API 文档信息,然后录入服务的 Appkey、服务名、方法名信息,Shepherd 管理端会从最新发布的服务框架控制台获取到服务参数的 JSON Schema 信息,JSON Schema 定义了服务参数的类型和结构信息,管理端可根据这些信息,自动生成服务参数的 JSON Mock 数据。结合 API 文档的信息,自动替换参数名相同的 Value 值。 这套 DSL 自动生成方案,使用过程中对业务透明、标准化,业务方只需升级最新版本服务框架即可使用,极大提升研发效率,目前受到业务研发人员的广泛好评。

img

2.3.2 API 操作提效 快速创建 API API 网关的核心能力是建立在 API 配置的基础上的,但提供强大功能的同时带来了较高的复杂性,不少业务研发人员吐槽 API 配置太繁琐,学习成本高。快速创建 API 的功能应运而生,业务研发人员只需要提供少量的信息就可以创建 API。快速创建 API 的功能当前分为 4 种类型(后端 RPC 服务 API、后端 HTTP 服务 API、SSO CallBack API、Nest API),未来会根据业务应用场景的不同,提供更多的快速创建 API 类型。批量操作 业务研发人员在 API 网关上,需要管理非常多的业务分组,每个业务分组,最多可以有 200 个 API 配置,多个 API 可能有很多相同的配置,如组件配置,错误码配置和跨域配置的。每个 API 对于相同的配置都要配置一遍,操作重复度很高。因此 Shepherd 支持批量操作多个 API:勾选多个 API 后,通过【批量操作】功能可一次性完成多个 API 配置更新,降低业务重复配置的操作成本。API 导入导出 Shepherd 提供在不同研发环境相互导入导出 API 的能力,业务研发人员在线下测试完成后,只需要使用 API 导入导出功能,即可将配置导出到线上生产环境,避免重复配置

2.4 可扩展性设计 一个设计良好的基础组件,除了能提供强大的基础能力,还需要有良好的扩展能力。 Shepherd 的可扩展性主要体现在:支持自定义组件、服务编排的能力

2.4.1 自定义组件 Shepherd 提供了丰富的系统组件完成鉴权、限流、监控能力,能够满足大部分的业务需求。但仍有一些特殊的业务需求,如自定义验签、自定义结果处理等。Shepherd 通过提供加载自定义组件能力,支持业务完成一些自定义逻辑的扩展

下图是自定义组件实现的一个实例。getName 中填写自定义组件申请时的名称,invoke 方法中实现自定义组件的业务逻辑,如继续执行、进行页面跳转、直接返回结果、抛出异常等。

img

目前 Shepherd 通过自定义组件已经成功支持了美团优选、外卖、餐饮、打车等重要业务,接入的自定义组件数量有 200 多个。

2.4.2 服务编排

一般情况下,网关上配置的一个 API 对应后端一个 RPC 或者 HTTP 服务。如果调用端有聚合和编排后端服务的需求,那么有多少后端服务,就必须发起多少次 HTTP 的请求调用。由此就会带来一些问题,调用端的 HTTP 请求次数过多,效率低,在调用端聚合服务的逻辑过重。

服务编排的需求应运而生,服务编排是对既有服务进行编排调用,同时对获取的数据进行处理。主要应用在数据聚合场景:一次 HTTP 请求返回的数据需要调用多个或多次服务(RPC 或 HTTP)才能获取到完整的结果。

经过前期调研,公司已经有一套成熟的服务编排框架,由客服团队开发的海盗组件(参见 《海盗中间件:美团服务体验平台对接业务数据的最佳实践》 一文),也是美团内部的公共服务。

因此我们与海盗团队合作,设计了 Shepherd 的服务编排支持方案。海盗通过独立部署的方式提供服务编排能力,Shepherd 与海盗之间通过 RPC 进行调用。这样可以解耦 Shepherd 与海盗,避免因服务编排能力影响集群上的其他服务,同时多一次 RPC 调用并不会有明显耗时增加。使用上对业务研发人员也是透明的,非常方便,业务研发人员在管理端配置好服务编排的 API,通过配置中心同时下发到 Shepherd 服务端和海盗服务上,即可开始使用服务编排能力。整体的交互架构图如下:

img

三、未来规划

目前接入 Shepherd API 网关的 API 数量超过 18000 多个,线上运行的集群数量 90 多个,日均总调用次数在百亿以上。随着 Shepherd API 网关业务规模的不断增长,对我们的可用性、易用性、可扩展性必将提出更高的要求。未来一年,Shepherd 的规划重点包括有云原生架构演进、静态网站托管、组件市场等。

3.1 云原生架构演进

Shepherd API 网关的云原生架构演进有三个目标:简化接入网关步骤,提升业务研发人员的研发效率;减小服务端 War 包大小,提升安全性和稳定性;接入 Serverless 弹性,降低成本,提高资源利用率。

为了实现这个三个目标,我们计划整体迁移网关服务到公司的 Serverless 服务 Nest(参见 《美团 Serverless 平台 Nest 的探索与实践》 一文)上,同时通过抽取 Shepherd 核心功能到 SDK 的方式集成到业务的网关集群,业务研发人员可以只选择自己需要使用的自定义组件,从而大幅减小服务端的 War 包大小。

img

3.2 静态网站托管 依托 Shepherd API 网关实现静态网站托管的目标是: 建设通用的静态网站托管解决方案,为开发者提供便捷、稳定、高扩展性的静态网站托管服务

静态网站托管解决方案能为业务研发人员提供的主要功能包括:托管静态网站资源,包括存储及访问;管理应用生命周期,包括自定义域配置以及身份验证和授权;CI/CD 集成等。

img

3.3 组件市场 Shepherd API 网关组件市场的目标是: 合作共赢,形成开发生态,业务研发人员可将开发的自定义组件提供给其他有需要的业务研发团队使用

我们希望让业务研发人员参与到自定义组件的开发,完善使用文档后设置为公共组件,开放给所有使用 Shepherd 的业务研发人员使用,避免重复造轮子。