6

LogReplay 流量录制回放设计与实现

 1 year ago
source link: https://forrestsu.github.io/posts/design/log-replay/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

基于拦截器,实现一个基于 trpc 协议的流量录制、回放插件。 支持回放流量验证。

常用场景:

  • 服务重构后的流量验证,差异检测
  • 日常需求迭代,回放验证(上线前)

2 整体方案

实现两组拦截器:录制拦截器、回放拦截器

  1. 录制拦截器:负责记录服务接口+所有下游调用数据(req、rsp、err),序列化后上报,用于回放。
  2. 回放拦截器:负责下游调用的mock(不实际发起调用),服务接口的回包上报,用于diff。
  3. 回包 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 ?

解法:

  1. 业务为每次RPC调用,构造唯一的spanName;
  2. 将spanName在发起client调用时,传递到 trpc-replay 拦截器中;
  3. 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 并发查询多个视图

func init() {
    // 使用 unionplus sdk 查询多个视图:可以将ViewName追加到spanName中,来保证唯一
    api.DefaultSpanNameFunc = func(ctx context.Context, req interface{}) string {
        spanName := api.GetSpanName(ctx, req)
        switch r := req.(type) {
        case *common.QueryReq:
            return spanName + r.GetViewName()
        default:
            return spanName
        }
    }
}

5.1 回放mock效果

由于是mock返回(下游在 1ms 之内返回)

回放效果

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK