LogReplay 流量录制回放设计与实现
1 前言
基于拦截器,实现一个基于 trpc 协议的流量录制、回放插件。 支持回放流量验证。
常用场景:
- 服务重构后的流量验证,差异检测
- 日常需求迭代,回放验证(上线前)
2 整体方案
实现两组拦截器:录制拦截器、回放拦截器
- 录制拦截器:负责记录服务接口+所有下游调用数据(req、rsp、err),序列化后上报,用于回放。
- 回放拦截器:负责下游调用的mock(不实际发起调用),服务接口的回包上报,用于diff。
- 回包 diff 能力:由 LogReplay 平台提供,拦截器插件只负责上报diff所需数据。
补充一点,如何保存切面数据?
方案一: 基于trpc包头 metadata 方式透传 切面数据。
- 优点:完整性,录制的数据包含所有切面(直接可用于回放 + 下游mock)
- 缺点:序列化后的切面数据总大小上限64KiB(2字节记录RequestHead长度)
方案二: 直接上报到LogReplay平台,基于traceID做关联(服务和切面数据)。
2.1 接口设计
2.2 录制拦截器
2.3 回放拦截器
3 实现思路
阶段1:基础能力-录制
- 1 支持 trpc 的染色录制能力(上报到录制平台)
- 2 支持下游切面录制 (上报到录制平台)
- 3 采用 replayContext,记录下游调用请求+回包(map + lock)
- 4 所有下游数据,存入 trpc 请求 head 的 metadata 中,一并上报;
阶段2:支持切面回放
- 1 支持回放,上报回放时产生的 rsp;
- 2 回放时,支持对下游服务回报 mock(服务重构场景:流量验证);
- 3 更多开关选项:
- a) 比如录制时,是否录制切面;
- b) 回放时,是否启用切面mock;
阶段3
- 支持更多常见协议: http 协议等
4 更上一层楼
4.1 思考题:在一次服务请求中,调用同一个下游服务多次(spanName
都是相同的),回放时如何 mock ?
解法:
- 业务为每次RPC调用,构造唯一的spanName;
- 将spanName在发起client调用时,传递到
trpc-replay
拦截器中; trpc-replay
对外导出api.SpanNameFunc(ctx, req)
, 用户可以自定义实现,拿到spanName即可;
这里列举3种方案:
方案一:使用
ctx.Value()
来传递trpc_replay_unique_name
- 优点:实现简单,无并发问题;
- 缺点:会在 ctx 链表中 增加一个节点;
方式二:借助于 trpc.Msg 来传递, 比如 client.WithMetaData()
- 优点:实现简单,无并发问题;
- 缺点:新增的 metaData kv 会通过trpc协议,透传给下游;
方式三(推荐):对 req 进行类型断言,从req 获取标识来区分;
- 优点:实现简单,影响面小,只针对有多次请求的下游-做逻辑处理;
- 缺点:无
实际案例: 使用 unionplus sdk 并发查询多个视图
|
|
5 附录
5.1 回放mock效果
由于是mock返回(下游在 1ms 之内返回)