共计 1549 个字符,预计需要花费 4 分钟才能阅读完成。

问题背景
- 当调用大型语言模型 (LLM)API 时,响应内容可能超过预设的 上下文窗口限制(如 GPT- 3 的 4096 token 限制),导致结果被截断
- 在大数据查询场景中,数据库 API 可能限制单次查询返回的行数(如 MySQL 的
LIMIT 1000),需要多次请求才能获取完整结果集 - 实时日志传输场景下,单个 HTTP 响应包可能因超出 TCP 窗口大小被分片,影响传输效率
技术方案对比
分页查询(Pagination)
- 优点:实现简单,兼容性高;客户端可灵活控制每批数据量
- 缺点:多次网络往返增加延迟;服务端需维护分页状态
- 适用场景:结构化数据查询、需要随机访问的场景
流式传输(Streaming)
- 优点:边生成边传输,降低内存占用;减少等待时间
- 缺点:需要长连接支持;错误恢复较复杂
- 适用场景:LLM 生成、文件下载等连续数据流
数据压缩(Compression)
- 优点:减少传输数据量;对客户端透明
- 缺点:增加 CPU 开销;压缩率依赖数据类型
- 适用场景:文本 /JSON 等可压缩数据
核心实现
Python 流式处理示例
def stream_llm_response(prompt):
try:
buffer = ""
for chunk in openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
stream=True
):
content = chunk.choices[0].delta.get("content", "")
if content:
buffer += content
# 达到处理阈值时 yield
if len(buffer) > 1024:
yield buffer
buffer = ""
if buffer:
yield buffer
except Exception as e:
print(f"Stream error: {str(e)}")
raise
Go 分页并发控制
func queryWithPagination(db *sql.DB, query string, pageSize int) {
var wg sync.WaitGroup
pool := &sync.Pool{New: func() interface{} {return make([]byte, 0, pageSize*2)
},
}
for page := 1; ; page++ {wg.Add(1)
go func(p int) {defer wg.Done()
buf := pool.Get().([]byte)
defer func() {buf = buf[:0]
pool.Put(buf)
}()
rows, err := db.Query(fmt.Sprintf("%s LIMIT %d OFFSET %d",
query, pageSize, (p-1)*pageSize))
// ... 处理逻辑
}(page)
}
wg.Wait()}
生产环境考量
TCP 窗口与吞吐量
- 窗口大小 决定未确认数据的最大在途量,计算公式:
吞吐量 = 窗口大小 / RTT - 可通过
sysctl -w net.ipv4.tcp_window_scaling=1启用窗口缩放(最高 1GB)
JWT 幂等性设计
- 在分页令牌中包含:
{"page": 2, "nonce": "a1b2c3", "exp": 3600} - 服务端校验 nonce 防止重复提交
- 建议结合 Redis 记录已处理页码
避坑指南
- 未关闭响应体 :Go 中未调用
resp.Body.Close()会导致 goroutine 泄漏 - 分页偏移膨胀 :MySQL 的
LIMIT 1000000, 10会先扫描 100 万行 - 流式超时控制 :未设置
http.Client.Timeout可能导致僵尸连接
延伸思考
- 如何根据网络延迟动态调整分页大小?可考虑实现基于 RTT 的 PID 控制器
- 流式传输中如何实现 背压机制?参考 TCP 滑动窗口协议的思想
正文完
