大概三年前的这个时候,开始负责一个项目,是一个 P2P 产品的客户端的开发。需求很常见,基本就是需要 手机App(iOS, Android) 和 移动 H5页面。当时的一个项目背景是,已经存在多个由后端团队使用 Java 开发的微服务,承载着产品的核心业务逻辑,以及主数据的管理。这些已经存在的微服务,基本是按照领域模型划分,如会员服务,标的服务,账务服务,充值支付服务等,每个服务基本还提供相应的查询服务,另外还有一些实用工具类的,如短信服务。可以预见,在微服务架构下,一个寻常的 UI 页面,往往需要调用多个服务。而这仅仅是问题的一个方面。
让我们看看在微服务架构下,关于提供给客户端的 API 的设计,都有哪些方面的问题需要考虑
- 微服务暴露的 API 粒度,通常不同于客户端的需求。微服务通常暴露细粒度的 API
- 不同的客户端可能需要不同的数据
- 不同客户端的网络性能可能不同。典型的如服务端渲染的 Web 应用程序,相较于移动客户端,可以在不影响用户体验的情况下,发起更多的请求,而区别就在于,LAN 比起移动网络,更快并且延迟低
- 服务的实例数量和位置可能发生变化
- 服务的划分可能随时间推移而变化
- 服务可能使用多种协议,其中一些可能不是对 Web 友好的
考虑到这些因素,便很自然地考虑,引入一个中间层,服务于客户端,按需定制 API,减少请求次数,同时隐藏不必要的细节。
引入这一层抽象之后,前述问题的化解,都找到一个好的抓手
- 客户端可以不受服务划分的变化的影响
- 客户端可以不受服务的实例数量和位置变化的影响
- 不同的客户端,可以有专属的 API,同时又共享底层的服务阵列和基础设施
- 减少客户端发起请求的数量,进而提升了用户体验
- 客户端不必调用多个服务而只需要与调用 API gateway
- 协议转换,将任何内部的通讯协议,转换为 Web 友好的 API 协议
在前述的项目中,微服务之间使用了 Hessian 和 SOAP 协议,经过 API gateway 的协议转换,最终只以 REST 的方式暴露 API 给客户端。
这一层的引入,显然也有一些代价
- 增加了系统复杂性。API gateway 作为一个代码工程,必然需要投入开发、部署和维护
- 增加了响应时间。但对于大多数应用而言,LAN 网络中一个额外往返的成本是微不足道的
回到当时的项目中,那时还未了解到 API gateway 作为一种架构模式的存在,代码项目的名称是 web-api
,但这个项目完整的承担了 API gateway 扮演的职责,有效地化解了微服务架构下,降低客户端的整体开发维护成本。
在技术选型上,实现 API gateway 常见的是采用事件驱动或者响应式的编程框架,当需要扩容应对高负载时,这是推荐的方式。在 JVM 上,可以考虑基于 NIO 的库,如 Netty,Spring Reactor 等。Node.js 也是个常见选择。
引入一点题外话,我当时对降低客户端的整体开发维护成本,还有另外一些思考,是关于沟通。日常的 UI 需求中,有不少其实是对后端微服务没有变更要求的,简单的比如,多显示一个字段,格式化显示金额,稍复杂的比如,页面呈现需要多组合一个既有的微服务,表单提交需要将部分信息反馈到另一个微服务等。对于这类需求,如果由后端团队来支持,一是会分散他们对领域服务和主数据管理的专注,二是考虑到 API gateway 这层比较薄的路由层/装配层,动态语言相比 Java 是更高效的选择。
再结合当时团队的情况,Java 开发人员普遍缺少基于 NIO 的库的开发经验,而且开发任务/风险已经偏重。而前端开发人员在编写前端组件以及实现前端构建时,都是在使用 Node.js,因此对于他们而言,使用 Node.js 上手 API gateway 的开发,门槛较低并且普遍有学习意愿。前端开发人员又是 UI 需求的直接受命人,对于前述的一大类 UI 变更需求,他们可以以最少的沟通成本,最少的信息传递失误,来高效的完成。
由此我组建了当时公司内第一个大前端部门,将前端团队和移动端团队纳入,将 API gateway 的实现和文档管理的职责纳入,大家共同围绕客户端的需求,保持较高的整体开发维护效率。此后,还在 API gateway 的基础上陆续添加了 API 版本管理,移动设备管理,客户端统计,缓存等一系列服务。
API gateway 还有很多的扩展点,试举一些例子
- 客户端多协议。之前在携程做 App 时,客户端就是同时支持 HTTP 和 TCP 两种协议
- 面向客户端支持 HTTP DNS / Direct IP。这个也是常见的客户端优化手段
- 客户端的流控
- 客户端认证和鉴权
- 响应数据的脱敏
- 客户端密钥管理
- 客户端缓存协商
- 客户端调用计量或计费。典型如 Open API
在 API gateway 这个领域,也有一些开源框架在活跃,如 Netflix Zuul,基于 Nginx 的 Kong 等,目前关注较少,就不展开介绍了。