接入层设计(一):API网关选型与限流策略
各位同学,今天我们聊聊接入层。说白了,就是用户请求到达咱们人脸识别服务之前,最先碰到的那个“守门员”。
我见过不少团队,一上来就怼业务逻辑,网关随便搭一个。结果呢?线上流量一冲,服务直接雪崩。嗯,这个坑我踩过,所以今天咱们把网关选型、限流策略、路由负载均衡这三件事掰开揉碎讲清楚。
为什么接入层这么重要?
人脸识别API有个特点:单次请求计算重、耗时长,而且经常要跟第三方(比如公安库、活体检测SDK)打交道。如果接入层不做防护,恶意刷接口、突发流量、慢连接耗尽连接池……随便一个都能让后端集群瘫痪。
接入层要干三件事:
- 流量管控——谁可以来,来多少,超了怎么办
- 请求分发——把请求扔给最合适的后端节点
- 协议转换——统一入口,后端爱用啥协议用啥
你想想看,这三件事要是没做好,后面再牛的算法模型也白搭。
API网关选型:Kong vs Nginx
市面上网关很多,但高并发场景下,我主要看两个:Kong 和 Nginx。不是其他不好,是这两个生态最成熟,坑最少。
| 对比维度 | Kong | Nginx |
|---|---|---|
| 核心定位 | API网关(带管理面) | 反向代理服务器 |
| 扩展方式 | 插件(Lua/Go/JS) | 模块(C/Lua) |
| 管理API | 自带RESTful Admin API | 需自行开发 |
| 性能 | 略低于Nginx(约5-10%) | 极致,单机10万+连接 |
| 适用场景 | 多团队、多服务、需动态路由 | 纯反向代理、静态路由 |
我个人习惯:如果团队规模大、服务多、需要频繁调整路由策略,选Kong。它自带限流、鉴权、日志插件,省去很多开发时间。但如果只是做流量入口,后端就两三个服务,Nginx完全够用,而且性能更极致。
限流策略:令牌桶 vs 漏桶
限流是接入层的核心。人脸识别API尤其需要——一次识别可能要几百毫秒,如果并发冲上来,数据库连接池、GPU资源全都会被打满。
两种经典算法:
令牌桶算法
原理很简单:一个桶,每秒往里面放固定数量的令牌。请求来了,拿一个令牌就走。桶里令牌用完了,请求就排队或者直接拒绝。
优点:允许突发流量。比如桶容量100,每秒放10个令牌,那瞬间可以处理100个请求,然后慢慢消化。
缺点:突发可能把后端打懵。我遇到过,桶设太大,瞬间流量把数据库连接池撑爆了。
漏桶算法
这个更“死板”。桶底下有个洞,每秒漏固定数量的水(请求)。不管上面倒多少水,下面流出的速度是恒定的。
优点:输出流量平滑,后端永远感受不到突发。
缺点:无法应对突发,用户体验差。比如用户瞬间上传10张照片,可能前9张都要排队。
| 特性 | 令牌桶 | 漏桶 |
|---|---|---|
| 突发处理 | 支持(桶容量内) | 不支持 |
| 输出平滑度 | 一般 | 平滑 |
| 实现复杂度 | 中等 | 简单 |
| 适用场景 | 大部分业务API | 数据库写入、第三方调用 |
限流实现:Nginx + Lua 示例
用Nginx做限流,最常用的就是 limit_req 模块(漏桶)和 lua-resty-limit-traffic(令牌桶)。
下面是一个令牌桶的Lua实现片段:
-- 令牌桶限流,基于lua-resty-limit-traffic
local limit = require "resty.limit.count"
-- 创建限流器:每秒10个令牌,桶容量20
local lim, err = limit.new("my_limit_store", 10, 20)
if not lim then
ngx.log(ngx.ERR, "failed to instantiate: ", err)
return ngx.exit(500)
end
-- 检查当前请求
local delay, err = lim:incoming("api:v1:face:compare", true)
if not delay then
if err == "rejected" then
return ngx.exit(429) -- 请求过多
end
ngx.log(ngx.ERR, "failed to limit: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- 需要等待,但这里我们选择直接拒绝
-- 实际可以ngx.sleep(delay)做排队
return ngx.exit(429)
end
这段代码我直接用在生产环境过。注意那个 true 参数,表示“如果超限就拒绝,不排队”。人脸识别场景,排队意义不大,用户等不起。
请求路由与负载均衡
网关拿到请求后,要决定扔给谁。这里有两个关键点:
- 路由规则:根据URL、Header、甚至请求体内容做分发
- 负载均衡:在同组后端里选一个最合适的节点
路由策略
人脸识别API常见的路由方式:
- 按版本路由:
/v1/face/compare→ 旧模型集群;/v2/face/compare→ 新模型集群 - 按渠道路由:根据
X-App-Id头部分发到不同资源池 - 按请求类型路由:1:N识别走专用集群,1:1比对走通用集群
负载均衡算法
| 算法 | 特点 | 人脸识别场景适用性 |
|---|---|---|
| 轮询 | 简单,不考虑后端负载 | 低,后端性能差异大时容易倾斜 |
| 最少连接 | 选当前连接数最少的节点 | 中等,适合长连接场景 |
| 一致性哈希 | 相同请求落到相同节点 | 高,人脸特征缓存命中率提升明显 |
| 加权响应时间 | 根据历史响应时间动态调整权重 | 高,能自动避开慢节点 |
我建议:人脸识别场景,优先用一致性哈希。为什么呢?因为人脸特征提取结果可以缓存。同一个用户反复请求,落到同一台机器,缓存命中率能从20%提升到70%以上。这个优化,比加机器还管用。
整体架构图
下面这张图,把今天讲的内容串起来了。你可以看到请求从客户端进来,经过网关的限流、路由、负载均衡,最后到达后端服务集群。