ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Opik 负载压测实战:用 tests_load 验证 Python SDK 的追踪摄取能力

Opik 负载压测实战:用 tests_load 验证 Python SDK 的追踪摄取能力 Opik 负载压测实战用 tests_load 验证 Python SDK 的追踪摄取能力【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm导读本文基于开源仓库 comet-llmOpik中的 tests_load/README.md 及其配套源码系统讲解如何对 Opik 的 Python SDK 与后端进行端到端负载压测。你将掌握 tests_load 目录的两级结构独立 CLI 脚本与 pytest 压测套件、10 个覆盖不同摄取形态的压测场景、统一的三阶段验证契约提交 → flush → 轮询校验以及如何通过--load-scale缩放压测规模、如何在本地 docker-compose 部署上手动复跑、如何在 CI 中按周自动执行并沉淀指标报告。读完即可在你的本地环境中复现全部压测流程。tests_load 目录的两层结构即席脚本与可调度套件tests_load目录将压测代码明确划分为两类职责不同、互不干扰tests/— 独立 CLI 脚本用于临时性、一次性的性能探测实验。它们不会被 pytest 收集适合快速手测某个具体问题。suite/target/— 由 pytest 驱动的压测套件既可在 CI 中按计划任务schedule运行也可手动触发。每个子目录针对一个被测系统当前只有python_sdk/未来的被测目标如 TypeScript SDK、仅后端等会以同级目录的形式加入例如suite/typescript_sdk/。这种“脚本探路、套件回归”的分层设计使得 ad-hoc 实验临时脚本与可重复的回归压测pytest 套件可以并存而不会互相污染。套件的完整实现位于 tests_load/suite/python_sdk/对应的 pytest 配置在 tests_load/pytest.ini。本地安装 Opik 并让 SDK 连接被测环境压测的首要前提是有一个可用的 Opik 后端。README 给出的标准做法是使用 docker-compose 部署本地实例对应 deployment/docker-compose/ 下的部署文件部署完成后Python SDK 的配置读取来源为环境变量或~/.opik.config对于本地 docker-compose 全栈安装需要把 SDK 指向前端代理地址export OPIK_URL_OVERRIDEhttp://localhost:5173/api/OPIK_URL_OVERRIDE是 SDK 读取的核心配置项之一它覆盖默认的 API 基地址。压测套件本身与运行环境无关——它只读取 shell 中已设置的OPIK_*环境变量配置工作由调用方负责。这意味着同一个套件可以无缝切换目标export OPIK_URL_OVERRIDEhttp://localhost:5173/api/ # 完整本地栈前端 后端 # export OPIK_URL_OVERRIDEhttp://localhost:8080 # 仅后端./opik.sh --backend # export OPIK_URL_OVERRIDEhttps://www.comet.com/opik/api/ OPIK_API_KEY... OPIK_WORKSPACE...Python SDK 压测套件四大摄取形态与十个场景suite/python_sdk/ 下的套件覆盖了四类摄取形态高条数、大负载、附件、突发/并发/时间分布外加数据集版本链。默认规模面向每周一次的定时压测而设计——而非 PR 检查——因此每个场景都能产生有意义的负载。可通过--load-scale缩小规模做本地冒烟测试。文件 / 场景默认规模test_ingestion_rate.py::test_many_traces_one_span_each10 万条 trace × 1 个嵌套 span约 100 B 负载test_ingestion_rate.py::test_many_spans_per_trace5 千条 trace × 50 个 span 25 万个 span约 100 B 负载test_heavy_payload.py::test_traces_with_one_megabyte_payload500 条 trace ×1 MB 入 1 MB 出≈ 1 GBtest_heavy_payload.py::test_spans_with_heavy_payload200 条 trace × 5 个 span ×500 KB 入 500 KB 出≈ 1 GBtest_attachments.py::test_traces_with_explicit_attachments500 条 trace × 2 个 × 50 KB 附件 ≈ 50 MB1 千次上传test_attachments.py::test_traces_with_implicit_attachments500 条 trace × 400 KB base64 数据块自动提取为附件test_bursts.py::test_burst_single_loop5 万条 trace紧循环、无思考间隔test_bursts.py::test_spread_over_time1 万条 trace均匀分布在 10 分钟内test_bursts.py::test_concurrent_writers_share_one_client30 线程 × 1 千条 trace 3 万条 trace共享一个 clienttest_dataset_items.py::test_dataset_insert_many_versions50 次顺序Dataset.insert()× 50 个 item × 约 4 KB 负载 2.5 千个 item、50 个版本高条数场景test_ingestion_rate.py该文件包含两个互为正交的吞吐场景源码位于 test_ingestion_rate.pytest_many_traces_one_span_each通过opik.track装饰器模拟“用户请求处理器handle_request调用一次下游服务downstream_call”的典型形态——每次调用产生一条带嵌套 span 的 trace。10 万条 trace × 1 span ≈ 20 万条观察数据。负载刻意保持 100 B 的小体积以便把压力集中在消息条数而非单条消息体积上。test_many_spans_per_trace改用opik.start_as_current_trace与opik.start_as_current_span上下文管理器模拟用户对 trace/span 生命周期有显式控制的场景。5 千条 trace × 50 span 25 万 span重点考验 span 批量发送与 trace/span 顺序保证。测试除了校验全部 trace id 落地还会抽查最后一条 trace 的 50 个 span是否全部可见且字段完整。大负载场景test_heavy_payload.py见 test_heavy_payload.py验证 MB 级 payload 下的链路吞吐test_traces_with_one_megabyte_payload每条 trace 的 input 与 output 各约 1 MB装饰器自动捕获函数入参与返回值等价于包装一个“长 prompt 进、长 completion 出”的 LLM 调用共约 1 GB 负载。test_spans_with_heavy_payload外层 trace 保持轻量约 1 KB内部 5 个 span 各携带约 500 KB 的 input/output总计约 1 GB。专门考验父 trace 轻、子 span 重时 span 批量发送的表现。附件场景test_attachments.pytest_attachments.py 覆盖两条附件上传路径显式附件在opik.track装饰的 handler 内通过opik.update_current_trace(attachments[...])为每条 trace 挂载 2 个 50 KB 的二进制附件压测 multipart 上传路径以及flush_tracker()对在途上传的协调契约。隐式附件handler 接收一个data:image/png;base64,~400 KB的 image 参数。由于嵌入的 base64 数据超过 SDK 的min_base64_embedded_attachment_size默认 250 KBSDK 的附件提取管线会自动识别并上传为附件无需用户显式操作——这正是多模态 LLM I/O 日志场景中最常见的路径。实现细节上_helpers.random_base64_png生成的是能被 SDK 提取管线识别的“伪 PNG”一是提取正则限定[A-Za-z0-9/]必须用标准 alphabet 的b64encode而非 url-safe 的-_变体二是解码端会做 MIME 嗅探跳过application/octet-stream与text/plain因此字节流必须以 PNG 魔数\x89PNG\r\n\x1a\n开头。魔数之后的字节全是随机噪声——测试并不渲染图片只验证提取/上传链路见 _helpers.py。突发与并发场景test_bursts.pytest_bursts.py 包含三种时间形态test_burst_single_loop单线程紧循环调用 5 万次opik.trackhandler仅保留套件共用的最小随机思考间隔0.5–2 ms由_helpers.think_time()提供。这个间隔足以避免并行运行多个重场景时压垮 docker-compose 栈又足够紧凑以持续占满 SDK 的进程内队列与批量 flusher。test_spread_over_time1 万条 trace 均匀铺在 600 秒窗口内约 17 trace/s 持续速率模拟中速生产负载并专门触发按时间间隔而非按批量大小触发的周期性 flush 路径。test_concurrent_writers_share_one_client30 个线程通过ThreadPoolExecutor同时调用同一个全局 Opik clientopik.track默认使用的那个每条调用经线程本地上下文获得独立 trace——完全等同于真实多线程服务器的用法。这是最可能暴露 batcher 竞态race的配置。数据集版本链场景test_dataset_items.pytest_dataset_items.py 是套件中最具“回归守门人”色彩的场景。每次Dataset.insert()调用都会在后端创建新版本后端通过 ClickHouse 的INSERT … SELECTCOPY_VERSION_ITEMS把上一版本的 item 快照进新版本。在多副本 ClickHouse 部署上该 SELECT 可能非确定性地返回短读截断新版本的行集随后每个后续版本都会基于被截断的基线级联放大损失。该测试通过 50 次顺序Dataset.insert()每次 50 个 item、约 4 KB/个并断言dataset.get_items()能完整回读全部 2.5 千个 item 来捕捉这类“元数据与存储不一致”问题items_total报 N 但流式返回更少。需要强调的是这类数据丢失是纯服务端问题单线程顺序 REST 调用即可触发但在单副本 localhost 上无法复现——因此该测试在多副本生产/预发环境跑通的价值在于提供绿色基线一旦出现短读即失败报警。每个测试的统一执行契约log → flush → verify → 指标落盘README 明确规定每个测试都遵循四个步骤记录请求的 trace/span涉及附件时一并上传调用opik.flush_tracker()轮询search_traces/search_spans/attachments.attachment_list直到预期数量的条目可见——只有每条数据都落库测试才算通过把各阶段耗时logging、flush、verify、total写入tests_load/.last_run/test_name.json。这套契约在 _helpers.py 中有完整的实现支撑Metrics一个极简的 key/value 记录器提供timer(label)上下文管理器记录各阶段耗时由metricsfixture 在 teardown 时写入REPORT_DIR即tests_load/.last_run/。写入的 JSON 同时会以日志形式输出便于 CI 汇总。verify_exact_trace_ids等待所有expected_ids落库并返回实际送达的 id 集合若超时仍有缺失则抛出带缺失样本的AssertionError——这能捕捉消息丢失如回归案例 OPIK-6444而不只是数量不足。verify_traces轮询search_traces默认 900 秒超时。在响应中通过exclude[input, output, metadata]排除大字段一是大幅减少高条数场景的回传数据量二是绕开 OPIK-6651附件提取的 trace 在流式返回时因 enrichment 路径读取不到workspaceName而失败的缺陷。name/end_time字段校验仍然执行。verify_spans_for_trace对指定 trace 轮询search_spans直至预期 span 数可见并断言name、end_time、input、output四个必需字段全部非空。verify_attachments轮询附件 REST 端点attachment_list直到数量达标。path查询参数是经 base64 编码的 base URL后端据此构建下载链接必须用标准b64encodealphabet 以匹配attachment/client.py与tests/e2e/verifiers.py的既有契约。安装与运行从冒烟测试到全量压测环境准备# 安装 Opik SDK本仓库源码安装或 pip install opik 使用已发布版本 pip install -e sdks/python # 安装套件专属依赖 pip install -r tests_load/suite/python_sdk/requirements.txt # 把 SDK 指向任意 Opik 实例 export OPIK_URL_OVERRIDEhttp://localhost:5173/api/ # 完整本地栈 # export OPIK_URL_OVERRIDEhttp://localhost:8080 # 仅后端./opik.sh --backend # export OPIK_URL_OVERRIDEhttps://www.comet.com/opik/api/ OPIK_API_KEY... OPIK_WORKSPACE...套件专属依赖由 tests_load/suite/python_sdk/requirements.txt 声明仅包含pytest、pytest-timeout、pytest-xdist——Opik SDK 本身单独安装避免混入版本耦合。串行 / 并行运行cd tests_load pytest suite/python_sdk # 串行 pytest suite/python_sdk -n auto --distworksteal # 经 pytest-xdist 并行关于并行度的取舍README 记录了明确的工程决策定时工作流固定使用-n 2 --distworksteal。因为-n auto在 ubuntu-latest 上是 4 个 worker在高负载摄取场景与其他重测试同时压同一个 docker-compose Opik 栈时会在 7 GB runner 上可靠地触发 OOM 杀掉进程。每个场景使用唯一 project 名_helpers.unique_project_name生成loadtest-scenario-时间戳-随机串因此 worker 隔离成立共享后端在并行下会看到有意义的并发负载这本身就是有价值的覆盖。pytest 配置的防呆设计tests_load/pytest.ini 中有几个值得关注的全局守卫testpaths suitepytest 默认只收集套件目录独立脚本tests/不会被误收。timeout 1200、timeout_method thread全局挂起守卫——任何单个场景运行超过 1200 秒即被杀并判失败避免死锁如 SDK 锁回归无声消耗整个工作流预算。最长合法场景是test_spread_over_timescale 1.0 时约 10 分钟1200 秒约留出 2 倍余量需要更紧上限的场景可用pytest.mark.timeout(...)覆盖。log_cli_level WARNING不输出 INFO 级别日志避免约 25 万 次 httpx 请求的INFO HTTP Request行在-n 2与 SDK 连接监控守护进程叠加时曾产生约 7 万行 traceback。每个测试的指标仍会写入.last_run/下的 JSON工作流 summary 步骤负责在运行页渲染它们。conftest.py中的_reset_opik_context_after_test自动 fixture 在测试结束后调用context_storage.clear_all()start_as_current_trace/start_as_current_span上下文管理器在进入时会获得context_storage的 project 名所有权但不释放若下一个测试用新的 project 跑opik.tracktrace 会静默落入泄漏的旧 project——该 fixture 正是为了中和这一跨测试污染见 conftest.py。用 --load-scale 缩放压测规模每个场景都接受一个规模乘数用于快速冒烟或加码长跑# 快速冒烟默认规模的约 10% pytest suite/python_sdk --load-scale 0.1 # 重负载5 倍默认规模 OPIK_LOAD_SCALE5 pytest suite/python_sdk该参数由 conftest.py 通过pytest_addoption注册默认值取环境变量OPIK_LOAD_SCALE缺省为 1.0随后以load_scalefixture 注入各测试。缩放是按场景类型各异的条数类场景直接对 trace/span 计数取整乘如 10 万 × 0.1 1 万test_spread_over_time则同时缩放时间窗口window_seconds max(1, int(600 * load_scale))保证均匀速率不随规模改变。CI 定时压测工作流每周自动跑 手动触发套件由 GitHub Actions 工作流 .github/workflows/load_tests.yml 驱动触发方式每周日 04:00 UTC 定时运行cron: 0 4 * * 0也可通过workflow_dispatch手动触发运行环境使用更大的 GitHub 托管 runnerubuntu-latest-m约 4 vCPU / 16 GB而非默认的 ubuntu-latest2 vCPU / 7 GB——最重的摄取场景在 7 GB 上偶发 OOM 杀掉 xdist worker额外内存余量正是为此执行流程checkout → Python 3.12 uv →./opik.sh --backend --port-mapping --build拉起全新 docker 化的 Opik 后端 → 安装 SDKuv pip install --system .与套件依赖 →pytest suite/python_sdk -n 2 --distworksteal --junitxml...结果沉淀一个内嵌 Python 脚本把.last_run/*.json渲染成包含 Test / Volume / Submit / Submit rate / Flush / Verify / Total / Delivered 各列的 Markdown 表格写入 job summary并附原始 JSON 供深挖.last_run/同时作为构建产物上传JUnit 报告经publish-unit-test-result-action发布为 “Load Test Results” 检查需checks: write权限失败排查失败时导出opik-backend-1容器日志为 artifact无论成败最终都会./opik.sh --stop清理环境。工作流内还预设了OPIK_ENABLE_LITELLM_MODELS_MONITORING、OPIK_SENTRY_ENABLE、OPIK_ANALYTICS_ENABLE为 False压测时关闭非必需的后台功能。独立 CLI 脚本即席性能探测tests/下的脚本保留用于 ad-hoc 实验不会被 pytest 收集依赖固定于 tests_load/requirements.txtopik、click、anthropic、datasets、pillow。现有五个脚本test_trace_span_ingestion.py — 记录 N 条 trace 并测量端到端延迟。它以 click 命令形式运行--num-traces控制规模默认 1000内部构造opik.track嵌套调用输出三段耗时日志写入耗时、trace 在 UI 可见的等待耗时、总耗时。这是最快了解“写多快、查多快”的入口。test_trace_span_retrieval.py — 在指定 project 内按日期范围检索 trace/span用于探测检索路径的吞吐。test_thread_ingestion.py — 记录带多条 trace 与 span 的 thread线程/会话数据。test_image_inference.py — 面向在线评测online-evaluation的图像生成推理探测。test_images_dataset_sample.py — 加载图像样本数据集供 playground / experiment 测试使用。此外 tests_load/tests/traces-local-v2-cutover/ 下还包含一套面向“本地 trace v2 切换”演练的独立脚本含seed_history.py、live_traffic.py、delete_traffic.py及各自的 README用于在迁移窗口前后灌入历史数据、打实时流量并清理属于专门的迁移验证工具。边界与注意事项环境无关性套件读取 shell 中设置的OPIK_*变量配置由调用方负责切换目标本地栈 / 仅后端 / Comet 云端只需改环境变量无需改动测试代码。单副本局限test_dataset_insert_many_versions针对的是多副本 ClickHouse 的COPY_VERSION_ITEMS短读截断在单副本 localhost 上不会复现——在那里它退化为“顺序版本链 完整回读”的常规回归覆盖。已知缺陷绕行verify_traces的字段排除列表是针对 OPIK-6651 的临时绕行verify_exact_trace_ids的存在则源于对 OPIK-6444 一类丢消息回归的守门需求。阅读源码时留意这些注释能帮助你理解每个断言为什么长成现在这样。延伸阅读套件入口与公共配置suite/python_sdk/、pytest.ini公共校验与数据生成工具suite/python_sdk/_helpers.py定时压测工作流.github/workflows/load_tests.yml本地部署入口opik.sh 与 deployment/docker-compose/被测 SDK 源码sdks/python【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表