本文目录
- 说在前面
- 日流量200亿,携程网关的架构设计
- 一、概述
- 二、高性能网关核心设计
- 2.1. 异步流程设计
- 2.2. 流式转发&单线程
- 2.3 其他优化
- 三、网关业务形态
- 四、网关治理
- 4.1 多协议兼容
- 4.2 路由模块
- 4.3 模块编排
- 五、总结
- 说在最后:有问题可以找老架构取经
- 部分历史案例
日流量200亿,携程网关的架构设计
方案的作者:Butters,携程软件技术专家,专注于网络架构、API网关、负载均衡、Service Mesh等领域。
一、概述
类似于许多企业的做法,携程 API 网关是伴随着微服务架构一同引入的基础设施,其最初版本于 2014 年发布。随着服务化在公司内的迅速推进,网关逐步成为应用程序暴露在外网的标准解决方案。后续的“ALL IN 无线”、国际化、异地多活等项目,网关都随着公司公共业务与基础架构的共同演进而不断发展。截至 2021 年 7 月,整体接入服务数量超过 3000 个,日均处理流量达到 200 亿。
在技术方案方面,公司微服务的早期发展深受 NetflixOSS 的影响,网关部分最早也是参考了 Zuul 1.0 进行的二次开发,其核心可以总结为以下四点:
-
server端:Tomcat NIO + AsyncServlet -
业务流程:独立线程池,分阶段的责任链模式 -
client端:Apache HttpClient,同步调用 -
核心组件:Archaius(动态配置客户端),Hystrix(熔断限流),Groovy(热更新支持)

众所周知,同步调用会阻塞线程,系统的吞吐能力受 IO 影响较大。
作为行业的领先者,Zuul 在设计时已经考虑到了这个问题:通过引入 Hystrix,实现资源隔离和限流,将故障(慢 IO)限制在一定范围内;结合熔断策略,可以提前释放部分线程资源;最终达到局部异常不会影响整体的目标。
然而,随着公司业务的不断发展,上述策略的效果逐渐减弱,主要原因有两方面:
-
业务出海:网关作为海外接入层,部分流量需要转回国内,慢 IO 成为常态 -
服务规模增长:局部异常成为常态,加上微服务异常扩散的特性,线程池可能长期处于亚健康状态

全异步改造是携程 API 网关近年来的一项核心工作,本文也将围绕此展开,探讨我们在网关方面的工作与实践经验。
重点包括:性能优化、业务形态、技术架构、治理经验等。
二、高性能网关核心设计
2.1. 异步流程设计
全异步 = server端异步 + 业务流程异步 + client端异步
对于server与client端,我们采用了 Netty 框架,其 NIO/Epoll + Eventloop 的本质就是事件驱动的设计。
我们改造的核心部分是将业务流程进行异步化,常见的异步场景有:
-
业务 IO 事件:例如请求校验、身份验证,涉及远程调用 -
自身 IO 事件:例如读取到了报文的前 xx 字节 -
请求转发:包括 TCP 连接,HTTP 请求
从经验上看,异步编程在设计和读写方面相比同步会稍微困难一些,主要包括:
-
流程设计&状态转换 -
异常处理,包括常规异常与超时 -
上下文传递,包括业务上下文与trace log -
线程调度 -
流量控制
特别是在Netty上下文内,如果对 ByteBuf 的生命周期设计不完善,很容易导致内存泄漏。
围绕这些问题,我们设计了对应外围框架,最大努力对业务代码抹平同步/异步差异,方便开发;同时默认兜底与容错,保证程序整体安全。
在工具方面,我们使用了 RxJava,其主要流程如下图所示。
-
Maybe
-
RxJava 的内置容器类,表示正常结束、有且仅有一个对象返回、异常三种状态
-
响应式,便于整体状态机设计,自带异常处理、超时、线程调度等封装
-
Maybe.empty()/Maybe.just(T),适用同步场景
-
工具类RxJavaPlugins,方便切面逻辑封装
-
Filter
-
代表一块独立的业务逻辑,同步&异步业务统一接口,返回Maybe
-
异步场景(如远程调用)统一封装,如涉及线程切换,通过maybe.obesrveOn(eventloop)切回
-
异步filter默认增加超时,并按弱依赖处理,忽略错误
{//模块名称,对应网关内部某个具体模块"name":"addResponseHeader",//执行阶段"stage":"PRE_RESPONSE",//执行顺序"ruleOrder":0,//灰度比例"grayRatio":100,//执行条件"condition":"true","conditionParam":{},//执行参数//大量${}形式的内置模板,用于获取运行时数据"actionParam":{"connection":"keep-alive","x-service-call":"${request.func.remoteCost}","Access-Control-Expose-Headers":"x-service-call","x-gate-root-id":"${func.catRootMessageId}"},//异常处理方式,可以抛出或忽略"exceptionHandle":"return"}
五、总结
网关在各种技术交流平台上一直是备受关注的话题,有很多成熟的解决方案:易于上手且发展较早的 Zuul 1.0、高性能的 Nginx、集成度高的 Spring Cloud Gateway、日益流行的 Istio 等等。
最终的选型还是取决于各公司的业务背景和技术生态。
因此,在携程,我们选择了自主研发的道路。
技术在不断发展,我们也在持续探索,包括公共网关与业务网关的关系、新协议(如 HTTP3)的应用、与 ServiceMesh 的关联等等。
- End-
DailyMart是一个基于 DDD 和Spring Cloud Alibaba的微服务商城系统,采用SpringBoot3.x以及JDK17。旨在为开发者提供集成式的学习体验,并将其无缝地应用于实际项目中。该专栏包含领域驱动设计(DDD)、Spring Cloud Alibaba企业级开发实践、设计模式实际应用场景解析、分库分表战术及实用技巧等内容。如果你对这个系列感兴趣,可在本公众号回复关键词DDD获取完整文档以及相关源码。

本篇文章来源于微信公众号: JAVA日知录
微信扫描下方的二维码阅读本文

Comments NOTHING