Skip to content

Capture Kafka consumer group membership on join#11989

Open
piochelepiotr wants to merge 1 commit into
masterfrom
piotr.wolski/dsm-consumer-group-membership
Open

Capture Kafka consumer group membership on join#11989
piochelepiotr wants to merge 1 commit into
masterfrom
piotr.wolski/dsm-consumer-group-membership

Conversation

@piochelepiotr

Copy link
Copy Markdown
Contributor

What

Instruments ConsumerCoordinator.onJoinComplete (kafka-clients 0.11 + 3.8) so that every time a consumer (re)joins a group the tracer reports its broker-assigned member id, generation id, and negotiated member protocol through Data Streams Monitoring, alongside the consumer group and Kafka cluster id.

  • New AgentDataStreamsMonitoring.reportKafkaConsumerGroupMember(...); carried on the DSM payload as first-class fields (MemberId, GenerationId, MemberProtocol) on the existing kafka config report — no new payload section.
  • Change-detection on (memberId, generationId) avoids re-reporting unchanged membership.
  • member_host is intentionally omitted: it is assigned broker-side and never sent to the joining client.

Part of a cross-repo change

This is the producer side. Downstream: dd-go data-pipeline-edge → dsm-kafka-configs stream → dsm-kafka-configs-writer → orgstore consumer_group_members table → dsm-api.

Tests

  • DataStreamsWritingTest + DefaultDataStreamsMonitoringTest (new member/generation/protocol wire-format assertions) — green.
  • Muzzle passes for both kafka modules across all supported versions.
  • kafka-clients-0.11 embedded suite (real consumer joins exercise the advice) — 13/13 green.

🤖 Generated with Claude Code

Instrument ConsumerCoordinator.onJoinComplete (kafka-clients 0.11 and 3.8)
to report the broker-assigned member id, generation id and negotiated
member protocol each time a consumer (re)joins a group. Reported through
Data Streams Monitoring alongside the consumer group and cluster id via a
new reportKafkaConsumerGroupMember path (member_host is not available
client-side and is intentionally omitted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@piochelepiotr piochelepiotr added tag: ai generated Largely based on code generated by an AI or LLM inst: kafka Kafka instrumentation comp: data streams Data Streams Monitoring type: feature Enhancements and improvements labels Jul 17, 2026
@datadog-datadog-prod-us1

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Jul 17, 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 13.92 s [-0.3%; +1.2%] (no difference)
startup:insecure-bank:tracing:Agent 12.94 s 12.98 s [-1.0%; +0.4%] (no difference)
startup:petclinic:appsec:Agent 16.94 s 16.12 s [+0.8%; +9.3%] (maybe worse)
startup:petclinic:iast:Agent 16.92 s 16.98 s [-1.3%; +0.6%] (no difference)
startup:petclinic:profiling:Agent 16.58 s 16.86 s [-2.8%; -0.5%] (maybe better)
startup:petclinic:sca:Agent 16.87 s 16.71 s [-0.1%; +1.9%] (no difference)
startup:petclinic:tracing:Agent 16.12 s 16.07 s [-0.4%; +1.1%] (no difference)

Commit: d299a2cb · 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 Jul 17, 2026

Copy link
Copy Markdown

Kafka / producer-benchmark

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master piotr.wolski/dsm-consumer-group-membership
git_commit_date 1784298512 1784318938
git_commit_sha e98ec49 d299a2c
See matching parameters
Baseline Candidate
ci_job_date 1784319969 1784319969
ci_job_id 1871072120 1871072120
ci_pipeline_id 125394688 125394688
cpu_model Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
jdkVersion 11.0.25 11.0.25
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 -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/go/src/github.com/DataDog/apm-reliability/dd-trace-java/platform/src/producer-benchmark/build/tmp/jmh -Duser.country=US -Duser.language=en -Duser.variant -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/go/src/github.com/DataDog/apm-reliability/dd-trace-java/platform/src/producer-benchmark/build/tmp/jmh -Duser.country=US -Duser.language=en -Duser.variant
vmName OpenJDK 64-Bit Server VM OpenJDK 64-Bit Server VM
vmVersion 11.0.25+9-post-Ubuntu-1ubuntu122.04 11.0.25+9-post-Ubuntu-1ubuntu122.04

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-enabled-benchmarks/KafkaProduceBenchmark.benchProduce worse
[-8703.595op/s; -1955.651op/s] or [-5.915%; -1.329%]
See unchanged results
scenario Δ mean throughput
scenario:not-instrumented/KafkaProduceBenchmark.benchProduce same
scenario:only-tracing-dsm-disabled-benchmarks/KafkaProduceBenchmark.benchProduce same

@pr-commenter

pr-commenter Bot commented Jul 17, 2026

Copy link
Copy Markdown

Kafka / consumer-benchmark

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master piotr.wolski/dsm-consumer-group-membership
git_commit_date 1784298512 1784318938
git_commit_sha e98ec49 d299a2c
See matching parameters
Baseline Candidate
ci_job_date 1784319999 1784319999
ci_job_id 1871072124 1871072124
ci_pipeline_id 125394688 125394688
cpu_model Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
jdkVersion 11.0.25 11.0.25
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 -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/go/src/github.com/DataDog/apm-reliability/dd-trace-java/platform/src/consumer-benchmark/build/tmp/jmh -Duser.country=US -Duser.language=en -Duser.variant -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/go/src/github.com/DataDog/apm-reliability/dd-trace-java/platform/src/consumer-benchmark/build/tmp/jmh -Duser.country=US -Duser.language=en -Duser.variant
vmName OpenJDK 64-Bit Server VM OpenJDK 64-Bit Server VM
vmVersion 11.0.25+9-post-Ubuntu-1ubuntu122.04 11.0.25+9-post-Ubuntu-1ubuntu122.04

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/KafkaConsumerBenchmark.benchConsume same
scenario:only-tracing-dsm-disabled-benchmarks/KafkaConsumerBenchmark.benchConsume same
scenario:only-tracing-dsm-enabled-benchmarks/KafkaConsumerBenchmark.benchConsume same

@piochelepiotr
piochelepiotr marked this pull request as ready for review July 17, 2026 21:15
@piochelepiotr
piochelepiotr requested review from a team as code owners July 17, 2026 21:16
@piochelepiotr
piochelepiotr requested review from ygree and removed request for a team July 17, 2026 21:16

@datadog-datadog-prod-us1 datadog-datadog-prod-us1 Bot 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.

Datadog Autotest: WARN

The PR instruments Kafka consumer group membership tracking but introduces a breaking msgpack format change: all kafka configs now serialize with 7 fields (adding MemberId, GenerationId, MemberProtocol) instead of 4. Downstream consumers that expect exactly 4 fields will fail to parse the new format, potentially breaking the entire DSM kafka pipeline. The PR claims cross-repo coordination, but without deployment verification, this is a critical downstream compatibility risk.

📊 Validated against 6 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit d299a2c · What is Autotest? · Any feedback? Reach out in #autotest

packer.writeUTF8(CONFIG_GENERATION_ID);
packer.writeLong(config.getGenerationId());

packer.writeUTF8(CONFIG_MEMBER_PROTOCOL);

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.

P1 Breaking msgpack format change for all kafka configs

DSM kafka configuration pipeline may fail to parse reports, leading to data loss and broken consumer group monitoring. This breaks production observability for Kafka consumers using Data Streams Monitoring.

Assertion details
  • Input: Any system downstream of DSM that consumes Kafka config reports (dsm-kafka-configs stream, dsm-kafka-configs-writer, etc.) and expects exactly 4 fields in the msgpack map.
  • Expected: Kafka config reports serialize with 4 fields: Type, KafkaClusterId, ConsumerGroup, Config. Downstream code that calls unpackMapHeader() expecting 4 and then reads exactly 4 fields should succeed.
  • Actual: Kafka config reports now serialize with 7 fields: Type, KafkaClusterId, ConsumerGroup, MemberId, GenerationId, MemberProtocol, Config. Any downstream unpacker expecting 4 fields will read 7 and either: (1) fail with assertion error, (2) read wrong data beyond the 4 expected fields, or (3) silently ignore the 3 new fields if using lenient parsing.

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · Any feedback? Reach out in #autotest

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d299a2cbf1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +59 to +61
transformer.applyAdvice(
isMethod().and(named("onJoinComplete")).and(takesArguments(4)),
packageName + ".JoinGroupAdvice");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Instrument async 3.8 consumers too

With Kafka 3.8+ consumers configured with group.protocol=consumer (the KIP-848 path), Kafka constructs the async ConsumerDelegate path rather than the legacy coordinator-backed consumer; this module already reflects that by storing KafkaConsumerInfo on ConsumerDelegate/OffsetCommitCallbackInvoker in ConstructorAdvice instead of on ConsumerCoordinator. Because the new member reporting is only attached to ConsumerCoordinator.onJoinComplete, those supported 3.8 consumers never execute this advice and no member/generation/protocol report is emitted for them. Please add equivalent reporting on the async membership path or explicitly restrict the feature to the legacy protocol.

Useful? React with 👍 / 👎.

&& generationId == kafkaConsumerInfo.getLastReportedGenerationId()) {
return;
}
kafkaConsumerInfo.setLastReportedMembership(memberId, generationId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Defer reporting until the cluster ID is known

If a consumer completes its first join before MetadataState.clusterId has been populated, this records the (memberId, generationId) as already reported and then sends a membership report with an empty cluster id. When the later metadata update fills in the cluster id, there is no rejoin and the guard above suppresses re-emitting the same membership, unlike the existing config path which stores pending reports until cluster id is available. This leaves downstream member rows permanently missing the Kafka cluster id for that startup ordering; consider keeping the membership pending or only updating lastReportedMembership after a report with a known cluster id.

Useful? React with 👍 / 👎.

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: feature Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant