Visitar URL original
PYTHON-6065 Benchmark OpenTelemetry support by blink1073 · Pull Request #3102 · mongodb/mongo-python-driver · GitHub
Skip to content

PYTHON-6065 Benchmark OpenTelemetry support - #3102

Draft
blink1073 wants to merge 6 commits into
mongodb:mainfrom
blink1073:PYTHON-6065
Draft

blink1073 wants to merge 6 commits into
mongodb:mainfrom
blink1073:PYTHON-6065

Conversation

@blink1073

@blink1073 blink1073 commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

PYTHON-6065

Changes in this PR

  • Adds tools/otel_bench.py, a benchmark harness covering the tracing config variants for DRIVERS-3620, plus per-op CPU-time recording in test/performance/ (PERF_CPU_TIME=1).
  • Hot-path optimizations: defer expensive span attributes until after the sampling decision, cache connection-static attributes, resolve the tracing option once at client construction, skip the duration timedelta when logging/APM are off.
  • Overhead is a fixed per-op cost (~50-55 µs/op at 1% sampling, ~130 µs/op always-on); span creation drops 18.0 → 3.0 µs/op; disabled tracing is at parity (≤2%) with the pre-OTel baseline. No public APIs changed.
  • The first two commits are from PYTHON-5945 Add OpenTelemetry Simple Command Support #3071. The second two add the optimizations and the bench harness.

Results

16-core x86_64, MongoDB 8.0.4 localhost, CPython 3.9, 5 interleaved repetitions with rotated config order, medians; no exporter or span processor installed.

Throughput (median MB/s, overhead vs untraced baseline in parens):

config sync insertOne sync findOne async insertOne async findOne
off (baseline) 1.07 5.21 0.61 3.19
api-only 0.96 (+10.2%) 4.79 (+8.0%) 0.57 (+6.1%) 3.04 (+4.5%)
sdk-ratio (1%) 0.87 (+19.1%) 4.36 (+16.3%) 0.54 (+11.3%) 2.88 (+9.6%)
sdk-always 0.69 (+36.0%) 3.56 (+31.6%) 0.46 (+24.4%) 2.50 (+21.7%)

CPU time per operation (µs/op median, delta vs baseline in parens):

config sync insertOne sync findOne async insertOne async findOne
off (baseline) 161 222 396 462
api-only 187 (+25) 246 (+24) 422 (+26) 484 (+22)
sdk-ratio (1%) 214 (+53) 278 (+56) 447 (+51) 511 (+50)
sdk-always 291 (+130) 355 (+133) 526 (+131) 592 (+130)

Tracing disabled vs pre-tracing commit (d5934e6):

task sync async
SmallDocInsertOne +1.8% -0.8%
FindOneByID +0.8% +0.6%

Overhead barely depends on sampling rate: a span must be started to learn it won't record, so attribute collection and sampler machinery run on every command. Micro-benchmarks on ~160-460 µs ops magnify the fixed cost; real workloads amortize it.

Test Plan

  • New tests in test/asynchronous/test_otel.py (sync suite mirrored) cover the deferred attributes, the connection cache, and a hot-path regression test.
  • python tools/otel_bench.py --verify checks span wiring end-to-end; full run via python tools/otel_bench.py --reps 5.

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

…butes

Fix tracing.enabled so an explicit client value overrides the
OTEL_PYTHON_INSTRUMENTATION_MONGODB_ENABLED environment variable,
fix db.query.text truncation so budgets smaller than the "..."
marker still honor the bound, and fix collection-name extraction so
user and role management commands do not expose usernames as
db.collection.name.
Benchmark tracing overhead per the OpenTelemetry spec's performance
requirements with tools/otel_bench.py, and optimize the
per-command hot path based on the results:

- Defer expensive span attributes (db.query.summary, db.mongodb.lsid,
  db.mongodb.txn_number, db.query.text) until after the sampler's
  decision, so unsampled and no-op spans skip building them entirely.
  db.query.text is the big win: it serialized the command to extended
  JSON on every single command.
- Cache connection-static span attributes on the connection (keyed by
  server connection id) instead of rebuilding them per command.
- Resolve the client's tracing option against the environment once, at
  MongoClient construction, so no command consults the environment.
- Skip building the duration timedelta when neither command logging nor
  APM events are enabled; a tracing-only client doesn't need it.

Add PERF_CPU_TIME to the DriverBench performance tests to record
per-operation CPU time, which otel_bench.py uses to report the fixed
CPU cost of each tracing configuration (tracing off, api-only, SDK with
TraceIdRatioBased sampling, SDK always-on).
@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.52381% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pymongo/_otel.py 86.39% 10 Missing and 10 partials ⚠️
pymongo/common.py 87.50% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant