透传模式
数据代理层收到数据后立刻转发给下游,不做缓冲、拼接或加工。核心价值是降低延迟,保持流式体验。
#type / concept
#status / growing
#tech / architecture
#tech / networking
[!info] related notes
- 应用场景: 多服务架构, Go SSE 代理模式
- 相关概念: SSE, 防抖节流
透传模式
什么是透传
透传(Pass-Through) 指代理层收到数据后立刻转发给下游,不做任何缓存、拼接或加工。
“透”= 穿透,“传”= 传递。数据穿透代理层,代理层只是传递,不修改内容、不等待凑批。
与缓冲模式的对比
缓冲模式: 上游 → [攒在内存] → 全部接收完 → 一次性发下游
透传模式: 上游第1行 → 立刻转下游 → 上游第2行 → 立刻转下游 → ...
| 维度 | 缓冲模式 | 透传模式 |
|---|---|---|
| 延迟 | 高(等全部完成) | 低(逐行转发) |
| 内存占用 | 高(存完整数据) | 低(只存当前行) |
| 适用场景 | 小数据、需要预处理 | 流式数据、实时性要求高 |
| 用户体验 | 等待后一次展示 | 实时逐字/逐行展示 |
典型场景:SSE 流式代理
LLM 对话场景中,业务后端代理 AI 服务的 SSE 数据流:
用户消息 → 前端 POST → 业务后端(鉴权)
→ 业务后端 POST → AI 服务(SSE)
→ AI 服务流式生成事件
→ 业务后端逐行透传
→ 前端逐事件渲染
错误做法:缓冲
// ❌ 读完所有数据再返回
body, _ := io.ReadAll(resp.Body)
c.Data(200, "text/event-stream", body)
用户要等 LLM 全部生成完(3-10 秒)才能看到第一个字。
正确做法:透传
// ✅ 逐行透传
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
fmt.Fprintf(c.Writer, "%s\n", scanner.Text())
c.Writer.Flush()
}
AI 每产生一行,前端立刻收到,可以逐字显示。
透传时能做什么
虽然不缓冲数据,但代理层在透传过程中仍可:
- 鉴权:转发请求前验证身份
- 注入上下文:附加用户信息、会话历史
- 日志记录:记一份流式日志用于审计(不阻塞转发)
- 协议转换:逐行转换格式(不攒批)
- 错误处理:检测上游异常并通知下游
设计原则
- 收到就发:不等不攒,代理层是管道不是水库
- 不加工内容:转发的是原始数据,不做业务逻辑处理
- 逐行/逐块处理:每次只处理一小块数据
- 立即刷出:写入后立刻 flush,确保数据到达下游
适用条件
- 数据是流式产生的(SSE、WebSocket、流式 API)
- 对延迟敏感(用户需要实时反馈)
- 代理层不需要预处理数据内容
- 数据量可能很大,不适合全部加载到内存
不适用场景
- 需要聚合或汇总数据后再返回
- 需要验证数据完整性后再转发
- 数据量小且不需要实时性
- 需要重试或幂等处理(透传不保留历史数据)
一句话总结
透传 = 收到就发,不等不攒。代理层是管道,不是水库。