做网络联调的时候,最怕的不是功能没写完,而是功能写完了,一上线才发现弱网下一塌糊涂:接口超时、图片加载失败、WebSocket 频繁断连、音视频卡成 PPT。这类问题靠“正常网络”很难复现,所以需要一台能主动制造故障的机器。这次我们看的 Bean Network Tester 就是干这个的:一个开源的坏网络模拟器,专门给应用制造丢包、延迟、抖动和带宽限制,帮你把弱网问题提前暴露在测试阶段。
它最值得关注的点是四个:开源可自部署、规则可以灵活组合、能把常见的网络故障变成可重复的测试场景、非常轻量。它是纯网络工具,不依赖显卡,不需要大内存,普通开发机或者一台小服务器就能跑。对做前端、后端、移动端、音视频和实时通信的同学来说,这篇文章可以直接收藏。
下面按部署流程来讲:环境准备、启动服务、配置干扰规则、验证效果、观察资源占用,最后给一套排错清单和最佳实践。部分命令和路径是通用模板,实际使用时需要替换成本机项目的真实值。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 开源网络干扰/弱网模拟器 |
| 开源状态 | 开源项目,发布于 Hacker News Show HN |
| 主要功能 | 模拟丢包、延迟、抖动、带宽限制、乱序、连接异常等网络故障 |
| 工作方式 | 在网卡或网桥上注入网络规则,影响经过该接口的流量 |
| 硬件要求 | 无特殊要求,普通 x86/ARM Linux 主机即可 |
| 操作系统 | 优先推荐 Linux 环境,依赖内核网络模块 |
| 启动方式 | 服务进程启动 + Web 界面/命令行配置,具体以项目 README 为准 |
| 接口 API | 视具体版本而定,可提供 HTTP 接口供自动化调用 |
| 批量任务 | 支持通过场景预设和脚本批量下发规则 |
| 适合场景 | 开发自测、联调测试、CI/CD 故障演练、性能压测辅助 |
从资料来看,这个项目最大的优势是“把坏网络变成可重复的实验”。不依赖实体网络设备,不需要手动拔网线,也不需要两台机器之间来回切,直接用软件在协议栈层面制造故障,测试完一键清理。
有一点要提前说明:这类工具只能用于你自己拥有的、或明确获得授权的测试环境,不能对生产环境、公网服务、第三方系统做干扰测试。这个边界后面还会反复提到。
2. 适用场景与使用边界
2.1 适合谁
Bean Network Tester 最典型的用户是这几类:
- 前后端联调工程师。接口在弱网下超时、重试、降级逻辑是否正常,通过模拟 10% 丢包或 300ms 延迟就能快速重现。
- 移动端和桌面端开发。App 在 2G/3G 网络下的表现,通过限制带宽和增加抖动来模拟。
- 音视频与实时通信开发。通话质量、推流稳定性、WebRTC 的拥塞控制,都需要延迟和丢包这两个关键参数来做故障注入。
- 后端故障演练。服务在依赖链路不稳定时,熔断、限流、降级是否正确触发。
- CI/CD 质量门禁。在自动化流水线里加一段弱网用例,每次发布前自动跑一遍。
2.2 能解决的问题
这类工具解决的核心问题只有一个:让网络故障变得可控、可量化、可复现。
假设你的应用在用户反馈里出现“视频通话经常卡”,你可以在本地搭建一套测试环境,把延迟设为 200ms、丢包率设为 5%,然后反复重启通话、切换网络、调整码率,观察应用是否有合理表现。这个过程完全可重复,并且每次的参数是确定的,比依赖真实弱网环境要高效得多。
2.3 不适用和不允许的场景
这里必须画一条清清楚楚的线:
- 不要对生产服务器做干扰测试。
- 不要对公网域名、云厂商的 SLA 探测或第三方 API 做延迟/丢包注入。
- 不要对你自己没有完整控制权的环境做网络干扰。
- 未经授权不要对同事的机器、客户的网络、学校或公司的公共网段下发规则。
- 不要用它去攻击、绕过安全机制或做任何形式的影响他人行为。
它的正确用法,是在一个你能完全掌控的网络命名空间、虚拟网卡或 Docker 容器里做故障注入。测试前留好清理手段,测试后确认规则已撤销。
3. 环境准备与前置条件
3.1 操作系统
优先准备一台 Linux 主机,发行版不限,Ubuntu/Debian/CentOS 都行。这类网络模拟工具通常依赖 Linux 内核的流量控制模块,最常见的是tc和netem模块。如果项目本身提供 Docker 镜像,那也可以通过容器方式运行,降低对宿主机内核模块的直接操作。
如果你手头只有 macOS 或 Windows,建议先开一台 Linux 虚拟机,或者在 WSL2 环境里测试。Windows 的 Hyper-V 虚拟网卡对流量控制支持不完整,直接用可能会遇到规则不生效的问题。
3.2 依赖项检查清单
| 检查项 | 作用 | 怎么确认 |
|---|---|---|
| root 权限或 sudo | 修改网卡流量控制配置需要权限 | sudo -v |
tc命令 | 检查链路是否支持规则注入 | tc -s qdisc show |
| 内核 netem 模块 | 延迟/丢包/抖动模拟的基础 | modprobe sch_netem |
| Docker | 可选的容器化部署方式 | docker --version |
| Node.js/Python | 取决于项目服务端的运行时 | node -v/python3 -V |
| 磁盘空间 | 一般占用极小,几百 MB 足够 | df -h |
如果modprobe sch_netem报错,说明当前内核没有加载该模块。需要确认内核版本,并安装linux-modules-extra之类的扩展包。不同发行版包名不同,具体以当前系统的包管理器为准。
3.3 网络环境
测试时最好准备一个独立的网卡接口。如果你跑在本地虚拟机,可以用一个独立的虚拟网络接口;如果跑在容器里,优先使用 bridge 网络模式,这样干扰规则作用于容器网卡,不会影响宿主机其他流量。
临时测试可以不用独立网卡,直接对当前接口操作,但风险在于:如果规则配置错误,可能把自己 SSH 远程连接都断掉。所以“通过 SSH 远程操作时,不要对管理网卡做高延迟、高丢包实验”,这条要作为铁律来执行。
4. 安装部署与启动方式
4.1 通用安装步骤
先从项目仓库 clone 代码,再按 README 的说明安装依赖并启动服务。下面是通用模板:
# 拉取项目源码,路径需要替换为实际仓库地址 git clone https://github.com/your-org/bean-network-tester.git cd bean-network-tester # 如果是 Node.js 项目 npm install npm start # 如果是 Python 项目 pip install -r requirements.txt python main.py具体是npm还是pip,以项目 README 为准。启动后一般会输出一个监听地址,格式类似Listening on 0.0.0.0:xxxx,这个地址就是你的访问入口。
4.2 通过 Docker 启动
如果项目提供了 Docker 镜像,部署会更干净。通用模板如下:
# 构建镜像 docker build -t bean-network-tester . # 启动容器,端口映射需要根据实际监听端口调整 docker run -d --name bean-net \ --network host \ --cap-add NET_ADMIN \ -p 8080:8080 \ bean-network-tester特别注意--cap-add NET_ADMIN,这个权限缺失会导致容器内无法修改流量控制规则。如果你看到 "Operation not permitted" 一类的报错,优先检查这一项。
4.3 启动后要确认什么
服务启动不是结束,启动后第一件事是确认三件事:
- 服务进程还活着,没有反复重启。
- 接口地址能访问,本地 curl 能通。
- 日志里没有权限相关报错。
# 查看服务进程 ps aux | grep bean-network # 访问本地接口,端口按实际日志替换 curl -I http://127.0.0.1:8080如果服务正常返回响应,说明基础环境没问题,可以开始配置干扰规则了。
5. 功能测试与效果验证
下面按“测试目的、操作步骤、预期结果、失败排查”的格式,逐一覆盖核心干扰能力。这里的所有规则参数都是示例,使用时以项目和本机网络环境为准。
5.1 丢包模拟
丢包是最常见的弱网表现。测试目的是验证应用在数据包丢失时的重传、重连和降级机制。
操作方式有两种。如果工具自带界面,直接建一个 rule,设置丢包率 5% 或 10%;如果走命令行底层,通用tc命令如下:
# 在 eth0 网卡上引入 10% 丢包 sudo tc qdisc add dev eth0 root netem loss 10%验证方式:
# 从另一台机器 ping 测试机的 IP ping -c 30 192.168.1.100预期结果:ping 的丢包率接近 10%,响应时间会略有波动。应用侧应该能看到连接超时或重试日志。
如果丢包率远低于设置值,说明规则没生效,或者测试流量根本没走这个网卡。排查时先看tc qdisc show是否有输出。
5.2 延迟模拟
延迟影响的是用户体验:页面加载速度、接口响应时间、实时通话的端到端时长。
# 在 eth0 网卡上引入 200ms 固定延迟 sudo tc qdisc add dev eth0 root netem delay 200ms # 增加 jitter,让延迟在 180ms 到 220ms 之间波动 sudo tc qdisc add dev eth0 root netem delay 200ms 20ms验证时用ping观察往返时间:
ping -c 20 192.168.1.100预期看到 RTT 比基线增加约 400ms(因为 ping 是来回两条链路,各加一次延迟)。如果配置了 jitter,会发现 RTT 数值在上下跳动。
应用侧观察点:接口请求时间是否符合预期,超时配置是否触发了重试逻辑,前端 loading 状态是否有兜底。
5.3 抖动模拟
抖动是实时通信里影响最大的参数之一。它会导致音频断续、视频卡顿、画质自适应频繁切换。
操作时设置“基础延迟 + 抖动幅度 + 相关性”三个参数:
sudo tc qdisc add dev eth0 root netem delay 100ms 40ms 25%这里的参数含义是:基础延迟 100ms,抖动幅度 40ms,相邻数据包之间抖动值有 25% 的相关性。相关性越高,抖动越接近真实网络的状态。
验证方式:用 iperf3 打流,观察带宽和丢包曲线;或者跑一段 WebRTC 通话,看接收缓冲和分辨率变化。
5.4 带宽限制
带宽限制用来模拟弱网下的限速场景。最常见的验证是:低带宽下,图片是否懒加载、视频是否自动降清晰度、上传任务是否走分片。
# 限制 eth0 带宽为 1Mbps sudo tc qdisc change dev eth0 root netem rate 1mbit验证方式:用iperf3两端打流,看实际吞吐是否被限制到设定值附近。
iperf3 -c 192.168.1.100 -t 10应用侧验证:上传一张大图,看是否走了分片上传;播放视频,看是否自动切换低码率。
5.5 乱序与连接异常
乱序对 TCP 有影响,对 UDP 影响更大,常见于弱网环境下的实时音视频。连接异常则是直接模拟服务不可达或连接被重置,用来验证应用的异常兜底逻辑。
通用命令示例:
# 让 25% 的数据包延迟 50ms 后再发出,模拟乱序 sudo tc qdisc add dev eth0 root netem delay 50ms reorder 25% # 清理所有网卡规则 sudo tc qdisc del dev eth0 root连接异常这类功能,如果工具提供了开关,可以直接触发;如果没有,通常用“防火墙丢包”或“暂停容器”的方式配合测试。应用侧预期表现是:错误提示明确、自动重试机制生效、崩溃兜底可用。
5.6 功能测试总结
从实际测试流程看,建议按下面的顺序执行:
- 先测延迟,因为最简单,效果最直观。
- 再测丢包,观察应用重试逻辑。
- 然后测抖动,重点看实时链路。
- 最后测带宽限制,验证自适应码率和流控逻辑。
- 每一项测完都清理规则,再做下一项。
这样能保证每一次干扰只改一个变量,定位问题更准确。
6. 接口 API 与批量任务
6.1 API 接口设计
绝大多数网络模拟器都可以通过接口自动下发规则。由于不同项目的接口路径不同,下面给一个通用调用模板,实际使用时需要用项目文档里的真实路由替换。
# 通用 POST 接口示例,路径和端口需要按实际项目调整 curl -X POST http://127.0.0.1:8080/api/scenario \ -H "Content-Type: application/json" \ -d '{ "target": "eth0", "loss": 10, "delay_ms": 200, "jitter_ms": 20, "bandwidth_mbit": 10 }'如果项目支持删除规则,通常是对应一个 DELETE 接口:
# 清理规则 curl -X DELETE http://127.0.0.1:8080/api/scenario注意:调 API 之前先确认目标网卡没有在跑重要业务流量。一旦规则下发,影响会立刻生效。
6.2 Python 批量任务示例
批量任务的典型使用方式,是把多个场景串起来,按顺序执行,并输出结果。下面这个 Python 脚本是通用模板,它的逻辑是:先并发下发三个场景,等待几秒,然后清理。
import requests import time BASE_URL = "http://127.0.0.1:8080" scenarios = [ { "name": "mild", "loss": 1, "delay_ms": 50, "jitter_ms": 5, }, { "name": "medium", "loss": 5, "delay_ms": 150, "jitter_ms": 20, }, { "name": "severe", "loss": 15, "delay_ms": 400, "jitter_ms": 80, } ] for sc in scenarios: response = requests.post(f"{BASE_URL}/api/scenario", json=sc, timeout=5) print(f"{sc['name']}: {response.status_code}") # 每个场景保持一段时间,方便应用侧观察 time.sleep(10) # 测试结束统一清理 requests.delete(f"{BASE_URL}/api/scenario", timeout=5) print("cleanup done")6.3 批量任务注意事项
批量任务真正的价值不是同时制造大量故障,而是让多个测试环境共享同一套“故障模板”。推荐做法是:
- 把一个场景定义为一个 JSON 文件,入库到测试方案仓库。
- 每次 CI 跑批之前先清理所有旧规则。
- 每个场景执行完自动记录应用侧指标,如成功率、延迟分位数、错误码分布。
- 失败时先检查规则是否生效,再检查应用日志。
另一个关键点是做失败重试。网络测试本身有波动,一次失败不代表应用有问题。建议在每个场景上设置重跑次数,例如每个场景连续跑三次,两次以上失败才标记为回归问题。
7. 资源占用与性能观察
7.1 工具本身的开销
Bean Network Tester 这类工具本身的资源占用很低。它只是在协议栈层面配置规则,不做数据包代理,也不转发流量,所以 CPU 和内存消耗可以忽略。部署在 1 核 1G 的轻量服务器上完全没有问题。
真正需要关注的是:干扰规则生效后,对被测应用性能的影响。这个影响正是你想要的,但要把“工具开销”和“干扰效果”区分开。
7.2 怎么观察资源占用
观察宿主机和被测服务的资源占用,用这几个命令就够了:
# 查看 CPU 和内存 top # 查看网络流量 nload iftop # 查看网卡错误和丢包统计 ip -s link show eth0 # 查看当前流控规则 tc -s qdisc show dev eth0在测试时,每秒记录一次被测服务的响应时间、错误率、重传率,对比有无干扰规则时的差异,就能量化故障造成的影响。
7.3 干扰参数对效果的影响
| 参数 | 影响 | 调整建议 |
|---|---|---|
| 丢包率 | 连接成功率、重传次数 | 先 1% 再 5% 再 10%,逐步加压 |
| 延迟 | 接口耗时、RTT | 100ms 起步,根据业务容忍度调整 |
| 抖动 | 实时链路稳定性 | 配合延迟一起调整 |
| 带宽 | 吞吐量、自适应码率 | 1Mbit 到 10Mbit 之间做梯度 |
| 批量数 | 规则下发的并发压力 | 一般不需要超过 5 个场景同时生效 |
一个常见误区是:把丢包率和延迟同时设到极端值,导致应用直接不可用,无法定位到底哪个因素造成的。更合理的做法是逐项调整,记录每项的效果。
7.4 降低测试干扰风险的方法
如果测试环境是远程服务器,可以通过这几项操作降低风险:
- 不要在管理网卡上做高丢包实验。
- 所有规则设置一个自动过期时间,或用脚本在 N 秒后清理。
- 测试前保存当前规则的快照,出问题可以一键回滚。
- 尽量在 Docker 容器或网络命名空间内测试,隔离到独立接口。
8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 规则下发后没有效果 | 网卡接口选错了 | tc qdisc show dev eth0确认规则挂在哪个接口 | 换到实际流量的网卡接口 |
| 报 “Operation not permitted” | 权限不足或容器缺少 NET_ADMIN | 查看服务日志和启动方式 | 用 root 运行,或给容器增加 NET_ADMIN 权限 |
| 启动后提示缺少内核模块 | sch_netem 模块未加载 | modprobe sch_netem测试 | 安装 linux-modules-extra 并重启加载 |
| 高延迟时 SSH 断连 | 对管理网卡做了干扰 | 用另一个终端登录检查规则 | 清理规则,后续只对非管理接口操作 |
| 端口冲突 | 服务默认端口被占用 | ss -tlnp查看端口占用情况 | 修改启动配置或杀掉占用进程 |
| 清理规则后依然有延迟/丢包 | 多路径或多层网络设备叠加 | 在测试机上逐层检查 tc 规则和路由器配置 | 清理所有 qdisc,并检查链路中其他设备 |
| API 调用返回 404 | 接口路径不是项目默认路径 | 查看项目文档的接口定义 | 替换为正确的路径 |
| 批量任务跑到一半卡住 | 场景数据量过大或并发过高 | 查看应用日志和资源占用 | 减少并发场景,增加超时和重试 |
| 容器内规则正常,宿主机流量不受影响 | Docker 网络模式隔离 | 确认容器运行方式和网卡连接方式 | 改用 host 网络模式或直接对宿主机接口配置 |
| 规则在重启后失效 | qdisc 规则没有持久化 | 重启后tc qdisc show查看 | 写启动脚本自动恢复规则 |
这里重点提示两个最容易踩的坑:
第一个是接口选错。你配置规则时觉得“明明下发了,怎么没效果”,实际可能是流量走的是 eth1,你配置的是 eth0。先用ip route get 目标IP确认数据包真正走哪张网卡。
第二个是权限问题。很多网络模拟工具在普通用户下无法加载内核模块,启动时不会立刻报错,但配置规则时才会失败。日志里出现 "Operation not permitted" 时,优先检查运行用户的权限和容器的cap-add配置。
9. 最佳实践与使用建议
9.1 建立测试环境基线
使用干扰工具之前,先在没有干扰的条件下跑一遍完整业务,记录延迟、丢包、吞吐的基线数据。基线的意义在于,干扰后的指标和谁对比、优化效果如何衡量,都需要数字支撑。
9.2 场景模板化
把常见弱网场景固化成配置模板,而不是临时手工调整参数。推荐的模板包括:
| 场景名 | 延迟 | 丢包 | 抖动 | 带宽 | 用途 |
|---|---|---|---|---|---|
| 弱网-轻度 | 80ms | 1% | 10ms | 10Mbit | 日常自测 |
| 弱网-中度 | 200ms | 5% | 30ms | 2Mbit | 联调验证 |
| 弱网-重度 | 500ms | 15% | 80ms | 500Kbit | 故障演练 |
| 无响应 | 1000ms | 50% | 200ms | 100Kbit | 极限兜底测试 |
模板文件建议纳入版本管理,每个模板说明适用场景和预期影响,团队成员共同维护。
9.3 自动化集成
如果项目提供了 API,可以把弱网测试接入自动化流水线。推荐的流程是:
- 先执行单元测试和功能测试。
- 再拉起测试环境,下发弱网场景。
- 跑冒烟用例和应用层性能测试。
- 记录指标,与基线对比。
- 退出前清理所有规则。
这样做的好处是,每次发布前都能自动化覆盖“弱网兼容性”这一维度,不用等用户反馈。
9.4 合规与安全使用
最后再强调一次安全边界:这个工具只能用于你拥有或已获得授权的测试环境。禁止在生产环境、公网服务、第三方系统、未经授权的网络设备上使用。测试前要确保不会影响到其他业务;测试中要有专人盯着;测试后要确认规则完全清理。任何形式的网络干扰行为,都要在权限范围内执行。
9.5 输出结果管理
测试产生的日志、指标、截图建议统一存放。比如按日期和场景名建立目录:
./test-results/ 2025-01-15/ mild/ app-logs/ network-metrics.csv summary.json severe/ app-logs/ network-metrics.csv summary.json这样事后复盘时,可以准确知道某个问题是在什么网络参数下出现的,修复后又能用同一场景回归。
10. 总结与下一步
Bean Network Tester 是一个值得放进测试工具箱的开源网络模拟器。它解决的问题很具体:用可控、可重复的规则注入,让弱网问题在开发阶段就暴露出来。它不复杂,也不吃硬件,轻量到一台小服务器就能承载完整的故障注入场景。
最先建议验证的功能是延迟和丢包模拟,因为这两个参数最能体现弱网问题的根因,也最容易观察效果。最容易踩的坑是“接口选错”和“权限不足”,测试前先把这一点检查清楚,后面会顺利很多。
如果你正在做前端页面、后端接口、移动端 App、实时音视频或者 IoT 相关的开发调试,可以先用它跑一遍基础弱网场景,看看应用的表现是否匹配预期。后续值得继续深化的方向是:把场景模板接入自动化 CI,形成持续回归能力;再叠加多节点、多链路组合故障,模拟更接近真实弱网环境的情况。
这类工具的最终价值不是“能把网络搞坏”,而是“能在可控范围内把网络搞坏,再用测试结果把应用修得更稳”。下一篇文章可以围绕具体的接入案例展开,例如怎么把弱网模拟器嵌入 Webrtc 通话质量测试流程,欢迎收藏备用。