Featured image of post tcpcopy 流量复制实战:把生产 TCP 流量引到测试机做真实压测

tcpcopy 流量复制实战:把生产 TCP 流量引到测试机做真实压测

tcpcopy 1.2.0 + intercept 1.0.0 编译安装、线上/测试/辅助机三机架构、libpcap 抓包、路由配置、流量放大与端口多路实战、GLIBC_2.34 兼容性坑

背景

业务上线前,常规压测方法(JMeter、ab、wrk)都模拟不出来真实流量的"乱"——真实的用户行为、参数分布、慢请求、错误重试,真实流量里才有

tcpcopy 是国产开源的流量复制工具,能把生产环境的真实 TCP 流量原样复制到测试机,完全真实地回放。

适用场景

  • 新版本上线前的真实流量压测
  • 性能调优(数据库加索引、改 SQL、缓存优化)的量化对比
  • 故障复现——线上出了 bug,把流量引到测试机反复重现
  • 容量规划——评估"双 11 流量峰值需要多少机器"

前置知识

  • TCP/IP 协议基础
  • Linux 内核路由
  • libpcap / iptables 基础

重要原则:tcpcopy 会修改源 IP 让响应走辅助机,生产环境用要谨慎

  1. 做好"白名单 + 流量比例"控制,先 n 1(1 倍流量)再 n 2(2 倍)
  2. 测试机配置必须等同生产(CPU、内存、网卡、数据库)
  3. 千万不要把响应数据写回生产库——确认测试库/影子表

一、tcpcopy 工作原理

tcpcopy 不是简单"复制 TCP 包",而是完整模拟 TCP 三次握手 + 数据交互

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
                  tcpcopy 进程                            intercept 进程
                  (线上机器)                              (辅助机器)
                       │                                      │
[生产客户端]  ──TCP──>  [线上服务器]                          │
                       │   ↑                                   │
                       │   │ 1. 抓 IP 层包到 tcpcopy         │
                       │   │                                   │
                       │   │ 2. 改目的 IP → 测试机           │
                       │   └──────────────────────>  [测试机]   │
                       │   3. 改源 IP → 辅助机 IP             │
                       │   4. 测试机处理请求,返回响应         │
                       │   5. 响应到辅助机,被 intercept 截获  │
                       │   6. drop 响应 body,复制 IP header ─>│
                       │   7. 发送响应头给 tcpcopy            │
                       │   8. tcpcopy 模拟响应回客户端       │
                       ↓                                      ↓
[生产客户端]  <──TCP──  [线上服务器]  ← 响应用辅助机的 IP 头 ──

三台机器(经典架构):

角色数量作用
线上服务器1安装 tcpcopy,抓生产包并转发
测试机1安装实际服务,接收复制流量
辅助机1安装 intercept,截获测试机响应、回传响应头

两台机器(简化):辅助机和测试机合一,前提是辅助机有 IP 层抓包能力(同机房内通常可以)。


二、安装

2.1 tcpcopy(线上机器)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 源码
wget https://github.com/session-replay-tools/tcpcopy/archive/refs/tags/v1.2.0.tar.gz
tar xvf v1.2.0.tar.gz
cd tcpcopy-1.2.0
./configure --prefix=/opt/tcpcopy/
make
make install

# 打包(方便多机部署)
cd /opt
tar -zcvf tcpcopy.tar.gz tcpcopy

2.2 intercept(辅助机器)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 依赖
yum -y install libpcap-devel
# Ubuntu: apt install libpcap-dev

wget https://github.com/session-replay-tools/intercept/archive/refs/tags/1.0.0.tar.gz
tar xvf 1.0.0.tar.gz
cd intercept-1.0.0
./configure --prefix=/opt/tcpcopy/
make
make install

三、IP 与端口规划

假设:

  • 线上服务器 IP:9.9.8.7(公网/业务)
  • 客户端网段:62.135.200.0/24(生产用户 IP 段)
  • 测试机 IP:10.1.2.3(内网,性能等同生产)
  • 辅助机 IP:10.1.2.4(与测试机同网段,能抓到测试机回包

线上服务器服务端口:8881(业务端口)


四、配置步骤

4.1 辅助机启动 intercept

1
2
3
4
# 默认端口 36524
/opt/tcpcopy/sbin/intercept -i any \
  -F 'tcp and (port 8881 or port 8882)' \
  -p 40003 -d

参数:

参数含义
-i any监听所有网卡
-F 'tcp and src port 8881'BPF 过滤器:抓 TCP 源端口 8881 的包
-p 40003intercept 与 tcpcopy 通信端口
-ddaemon 模式

4.2 测试机配置路由(把响应导向辅助机)

1
2
3
# 在测试机(10.1.2.3)上执行
# 把客户端网段 62.135.200.0/24 的响应路由到辅助机 10.1.2.4
route add -net 62.135.200.0 netmask 255.255.255.0 gw 10.1.2.4

4.3 线上服务器启动 tcpcopy

1
2
3
4
5
/opt/tcpcopy/sbin/tcpcopy \
  -x 8881-10.1.2.3:8881 \
  -s 10.1.2.4:40003 \
  -c 62.135.200.0/24 \
  -d

参数:

参数含义
-x 8881-10.1.2.3:8881把 8881 端口流量复制到测试机 8881
-s 10.1.2.4:40003intercept 通信地址
-c 62.135.200.0/24客户端 IP 段(必须,否则不复制)
-ddaemon 模式

五、流量控制实战

5.1 复制指定比例流量

1
2
3
4
5
6
7
# 复制 20% 流量
/opt/tcpcopy/sbin/tcpcopy -x 18001-10.1.2.3:18001 \
  -s 10.1.2.4 -c 62.135.200.0/24 -r 20 -d

# 复制 2 倍流量(流量放大,做压测峰值用)
/opt/tcpcopy/sbin/tcpcopy -x 18001-10.1.2.3:18001 \
  -s 10.1.2.4 -c 62.135.200.0/24 -n 2 -d

5.2 多端口同时复制

1
2
3
4
/opt/tcpcopy/sbin/tcpcopy \
  -x 80-61.135.233.160:8080 \
  -x 81-61.135.233.160:8081 \
  -s 61.135.233.161 -c 62.135.200.0/24 -d

5.3 复制 HTTPS

tcpcopy 抓的是IP 层包,对应用层透明,HTTPS/MySQL/Redis 都能复制。

但 HTTPS 复制后,测试机的 SSL 证书需要能"通过校验"——可以用 -k(客户端跳过证书校验)或导入相同证书。


六、完整生产级命令

线上服务器(iptables 配合,把响应包标记后让 tcpcopy 处理):

1
2
3
4
5
6
7
8
9
# 让 tcpcopy 处理的端口
iptables -I INPUT -p tcp --sport 40001 -j DROP -s <测试机IP>
iptables -I INPUT -p tcp --sport 8881  -j DROP -s <测试机IP>
iptables -I OUTPUT -p tcp --sport 40001 -j NFQUEUE

/opt/tcpcopy/sbin/tcpcopy \
  -x 8787-<测试机IP>:40001 \
  -s <辅助机IP>:40003 \
  -c <客户端网段> -d

辅助机

1
2
3
4
/opt/tcpcopy/sbin/intercept \
  -i em1 \
  -F 'tcp and src port 8881' \
  -p 40003 -d

测试机(路由 + 服务启动):

1
2
route add -net <客户端网段> netmask 255.255.255.0 gw <辅助机IP>
# 启动业务服务,监听 8881

七、GLIBC_2.34 兼容性坑

最常见的错误

1
2
/opt/tcpcopy/sbin/tcpcopy: /lib/x86_64-linux-gnu/libc.so.6: 
version `GLIBC_2.34' not found (required by /opt/tcpcopy/sbin/tcpcopy)

原因:tcpcopy 1.2.0 是 2022 年编译的,链接到 GLIBC 2.34(Ubuntu 22.04 默认)。如果线上服务器是 Ubuntu 20.04(GLIBC 2.31),就会报错。

对策

方案 A:升级 OS 到 Ubuntu 22.04+(推荐)

方案 B:在 Ubuntu 22.04 编译后部署

1
2
3
4
5
# 拿 22.04 容器编译
docker run --rm -v $(pwd):/src ubuntu:22.04 bash -c "
  apt update && apt install -y build-essential libpcap-dev
  cd /src && ./configure --prefix=/opt/tcpcopy/ && make && make install
"

方案 C:打补丁降级

在 configure.ac 中改 -D_GNU_SOURCE 处理,不推荐——容易出诡异 bug。

查看 glibc 版本:

1
2
strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC_
# 应看到 GLIBC_2.31 / GLIBC_2.34 等

八、常见问题

8.1 “many connections can’t be established”

tcpcopy 复制时建立大量连接,可能与以下冲突:

  • 测试机 ulimit 限制
  • 测试机 TIME_WAIT 累积
  • 辅助机抓包丢包(libpcap buffer 太小)

对策

1
2
3
4
5
6
7
# 测试机优化
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.ip_local_port_range="1024 65000"
ulimit -n 65535

# intercept 增大 buffer
/opt/tcpcopy/sbin/intercept -i any -F ... -p 40003 -d -m 4096

8.2 测试机收到的 IP 全是辅助机 IP

正常——这是 tcpcopy 故意改的(让响应回辅助机)。如果你的服务强依赖客户端 IP(如 IP 白名单、IP 限流),需要用其他工具(nginx X-Forwarded-For)。

8.3 数据库连接爆掉

复制 N 倍流量意味着测试数据库要承受 N 倍写入。对策

  • 测试库用 binlog_format=ROW + read_only 防止误写
  • 用影子表(按用户分表)
  • ShardingSphere 影子库

8.4 tcpcopy 进程秒退

查看日志:

1
2
/opt/tcpcopy/sbin/tcpcopy -x ... -d 2>&1 | tee tcpcopy.log
# 去掉 -d 改前台

常见:libpcap 权限不够(用 root 跑)、intercept 端口不通(防火墙)。


九、卸载

1
2
3
4
rm -rf /opt/tcpcopy
rm -rf /opt/tcpcopy.tar.gz
# 清理路由
route del -net 62.135.200.0 netmask 255.255.255.0 gw 10.1.2.4

小结

tcpcopy 是真实流量回放的事实标准:

  1. 三机架构:线上 + 测试机 + 辅助机
  2. 流量控制-r 比例复制、-n 流量放大
  3. 应用层透明:HTTP/HTTPS/MySQL/Redis 都能复制
  4. GLIBC 坑:在 Ubuntu 22.04+ 编译部署

生产使用三原则

  • 先 1 倍再放大,避免误伤
  • 测试库用 read_only + 影子表
  • 看响应指标而非客户端数(测试机 CPU、DB QPS、慢 SQL)

下一步

  • 商业方案:GorillaStreamer、NetStitcher
  • 应用层工具:GoReplay(HTTP 专用,更简单)
  • 影子库:ShardingSphere 影子规则

2024 视角:流量复制进入 eBPF + 服务网格时代

2022 那篇是 tcpcopy 1.2.0 时代的"IP 层抓包复制"。2024 视角下,流量复制有了更现代的实现——尤其在 K8s/微服务生态。

一、tcpcopy 1.2.0 仍是 2024 的"经典选择"

  • 2024 现状:tcpcopy 仓库 session-replay-tools/tcpcopy 维护节奏放缓(2018 后基本没大更新),但功能完整、稳定性高——仍被大量企业用
  • 替代选择
    • goreplay(Go 写,HTTP 专用)
    • tcprewrite + tcpreplay(TCP 层回放)
    • bilibili/overlord(B 站开源,Go 写,2023+ 活跃)
    • eBPF-based:基于 eBPF 的现代方案

二、eBPF 流量复制的"现代方案"

  • 2024 主流:用 eBPF 在内核态做流量复制——比 tcpcopy 更灵活
1
2
3
4
5
6
# bpftool / tc 的 mirror 动作
tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 \
    action mirred egress mirror dev eth1

# 镜像 eth0 流量到 eth1(旁路采集)
  • 优势
    • 内核态抓包,性能零损耗
    • 不会改源 IP(vs tcpcopy 改 IP)
    • 可镜像到任何网卡 / netns
    • 配合 bpf_dump(bpftool)能直接拿到包内容

三、K8s 时代的流量复制:服务网格

  • Istio(2024 仍是 K8s 服务网格事实标准)的 VirtualService 镜像功能:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews-mirror
spec:
  hosts:
    - reviews
  http:
    - mirror:
        host: reviews-test    # 镜像到测试服务
      route:
        - destination:
            host: reviews      # 主流量仍走主服务
  • 效果
    • 生产流量 100% 走 reviews(主服务)
    • 同时 100% 流量复制到 reviews-test(测试服务)
    • 测试服务的响应丢弃(不影响生产)

四、GoReplay 在 HTTP 场景的"现代姿势"

1
2
3
4
5
6
# 在生产机器
goreplay --input-raw :8080 --output-http "http://test-server:8080"

# 复制 10% 流量
goreplay --input-raw :8080 --output-http "http://test-server:8080" --middleware "/path/to/middleware.go"
# middleware.go: 用 probability 控制复制比例
  • GoReplay 优势(比 tcpcopy 简单):
    • 纯 Go 单文件,不依赖 libpcap
    • 不需要路由配置
    • 不需要辅助机
    • HTTP / WebSocket / HTTPS 都能复制

五、AI 训练数据的"流量录制"

  • 2024 LLM / AI 应用最大新需求生产 LLM API 请求录制做离线评测 / 模型微调:
    • LangSmith(LangChain 自带)
    • Langfuse(开源,2023 推出,2024 主流)
    • Helicone(LLM 专用 observability)
1
2
3
4
5
6
7
# Langfuse 录 LLM 请求
pip install langfuse
from langfuse.decorators import observe, langfuse_context

@observe()
def llm_call(prompt: str) -> str:
    return openai.ChatCompletion.create(model="gpt-4", messages=[{"role": "user", "content": prompt}])
  • 价值:把生产真实 prompt / response 录下来,做 Few-shot 训练数据

六、数据库流量复制的"现代姿势"

2017 那篇没提,2024 数据库压测有专属方案:

  • MySQL Traffic Replay(MySQL 8.0+ 内置 mysqlbinlog | mysql 工具)
  • PostgreSQL pg_replay(第三方)
  • ShardingSphere 影子库应用层流量分流
  • tcpcopy + 数据库代理(如 ProxySQL):用 tcpcopy 抓 MySQL 流量复制到测试库
1
2
3
4
5
6
7
-- MySQL 8.0 录 binlog
mysqlbinlog --read-from-remote-server --host=prod-db --user=repl --password=xxx \
    --raw --stop-never-slave-server-id=1 \
    mysql-bin.000001 > /tmp/binlog.sql

# 拿到测试库
mysql -h test-db < /tmp/binlog.sql

七、流量复制的"合规边界"

  • 生产流量包含用户数据(手机号、地址、身份证)—— 复制到测试环境直接违反《数据安全法》《个保法》
  • 2024 合规要点
    • 脱敏:复制前 mask 敏感字段
    • 审计:所有流量复制要留审计日志
    • 数据隔离:测试环境的流量复制数据不能进生产库
    • 用途限制:复制的流量只能用于压测、调试,不能用于训练、对外展示
1
2
3
4
5
6
7
8
9
# 流量脱敏示例
import re

def mask_pii(payload: dict) -> dict:
    if 'phone' in payload:
        payload['phone'] = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', payload['phone'])
    if 'id_card' in payload:
        payload['id_card'] = payload['id_card'][:6] + '********' + payload['id_card'][-4:]
    return payload

源文档os/linux/第三方tools/net/tcpcopy/tcpcopy.md(完整安装步骤、路由配置、GLIBC 报错、iptables 配合)

使用 Hugo 构建
主题 StackJimmy 设计