B站大规模API Gateway设计与最佳实践
如果无法正常显示,请先停止浏览器的去广告插件。
1. b 站大规模 API 网关的设计
与最佳实践
佳辉
2. API 网关的历史背景
第一次微服务化重构 - SOA
这是 b 站的第一次向微服务架构演进
• 按垂直功能进行拆分
• 这些微服务对外暴露接口
但因缺乏统一出口,也遇到了不少困难:
• 客户端直接调用微服务,强耦合
• 需要多次请求,客户端聚合数据,工作量巨大
• 协议不利于统一,各个部门间有不少差异
• 面向“端”的 API 适配,耦合到了内部服务
• 多终端兼容逻辑复杂,每个服务都需要处理
• 统一逻辑无法收敛,比如安全认证、限流
3. API 网关的历史背景
网关演进 – BFF 1.0
我们新增了一个 app-interface 用于统一的协议出口,在
服务内进行大量的 dataset join,按照业务场景来设计粗
粒度的 API,给后续服务的演进带来的很多优势:
• 轻量交互:协议精简、聚合;
• 差异服务:数据裁剪以及聚合、针对终端定制化 API
• 动态升级:原有系统兼容升级,更新服务而非协议
• 沟通效率提升:协作模式演进为移动业务+网关小组
BFF 可以认为是一种适配服务,将后端的微服务进行适配,
主要包括聚合裁剪和格式适配等逻辑,向无线端设备暴露
友好和统一的 API。
4. API 网关的历史背景
网关演进 – BFF 2.0
BFF 1.0 最致命的问题是整个 app-interface 属于 single
point of failure,严重代码缺陷或者流量洪峰可能引发
集群宕机。
• 单个模块也会导致后续业务集成复杂度高,根据康威
法则,单块的 BFF 和多团队之间就出现不匹配问题,
团队之间沟通协调成本高,交付效率低下
• 很多跨横切面逻辑,比如安全认证,日志监控,限流
熔断等。随着时间的推移,代码变得越来越复杂,技
术债越堆越多
5. API 网关的历史背景
网关演进 – API Gateway
将跨横切面(Cross-Cutting Concerns)的功能(路由、
认证、限流、安全)全部上移,引入了 API Gateway。
将重业务逻辑的 BFF 层和通用服务层 API Gateway 进行
分离。
• API 网关和 BFF 配合,解耦了客户端和微服务,各业
务团队可以独立开发交付新功能,研发效率大大提升。
• 另外,把跨横切面逻辑从 BFF 剥离至 API 网关后,
BFF 的开发人员可以更加专注业务逻辑交付,实现架
构上关注分离(Separation of Concerns)。
我们业务流量实际为:
• 客户端 -> API Gateway -> BFF -> Microservices。
• 在 FE Web 业务中,BFF 可以是 Node.js 来做服务端
渲染(Server-Side Rendering),注意这里忽略了上
游的 CDN、4/7层负载均衡(SLB)。
6. API 网关的
设计目标
•
API 元信息管理
•
•
流量调度
•
•
限流、熔断、降级、缓存
访问控制
•
•
路由、调度、多活、染色灰度、流量复制
隔离保护
•
•
统一管理、生命周期、文档、调试、IDL、OpenAPI、SDK
统一鉴权、跨域、风控
可观测性
•
QPS、Latency、SLA、日志、统一运维视角
7. API 网关的
整体架构
8. API 网关的
配置管理
配置是 API 网关的重要运行时依据,我们通
过以下手段保证配置的高可用:
• 通过 Git Repo 保存最新的配置,并在构
建镜像时同时编译到镜像中
• 控制面监听配置变更,同时也会做内存、
文件缓存
用户变更配置通过 diff 确认,当配置变更量
较多时提醒用户二次 Review。
9. API 网关的
配置设计
Gateway
middleware
middleware
Endpoint
middleware
backend
middleware
Endpoint
10. API 网关的配置
Endpoint
路由转发是 API 网关的重要责任,我们主要支持以下
几种路由匹配模式:
• 前缀匹配:/api/echo/*
• 精确匹配:/api/echo/hello
• 正则匹配:/api/echo/[a-z]+
• RESTful:/api/echo/{name}
在集成控制面后,我们最终仅以精确匹配模式进行
API 的管理与发布。
11. API 网关的配置
Middleware
Middleware 需要注册到 Global Registry 中,通过
名称进行引用。当配置构建时,将会通过工厂函数进
行创建使用。
func RoundTripper(Request) (Response, error)
即标准库 HTTPClient 的插件接口。
PRE
next.RoundTrip(req)
POST
12. API 网关的配置 Rate-
Limiting
我们主要有两种限流模式:
• BBR:基于 CPU 的自适应限流,防止活动峰值进行
压跨网关
• 基于分布式 Quota 服务的全局限流,通过配额令牌,
进行对某个分组、接口限流
BBR 可以按接口等级决定是否限流:CRITICAL、
SHEDDABLE
https://sre.google/sre-book/handling-overload/
13. 真实流量下的
API 网关
14. API 网关的
负载均衡
我们通常认为负载均衡算法中混合多种策略
(P2C、CPU、subset 等)的效果会优于传统
的 rr 或 wrr,但其实也有可能反而导致均衡效果
劣化,如:
• CPU 规格不一致影响 Auto Scaling、 CPU
指标告警的准确性
• 大规模集群节点排序不一致导致 subset 选择
不平均
解决方案:
• 负载均衡算法中应该考察节点过往成功率、
CPU 和请求延时之间的关系
• 服务发现辅助客户端对后端节点的排序,使节
点排序一致后再进行 subset
15. API 网关的
连接数统计
对于网关型应用,对后端的连接数一定程度上决定了转发
能力上限,但过去针对连接数的配置好像一直是“凭感
觉”,我们已知:
• HTTP2 前,一般情况下一个请求占用一个连接,需要
慎重配置
• HTTP2 后,单连接上可承载相当多的请求,连接数配
置基本可忽略
通过压测统计,我们常规 API 耗时一般在 1s 内,且数据
一般小于 800kB,我们得到以下配置可基本满足大部分
需要。
• 单节点最高连接数设置为 1000,最高 IDLE 连接数设
置为 1000,
• *单节点服务发现节点时,选一个最大数量为 20 的子
集,不和所有节点建立连接
• 如果耗时和数据体积大于预计值时,应当调大两个最
大连接数配置
16. API 网关的
重试
在工作中我们有时候为了保证请求的 SLA,会在各个网络
CDN
节点上配置重试策略。而在某次超高流量压力下,因应用
过载带来的重试流量导致服务迟迟无法恢复。
梳理重试策略:
SLB
• CDN:error、timeout、invalid_header
• SLB:error、timeout、invalid_header、
non_idempotent
API 网关
• API 网关:针对 500、502、503、504 等 HTTP
Status Code 或相应的 gRPC Status 进行重试,并且
可做接口级别的配置调整
• 客户端冷却:客户端应当遵循约定的返回头,当出现
返回头时,客户端在冷却时间内主动阻断用户重试
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
17. T h a n k s