Skip to content

Skip DSM tag/context building in Kafka consumers when Data Streams is off (dsm - perf quick fix) - #13075

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 3 commits into
masterfrom
dougqh/kafka-dsm-guard
Oct 27, 2026
Merged

gh-worker-dd-mergequeue-cf854d[bot] merged 3 commits into
masterfrom
dougqh/kafka-dsm-guard

Conversation

@dougqh

@dougqh dougqh commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What Does This Do

Skips building Data Streams Monitoring (DSM) tags and context in the Kafka consumer TracingIterators (kafka-clients-0.11 and kafka-clients-3.8) when DSM is disabled.

Before this change, startNewRecordSpan called DataStreamsTags.create(...) (hashed tags, strings) and built a DataStreamsContext for every consumed record, whether DSM was on or not. Only the payload-size computation checked isDataStreamsEnabled(). With DSM off, the receivers are already no-ops:

  • new spans get NoopPathwayContext, so setCheckpoint records nothing and sets no pathway-hash tag
  • DataStreamsPropagator.inject already returns early when DSM is disabled

The whole DSM block now sits behind traceConfig().isDataStreamsEnabled(). That's the same dynamic check the payload-size line already used, so turning DSM on through remote config still works.

Motivation

kafka-consumer-perf-test (10M records carrying real trace headers, 256m heap, JDK 17, 5 fresh-JVM reps, rotated), DSM off:

  • this DSM construction was about 12% of consumer-thread allocation (JFR)
  • guarding it: +6.6% throughput (median 325k → 352k records/s, runs don't overlap)

Kafka consumers amplify per-message tracer cost more than any other workload we've measured. The consumer's own work is about 0.7 µs per record, so small per-record savings show up directly.

The macro numbers above were measured on the combined dense-store + trace-segment build. This PR adds KafkaConsumeScenariosBenchmark (JMH, no agent or broker needed), which measures the guard alone against master: a 500-record poll batch drained through TracingIterator, every record carrying this tracer's propagation headers. JDK 17, 3 forks × 5 iterations, M1 Max:

dataStreams build ns/record B/record
false master 1923 ± 107 3989 ± 30
false this PR 1764 ± 82 3442 ± 12
true master 2130 ± 27 4654 ± 11
true this PR 2099 ± 35 4660 ± 6
  • DSM off: −548 B per record (−13.7%). That matches the ~12% of consumer-thread allocation JFR attributed to this code in the macro run. Time per record is −8% but the error bars touch; allocation is the reliable signal here.
  • DSM on: no change, within noise, as expected.
  • The relative gain in a real consumer is smaller: these records are pre-built, so Kafka's fetch and header parsing aren't in the measurement.

To reproduce, cherry-pick the benchmark commit onto the base commit and run on both:

./gradlew :dd-java-agent:instrumentation:kafka:kafka-clients-0.11:jmh \
    -Pjmh.includes=KafkaConsumeScenariosBenchmark -Pjmh.profilers=gc -PtestJvm=17

Additional Notes

The same pattern appears elsewhere: DSM arguments built eagerly for a call that does nothing when DSM is off. Follow-ups:

  • APMLP-2116: audit of other messaging/RPC integrations (SQS, SNS, RabbitMQ, the Kafka producer, gRPC)
  • APMLP-2117: gated contributions (setTagsFromIf(Product, ...)), so a disabled product costs one branch by construction instead of relying on a guard at each call site
  • APMLP-2124: a /perf-review rule to flag arguments built for a disabled or no-op call

DSM and IDM reviewers: mostly an FYI on the pattern, since it affects how this code is likely to evolve.

Jira ticket: APMLP-2115

🤖 Generated with Claude Code

… off

The consumer TracingIterators built DataStreamsTags and a
DataStreamsContext for every record even with DSM disabled, where the
checkpoint and DSM injection are no-ops. Guard the whole DSM block with
the same dynamic isDataStreamsEnabled() check the payload-size line
already used, so remote-config enablement still takes effect.

kafka-consumer-perf-test with DSM off: ~12% less consumer-thread
allocation, +6.6% throughput.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh dougqh added type: bug fix Bug fix inst: kafka Kafka instrumentation comp: data streams Data Streams Monitoring tag: ai generated Largely based on code generated by an AI or LLM labels Oct 27, 2026
@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🎯 Code Coverage (details)
• Patch Coverage: 100.00%
• Overall Coverage: 59.44% (-0.01%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 5ede6d4 | Docs | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 13.98 s 14.02 s [-0.9%; +0.5%] (no difference)
startup:insecure-bank:tracing:Agent 12.93 s 13.04 s [-1.5%; -0.2%] (maybe better)
startup:petclinic:appsec:Agent 17.80 s 17.58 s [+0.4%; +2.0%] (maybe worse)
startup:petclinic:iast:Agent 17.60 s 17.71 s [-1.4%; +0.2%] (no difference)
startup:petclinic:profiling:Agent 17.55 s 17.41 s [-0.1%; +1.7%] (no difference)
startup:petclinic:sca:Agent 17.84 s 17.72 s [-0.6%; +1.9%] (no difference)
startup:petclinic:tracing:Agent 16.68 s 16.88 s [-2.2%; -0.2%] (maybe better)

Commit: 5ede6d49 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@pr-commenter

pr-commenter Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Kafka / producer-benchmark

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master dougqh/kafka-dsm-guard
git_commit_date 1793103791 1793133436
git_commit_sha 732a7fe 5ede6d4
See matching parameters
Baseline Candidate
ci_job_date 1793134715 1793134715
ci_job_id 2183077501 2183077501
ci_pipeline_id 148005932 148005932
cpu_model Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
jdkVersion 11.0.31 11.0.31
jmhVersion 1.36 1.36
jvm /usr/lib/jvm/java-11-openjdk-amd64/bin/java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
jvmArgs -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=15002 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=15002 -Dhttp.nonProxyHosts=localhost *.localhost
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-0-u7rokfkl 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-0-u7rokfkl 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
vmName OpenJDK 64-Bit Server VM OpenJDK 64-Bit Server VM
vmVersion 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 3 metrics, 0 unstable metrics.

See unchanged results
scenario Δ mean throughput
scenario:not-instrumented/KafkaProduceBenchmark.benchProduce same
scenario:only-tracing-dsm-disabled-benchmarks/KafkaProduceBenchmark.benchProduce same
scenario:only-tracing-dsm-enabled-benchmarks/KafkaProduceBenchmark.benchProduce same

@pr-commenter

pr-commenter Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Kafka / consumer-benchmark

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master dougqh/kafka-dsm-guard
git_commit_date 1793103791 1793133436
git_commit_sha 732a7fe 5ede6d4
See matching parameters
Baseline Candidate
ci_job_date 1793134779 1793134779
ci_job_id 2183077502 2183077502
ci_pipeline_id 148005932 148005932
cpu_model Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz
jdkVersion 11.0.31 11.0.31
jmhVersion 1.36 1.36
jvm /usr/lib/jvm/java-11-openjdk-amd64/bin/java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
jvmArgs -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=15002 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=15002 -Dhttp.nonProxyHosts=localhost *.localhost
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-0-hio6d3z6 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-0-hio6d3z6 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
vmName OpenJDK 64-Bit Server VM OpenJDK 64-Bit Server VM
vmVersion 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu 11.0.31+11-post-1ubuntu1-22.04.2-Ubuntu

Summary

Found 0 performance improvements and 1 performance regressions! Performance is the same for 2 metrics, 0 unstable metrics.

scenario Δ mean throughput
scenario:only-tracing-dsm-disabled-benchmarks/KafkaConsumerBenchmark.benchConsume worse
[-14470.900op/s; -2908.653op/s] or [-5.644%; -1.135%]
See unchanged results
scenario Δ mean throughput
scenario:not-instrumented/KafkaConsumerBenchmark.benchConsume same
scenario:only-tracing-dsm-enabled-benchmarks/KafkaConsumerBenchmark.benchConsume same

@dougqh
dougqh marked this pull request as ready for review October 27, 2026 15:00
@dougqh
dougqh requested review from a team as code owners October 27, 2026 15:00
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T15:02:36.305305Z fcf4319 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bits Code Review: PASS

More details

Both Kafka consumer guards preserve DSM-enabled checkpoint and propagation behavior while skipping tag and context construction when DSM is disabled. The completed static review identified no actionable regressions.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit fcf4319

KafkaConsumeScenariosBenchmark drains a 500-record poll batch through
TracingIterator with a default-configured CoreTracer and no agent. Each
record carries the headers this tracer injects on produce, so every
record goes through extraction, a consume span and the DSM checkpoint
path. dataStreams toggles dd.data.streams.enabled per fork.

It measures what the Kafka macro benchmark can't isolate without a
broker: ns and bytes per record on the consumer thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh
dougqh requested a review from a team as a code owner October 27, 2026 15:52
@dougqh
dougqh requested review from PerfectSlayer and removed request for a team October 27, 2026 15:52

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bits Code Review: PASS

More details

Both Kafka consumer guards use the existing dynamic DSM setting, preserving enabled checkpoint and propagation behavior while avoiding tag and context construction when disabled. The completed static review found no actionable regression.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit b13e6e3

@ygree ygree left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDM approved

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh

dougqh commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-10-27 21:43:19 UTC ℹ️ Start processing command /merge


2026-10-27 21:43:23 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in master is approximately 2h (p90).


2026-10-27 22:44:29 UTC ℹ️ MergeQueue: This merge request was merged

@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit 50f347f into master Oct 27, 2026
621 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the dougqh/kafka-dsm-guard branch October 27, 2026 22:44
@github-actions github-actions Bot added this to the 1.69.0 milestone Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: data streams Data Streams Monitoring inst: kafka Kafka instrumentation tag: ai generated Largely based on code generated by an AI or LLM type: bug fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants