ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

mitmproxy 代理性能剖析:test/bench 基准插件使用与源码解析

mitmproxy 代理性能剖析:test/bench 基准插件使用与源码解析 mitmproxy 代理性能剖析test/bench 基准插件使用与源码解析【免费下载链接】mitmproxyAn interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.项目地址: https://gitcode.com/GitHub_Trending/mi/mitmproxymitmproxy 仓库的test/bench目录内置了一套面向开发者自身的代理基准与剖析benchmark profiling工具以 addon 形式加载借助 wrk 与 devd 在真实 HTTP 负载下压测代理数据通路并同时输出 cProfile 统计结果。本文以 test/bench/README.md 为纲结合插件源码 benchmark.py、一键脚本与 addon 生命周期钩子实现完整讲解这套基准工具的安装、运行、产物解读与底层原理帮助你评估一次改动对 mitmproxy 代理吞吐与 CPU 开销的影响。这套基准工具是做什么的在 mitmproxy 源码仓库中test/bench是一个面向 mitmproxy 开发者的专用目录而不是给最终用户做的黑盒压测框架。它设计为加载一个自定义 addonbenchmark.py自动拉起一个 HTTP 后端并生成真实并发请求让请求穿过完整的 mitmproxy 代理链路同时输出两类结果wrk 生成的吞吐/延迟报告.bench与 PythoncProfile生成的性能剖析数据.prof。README 中说明了它的初衷为开发者提供一种快速看到自己的工作对性能影响的方式长远来看它可能演化成一个带历史数据的性能看板用于跨版本跟踪性能变化。也就是说它的价值更多是改完代码自己跑一下、对比前后的剖析数据而非发布给用户的性能承诺。运行前提需要安装的工具开始之前需要准备三样外部工具README 同时注明推荐安装 snakeviz 用于查看 profile。它们的作用在源码中可以一一对应工具用途在本目录中的角色wrkHTTP 负载压测工具由 benchmark.py 作为子进程启动对代理端口发起-c50、-d5s的请求devd静态文件/开发服务器由 benchmark.py 作为子进程启动作为被测的后端服务snakevizcProfile 结果可视化可选用于查看.prof剖析文件安装方式安装 wrkHTTP 压测工具与 devd其作者 cortesi 同是 mitmproxy 社区工具 devd 的维护者安装命令为 Go 模块方式go get github.com/cortesi/devd/cmd/devd安装 snakeviz 以便更方便地浏览剖析结果pip install snakeviz说明wrk 与 devd 均以子进程形式由插件 spawn请确保它们位于PATH中。快速开始一条命令跑完整基准在test/bench目录内执行下述命令即可mitmdump -p0 -q --set benchmark_save_path/tmp/foo -s ./benchmark.py参数含义-p0让 mitmproxy 的监听端口交给系统动态分配插件随后通过ctx.master.server.address[1]读取实际端口供 wrk 使用见 benchmark.py-q安静模式减少终端噪音--set benchmark_save_path/tmp/foo指定结果文件的前缀路径这是该 addon 通过loader.add_option注册的自定义选项详见下文-s ./benchmark.py以脚本addon方式加载基准插件。命令执行后将自动完成启动后端 → 运行压测 → 保存结果 → 退出的全流程产出两个文件/tmp/foo.bench—— wrk 输出的基准报告文本/tmp/foo.prof—— cProfile 二进制剖析数据。两个内置的一键脚本目录中还提供了两个 shell 脚本用于把结果集中保存到本地results/目录方便后续比较run-mitmdump用mitmdump运行无控制台界面纯数据通路mkdir -p results mitmdump -p0 -q --set benchmark_save_path./results/mitmdump -s ./benchmark.pyrun-mitmproxy用带交互界面的mitmproxy运行产物前缀改为./results/mitmproxymkdir -p results mitmproxy -p0 -q --set benchmark_save_path./results/mitmproxy -s ./benchmark.py两者的唯一区别是使用的可执行文件与结果文件前缀。开发者在对比控制台界面本身对代理主循环的开销时可以分别运行这两个脚本并对照.prof剖析结果。插件源码逐段走读整个基准逻辑集中在约 65 行的 benchmark.py理解它就能理解整套工具的数据流。我们从 addon 的声明说起。addon 入口文件末尾以标准 addon 导出方式声明addons [Benchmark()]Benchmark类benchmark.py在__init__中创建cProfile.Profile()实例并初始化请求/响应计数self.pr cProfile.Profile() self.started False self.resps 0 self.reqs 0load 阶段注册选项并开启剖析load(self, loader)benchmark.py是 addon 生命周期中最早被调用的钩子之一做了三件事注册自定义选项用于控制结果文件的落盘路径loader.add_option( benchmark_save_path, str, /tmp/profile, Destination for the .prof and .bench result files, )注意它的默认值是/tmp/profile——也就是说即使你不传--set benchmark_save_path...也会在结束时生成/tmp/profile.bench与/tmp/profile.prof。通过ctx.options.update(...)将当前 mitmproxy 实例切换为反向代理模式ctx.options.update( modereverse:http://devd.io:10001, )这是这套基准运行形态的关键wrk 发出的请求会经 mitmproxy 反向代理语义转发到后端 devd 服务。调用self.pr.enable()开始cProfile采样。ctx在此是 mitmproxy 提供的运行期上下文单例其中暴露ctx.master与ctx.options源码见 mitmproxy/ctx.py。running 阶段编排压测主流程addon 生命周期钩子runningbenchmark.py在代理完全就绪后被触发。由于一个会话中该钩子可能多次回调代码用self.started标志保证只启动一次基准任务def running(self): if not self.started: self.started True self._task asyncio.create_task(self.procs())真正干活的是协程procs()benchmark.py其编排逻辑为以子进程方式启动后端 devd-q安静模式、监听本机10001端口、以.当前工作目录作为静态文件根backend await asyncio.create_subprocess_exec(devd, -q, -p, 10001, .)以子进程方式启动 wrk用50 个并发连接、持续 5 秒向代理端口发起请求traf await asyncio.create_subprocess_exec( wrk, -c50, -d5s, http://localhost:%s/benchmark.py % ctx.master.server.address[1], stdoutasyncio.subprocess.PIPE, )ctx.master.server.address[1]读取的是代理实际监听的端口——这与命令行-p0系统动态分配端口配合保证无论分配到哪个空闲端口都能被正确压测。等待 wrk 结束并把其标准输出原样写入benchmark_save_path .benchstdout, _ await traf.communicate() with open(ctx.options.benchmark_save_path .bench, modewb) as f: f.write(stdout)打印代理内部统计日志与 wrk 报告清理后端并退出整个 mitmproxy 进程logging.error(fProxy saw {self.reqs} requests, {self.resps} responses) logging.error(stdout.decode(ascii)) backend.kill() ctx.master.shutdown()这一行日志非常有价值它告诉你的是从代理内部视角实际流经的请求/响应数与 wrk 侧看到的吞吐互为印证可以用来发现请求到达了但代理没处理完这类不一致。request / response 钩子代理视角的计数类中实现的两个数据流钩子benchmark.py分别对流经代理的 HTTP 请求和响应做累加def request(self, f): self.reqs 1 def response(self, f): self.resps 1done 阶段落盘剖析数据donebenchmark.py是 addon 收到的最后一个事件在进程退出前把 cProfile 采样结果 dump 成.prof文件def done(self): self.pr.dump_stats(ctx.options.benchmark_save_path .prof)addon 生命周期钩子背后的实现依据benchmark.py用到的load/running/done/request/response并不是随意命名的魔法方法而是 mitmproxy addon 钩子机制的一部分。在 mitmproxy/hooks.py 中可以看到所有钩子类都会把类名自动转换为小写下划线形式的事件名例如RunningHook→running、DoneHook→done。其中与本工具直接相关的两个生命周期钩子定义如下RunningHookmitmproxy/hooks.py在代理完全启动、所有 addon 与选项就绪后触发其 docstring 注明此时可以放心依赖所有 addon 与选项——这正是benchmark.py选择在running里发起压测子进程的原因DoneHookmitmproxy/hooks.py在 addon 被移除或 mitmproxy 自身关闭时触发且保证是 addon 收到的最后一个事件同时提示此阶段日志处理器可能已关闭。benchmark.py在此阶段 dump profile正是利用了它最后收尾的语义。如何解读基准产物.bench 文件它是 wrk 的原始文本输出包含请求总数、每秒请求数Requests/sec、平均/最大延迟、传输字节数等统计。这是吞吐与延迟视角的结果用于回答改动后代理每秒能扛多少请求、延迟是否恶化。.prof 文件它是cProfile的二进制统计文件用于回答CPU 时间花在了哪些函数上。推荐用 snakeviz 打开以树状图交互式浏览调用热点snakeviz /tmp/foo.prof开发者在优化前后各跑一次用 snakeviz 对比热点函数占比变化即可量化本次改动的剖析开销。终端日志即使不解析文件插件退出前还会在终端打印Proxy saw N requests, M responses与 wrk 报告全文benchmark.py方便快速扫一眼结论。注意事项与适用边界基于代码实现使用这套工具时有几点需要留意运行目录有讲究devd 以.为静态根目录、-s ./benchmark.py也依赖相对路径因此推荐在 test/bench 目录内执行命令或直接运行./run-mitmdump/./run-mitmproxy且mitmdump/mitmproxy需在PATH中。一次会话只跑一轮running钩子通过started标志保证仅启动一次随后ctx.master.shutdown()会让整个进程自行退出。结果文件是覆盖式写入benchmark_save_path指向的目标会直接被覆写若要保留历史对比请每次更换路径这正是两个 run 脚本用results/目录的原因。结果偏向整机环境作为本地快速回归工具其吞吐数据受宿主 CPU、后端 devd 性能与并发设置固定-c50 -d5s影响适合做改动前后的相对对比不适合作为对外宣称的绝对性能指标。README 也明确当前仅用于开发者快速查看自己改动的影响。另一种基准思路pytest-benchmark 单元基准如果你关注的是代理各层协议栈内部的单点开销而不是端到端吞吐仓库还提供了一条基于pytest-benchmark的路线test/mitmproxy/proxy/bench.py。它的用法文件头部 docstring为- pip install pytest-benchmark - pytest bench.py其中定义了多个基准用例覆盖 HTTP、HTTP/2、TCP、TLS仅服务端、仅客户端、双向等往返场景例如test_bench_http_roundtrip复用test_http的代理往返测试交给 pytest 的benchmarkfixture 计时test_bench_tcp_roundtrip对 TCP 简单用例做deepcopy隔离后计时test_bench_server_tls/test_bench_client_tls/test_bench_tls_both分别测量 TLS 握手涉及服务端证书、客户端认证、双向认证的开销。它与 test/bench 形成互补前者在单元层用固定测试夹具反复执行某个协议往返并取统计后者在集成层用真实 wrk 负载穿透整个代理。两者都锚定在test/目录下benchmark 相关测试改动代理核心后配合使用可同时获得宏观吞吐 微观热点两方面的反馈。小结test/bench是一套轻量而完整的 mitmproxy 性能回归工具外围靠 wrk devd 构造真实负载内核由一个生命周期清晰的 addonbenchmark.py驱动——load注册选项并开启剖析、running编排子进程发起压测、request/response做代理视角计数、done落盘.prof。配合.bench文本报告、snakeviz可视化以及 proxy 层的 pytest 单元基准你可以快速验证自己的改动究竟给这个 TLS 拦截代理带来了多大的性能影响。【免费下载链接】mitmproxyAn interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.项目地址: https://gitcode.com/GitHub_Trending/mi/mitmproxy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进