Skip to content

[kafka] Integrate Produce with native Fluss append - #4286

Open
gyang94 wants to merge 31 commits into
apache:mainfrom
gyang94:codex/kafka-produce-append
Open

gyang94 wants to merge 31 commits into
apache:mainfrom
gyang94:codex/kafka-produce-append

Conversation

@gyang94

@gyang94 gyang94 commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Closes #4283. Part of #4185.

Connect Kafka Produce v3-v11 to the TabletServer append gateway for pre-created raw/string tables addressed as database.table. Preserve partition-level error isolation, native acknowledgements and offsets, and immediate delayed-fetch wakeups after append.

Reuse parsed table metadata and compiled write plans, and move Produce metadata lookup, conversion and native submission onto dedicated bounded workers. A slow ZooKeeper lookup no longer occupies the shared RPC request processor for this Produce path.

This is PR07, depending on #4285 (PR06) and independent core PR #3412.

Brief change log

  • Apply the shared qualified-topic and table schema contract, retaining the resolved TablePath through lookup and conversion. Invalid topics, missing tables, invalid buckets and conversion failures remain isolated from valid writes.
  • Cache up to 1000 parsed TableInfo snapshots and 1000 immutable write plans. Every topic write still refreshes native metadata and authorization; changes to the response, including table identity, schema, properties or bucket-count epoch, invalidate reuse.
  • Execute Produce lookup, conversion and synchronous native append through bounded FIFO lanes keyed by the originating RPC worker, preserving same-connection submission order. Workers do not wait for asynchronous acknowledgements. Queue rejection returns REQUEST_TIMED_OUT without running rejected work on the RPC caller.
  • Use a separate worker pool sized from netty.server.num-worker-threads and netty.server.max-queued-requests, with queue capacity capped at 1024. Defaults are 8 workers and 500 total queued requests.
  • Drain deferred actions immediately after synchronous produceLog invocation, including throws, so acks=all can make replication progress.
  • Add the minimal NetworkProtocolPlugin.closeAsync and NettyServer lifecycle support needed to close plugin workers after transport and RPC processors stop, complete queued requests, and handle repeated or pre-start shutdown.

Incremental scope relative to the combined prerequisite baseline: 19 files changed, 2716 insertions(+), 30 deletions(-). This stage changes fluss-kafka plus the protocol lifecycle implementation and tests in fluss-rpc.

Tests

Java 11 reactor verify passed for the source committed at 972c726bf6c774805b70f06686abeb4c62f17962:

  • 160 Kafka unit tests, 8 Kafka integration tests and 5 NettyServerTest cases; no failures, errors or skipped tests.
  • Checkstyle, Spotless, RAT and git diff --check passed. Committed source files were verified byte-for-byte against the validated working tree.
  • Three-TabletServer tests cover native DDL, Kafka discovery, gzip Produce, raw/string, acks=0/1/all, offsets, timestamps/headers and native Fluss readback, including same-named tables in different databases.
  • A pipelined producer sends 30 batches of alternating sizes and verifies both offsets and native readback order.
  • Unit tests cover concurrent cache reuse, property/epoch changes, authorization revocation, bounded queue rejection, shutdown interruption and cancellation, pending acknowledgements, and immediate deferred-action draining.

The full repository suite, Flink SQL runtime, throughput benchmarks and memory-pressure tests were not run.

API and Format

Activates non-idempotent Produce v3-v11 over the existing Fluss append RPC and Arrow format. Kafka CreateTopics/DeleteTopics, automatic table creation, JSON, authentication, idempotence and transactions remain outside this stage.

ZooKeeper query-count reduction and byte-based admission control are deferred follow-ups. The caches avoid repeated parsing and plan construction; they do not avoid the fresh lookup. The conversion queue is bounded by request count, not retained payload bytes.

Stack and review

Draft while prerequisites are unmerged. The PR targets Apache main, so the full Files changed view includes prerequisites. Use this incremental comparison to review PR07 alone.

The comparison base 2a1622da4e18a6659a4b8eb22dba01c927ff279a combines PR06 at 04a9093b331cfb1835493627ef0ab0adb969b8c2 with the existing core PR #3412 at 969f985abbad907e99588a1d0f3252196e2fdee8. The delayed-fetch changes remain owned and reviewed in #3412. PR07 additionally includes the small RPC protocol shutdown hook required for its executor. After prerequisites merge, update the baseline and validate again.

Generative AI disclosure: Codex assisted with extraction, implementation, tests and commit organization. Human review is required before merge.

gyang94 and others added 24 commits October 19, 2026 10:22
Integrate the DDL mapping prerequisite and use its resolver for Metadata discovery. Omit unsupported tables from all-topic queries and return per-topic mapping errors for named queries. Preserve metadata for compatible tables in mixed requests.

Validation: Java 11, mvn -o -pl fluss-kafka clean verify (62 unit tests and 2 integration tests); Checkstyle, Spotless and RAT passed.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 742/742
AI-Contributed/UT: 571/571
Route Metadata queries through the database.table mapping from PR03 and
enumerate compatible topics across databases. Preserve brokers and valid
topics when a requested database is absent or disappears during discovery;
propagate other gateway failures.

Cover qualified names, same-named tables across databases, synchronous and
asynchronous lookup failures, and Metadata v0-v11 over a real listener.

Validated on Java 11: 90 unit tests and 4 integration tests passed, along
with Checkstyle, Spotless, RAT, and git diff --check. Five additional
interleaved asynchronous review probes passed.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 129/129
AI-Contributed/UT: 514/514
Keep the ApiVersions wire fallback assertion limited to its retry range,
while successful negotiation verifies both registered API ranges.

Cover Metadata v0-v11 handling of native gateway visibility filtering in
named queries, all-topic discovery, and missing-database retries. Verify
Metadata v12 is rejected before invoking the gateway.

Retain the existing qualified-topic discovery contract on prerequisite
c508de6. New Core-dependent aliases and
persisted table enablement remain deferred.

Validation: Java 11 reactor verify passed 105 unit tests and 5 integration
tests, with Spotless, Checkstyle, RAT, and git diff --check.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 0/0
AI-Contributed/UT: 71/71
Wait for all server gateways to advertise the restarted coordinator before
acquire, release and drop lease checks. Assert that the client still holds
its cached address so each operation exercises metadata refresh and retry.

Rebased PR04 onto PR03 at 86d2735.
Validation: restart case passed in the full Admin suite and focused rerun;
Kafka 110 tests, RPC retry 6 tests, Spotless and Checkstyle passed. The full
Admin suite passed 46/47; the unchanged rolling-upgrade health test first
observed RED instead of GREEN and passed the subsequent focused rerun.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 0/0
AI-Contributed/UT: 11/11
Use the actual server default database and the PR03 shared mapper/schema
contract. Resolve aliases by TablePath, preserve requested names, and retain
valid aliases when a missing database triggers metadata discovery retry.

Expose only tables with persisted table.kafka.enabled. Return unknown-topic
for disabled or missing tables and invalid-topic for damaged enabled
contracts in named and all-topic requests. Discovery emits canonical names
without duplicate aliases and retains native authorization and routing.

Verify configuration injection, no fallback lookup or database creation,
enablement/reset changes, invalid historical contracts and v0-v11 behavior
through real Kafka listeners. Preserve the coordinator snapshot lease fix.

Validation: Java 11 clean reactor verify passed 160 distinct cases: 118 Kafka
(including 6 Metadata integration cases), 31 shared schema, 3 atomic DDL,
6 RPC retry and 2 snapshot lease cases. Spotless, Checkstyle and RAT passed.
The four existing PR04 commits were rebased unchanged onto PR03
4a9aa6b and checked with range-diff.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 155/155
AI-Contributed/UT: 571/571
Keep canonical topic IDs unchanged and encode alias wire IDs in a separate
namespace using the same Fluss table ID. Kafka clients can then cache both
names and detect table recreation even when the new leader epoch is lower.

Cover Kafka Metadata v10/v11 full and partial updates, recreation from epoch
5 to 0 without a missing-topic response, and native Metadata responses.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 31/31
AI-Contributed/UT: 135/135
Adapt the decoder regression to the configured request handler. Cover
optional three-field metadata columns and legacy offset rejection across
Metadata v0-v11, including native DDL and both real TabletServer listeners.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 0/0
AI-Contributed/UT: 109/109
Pass one RPC service through the request handler and validate its
TabletServerGateway capability inside the Metadata backend.

Consolidate overlapping Metadata tests while retaining protocol-version,
alias identity, client cache, authorization and discovery regressions.
Align the custom default database test with PR03 startup creation and
verify that Metadata does not recreate a deleted default database.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 35/35
AI-Contributed/UT: 546/546
Use KafkaValueConversionType for typed table properties after rebasing
onto main. Preserve the raw invalid value in the disabled-table regression
to keep verifying that Metadata filters it before schema resolution.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 0/0
AI-Contributed/UT: 21/21
Clarify the namespace name and comment for default-database aliases.
Keep the UUID namespace value and mapping behavior unchanged.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 8/8
AI-Contributed/UT: 0/0
Validate non-idempotent Produce v3-v11 and isolate invalid partitions before invoking a protocol-independent backend. Preserve partition order, acknowledgements and owned record data. Leave production registration to the append integration PR.

Validation: Java 11, mvn -o -pl fluss-kafka spotless:apply clean verify; 69 unit tests and 2 integration tests passed, including Checkstyle, Spotless and RAT.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 621/621
AI-Contributed/UT: 366/366
Read compressed records through a closeable streaming iterator to avoid
preallocating a record list from the declared batch count. Reject incoming
Kafka batches whose offset range disagrees with their record count before
copying records or invoking the backend. Keep Fluss-assigned offsets independent
of this input validation and preserve partition error isolation.

Cover all five codecs, owned record copies, malformed counts and offset ranges,
and backend-assigned offsets. Java 11 validation passed: 117 unit tests and
4 integration tests, plus Checkstyle, Spotless, RAT, and git diff --check.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 42/42
AI-Contributed/UT: 168/168
Carry timestamp provenance through a protocol-independent enum on each copied
record. Read the type from its batch for compressed and uncompressed records;
keep timestamp presence separate. Retain the existing constructor with an
explicit UNKNOWN type instead of guessing provenance from the numeric value.

Cover mixed batch types across partitions, absent timestamps, owned data and
legacy constructors. Keep partition validation and acks=0 behavior, and check
that ApiVersions advertises the registered Produce range. Metadata row storage
and production append registration remain outside this protocol-only change.

Validated with Java 11 and this worktree's clean reactor: 152 unit tests and
5 integration tests passed, including ApiVersions and Metadata regressions.
Spotless, Checkstyle, RAT and git diff --check passed.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 64/64
AI-Contributed/UT: 326/326
Document that the protocol backend receives original topic names and returns
results keyed by those names, leaving database resolution to the adapter.
Cover bare and qualified names together across Produce v3-v11, reordered
backend results, local validation failures, backend errors and invalid acks.
Keep null and empty record values distinct in the owned protocol command.

Validated on Java 11 with this worktree's clean reactor: 162 Kafka unit tests,
23 integration tests, and 34 Common/Server schema and DDL tests passed.
Spotless, Checkstyle, RAT and git diff --check passed.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 11/11
AI-Contributed/UT: 150/150
Reuse the DDL contract to assemble key, value, timestamp and ordered headers into physical rows. Decode strings with strict UTF-8 validation and preserve nullable values. Return owned heap log bytes and recycle Arrow writers on success and failure.

Validation: Java 11, mvn -o -pl fluss-kafka spotless:apply clean verify; 75 unit tests and 2 integration tests passed, including Checkstyle, Spotless and RAT.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 314/314
AI-Contributed/UT: 326/326
Decode and append one record at a time instead of retaining an entire row
list. Borrow command-owned key, value and header bytes during synchronous
conversion while preserving defensive-copy accessors.

Cover row and payload reuse, batches beyond initial Arrow capacity, and
resource cleanup after partial conversion failures.

Validation on Java 11: reactor clean verify passed with 130 unit tests and
4 integration tests, plus Checkstyle, Spotless, RAT and git diff --check.
An additional 25 boundary scenarios passed.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 101/101
AI-Contributed/UT: 224/224
Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 13/13
AI-Contributed/UT: 75/75
Use the shared KafkaTableSchema contract for the fixed value column, raw
optional keys, and last-value-wins header maps. Validate final map and key
nullability, keep optional rescue values null, and remove prototype field
projections and timestamp-column mapping. Reject metadata until native
per-row offsets are available; JSON decoding remains a later stage.

Preserve synchronous streaming, borrowed payloads, owned Arrow output and
failure-path cleanup. Cover all optional system-column combinations, raw
bytes, strict UTF-8, header deduplication, multi-page output and partial
conversion failures without changing null-value filtering.

Validation: Java 11 current-worktree clean reactor, 277 unit tests and 27
integration tests passed, including cumulative Kafka, shared schema, DDL
and Arrow coverage. The final 23 transcoder cases passed again after
strengthening the multi-page test. Spotless, Checkstyle, RAT and diff checks
passed. All SNAPSHOT test dependencies came from this worktree.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 95/95
AI-Contributed/UT: 741/741
The shared schema now accepts three-field Kafka metadata without offsets.
Reject it explicitly during row assembler construction so binary/string
conversion cannot silently emit null metadata. Keep the existing streaming
and borrowed-payload paths unchanged.

Cover nullable and non-null metadata in both formats, and update the legacy
offset-field regression to the current schema validation message.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 5/5
AI-Contributed/UT: 41/41
Populate TIMESTAMP_LTZ(3), Kafka batch timestamp type and the requested
partition before Arrow encoding. Preserve timestamp provenance independently
of timestamp presence, and enforce nested timestamp NOT NULL constraints.

Keep synchronous streaming and borrowed key/value/header payloads. Cover all
16 optional-column combinations, timestamp boundaries, partition isolation,
Arrow vector growth and failure atomicity for binary and string values.

Validation: Java 11 offline clean verify; 348 tests passed (317 unit and
31 integration), with Spotless, Checkstyle and RAT checks passing.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 74/74
AI-Contributed/UT: 233/233
Use the typed conversion API from the current metadata contract and align
transcoder tests with schema-time nullability validation.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6.1-sol
AI-Contributed/Feature: 16/16
AI-Contributed/UT: 237/237
Register Produce v3-v11 and adapt the local TabletServer gateway using
the shared qualified-topic DDL contract and raw/string transcoder.
Preserve the resolved TablePath across metadata lookup and conversion,
isolate table/partition failures, and map invalid topic names correctly.
Drain deferred actions immediately after the synchronous append invocation
so acks=all does not wait for its own delayed replica fetches.

Base on PR06 04a9093 and independent core PR apache#3412 at 969f985.

Validation: Java 11 reactor verify; 139 Kafka unit tests, 7 Kafka integration
tests, and 10 targeted RPC/server tests passed. Three-replica tests cover
raw/string, gzip, acks=0/1/all, offsets, timestamp/headers, native readback,
and independent writes to same-named tables in different databases.
Checkstyle, Spotless, RAT, and git diff --check passed.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 319/319
AI-Contributed/UT: 606/606
Reuse parsed table metadata and immutable raw/string write plans while
refreshing native metadata and authorization for every topic write.
Offload metadata lookup, conversion and native submission to bounded FIFO
workers, preserving connection order without waiting for acknowledgements.
Close protocol-owned workers after transport and RPC processors stop.

Validation: Java 11 reactor verify passed 160 Kafka unit tests, 8 Kafka
integration tests and 5 NettyServer tests. Checkstyle, Spotless, RAT and
git diff --check passed. Tests cover cache invalidation, authorization
refresh, saturation, shutdown, pending acknowledgements and pipelined
three-replica append order. Source content is unchanged since validation.

ZooKeeper query reduction and byte-based admission remain follow-up work.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 812/812
AI-Contributed/UT: 1047/1047
Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 50/50
AI-Contributed/UT: 99/99
gyang94 and others added 6 commits October 19, 2026 12:02
Cover WRITE revocation after metadata reuse, offloaded metadata identity
and schema refresh, and shutdown with an already submitted native append.
Preserve Record timestamp provenance and the existing null-value filtering
behavior, including native offsets and real Kafka producer readback.
The FIP null-value contract and new Core dependencies remain deferred.

Validated on PR06 b6f31fc84baf91c030b296701eb319644578056c with Java 11:
206 Kafka unit tests, 10 Kafka integration tests, 8 RPC regression tests
and 7 delayed-fetch regression tests passed. Checkstyle, Spotless, RAT
and git diff --check passed. This commit changes tests only.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 0/0
AI-Contributed/UT: 191/191
Inject the configured topic mapper into Produce, check authoritative table
enablement before plan preparation, and use the shared fixed-column schema.
Reject conversion failures as INVALID_RECORD and missing databases as
UNKNOWN_TOPIC_OR_PARTITION without alias fallback.

Cover shared alias plans and offsets, disable/reset and property/schema
changes, null filtering, raw keys, last-wins headers and null rescue values.
Preserve bounded conversion, authorization and atomic partition conversion.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 34/34
AI-Contributed/UT: 656/656
Wait for table replica metadata and leader readiness before round-trip
writes. Node discovery alone does not ensure a fresh table can accept
acks=0 records, whose failures cannot be observed or retried by the producer.
Include the table path in readback failures to identify format/acks cases.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 0/0
AI-Contributed/UT: 7/7
Remove the Kafka drain-hook dependency after separating the core delayed
fetch optimization into apache#3412. Continue to use native append
responses for acknowledgements, including pending acks=all completions.

Retain append, authorization, error mapping, ordering and shutdown coverage;
move the test append signal to native submission instead of the drain hook.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 9/9
AI-Contributed/UT: 33/33
Append null-valued records through the native Produce path, preserving record
order and offsets. Remove the separate authorization shortcut for filtered
records. Cover nullable and NOT NULL values with unit and native readback tests.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6
AI-Contributed/Feature: 54/54
AI-Contributed/UT: 243/271
Update cached Produce write plans and tests to use the current typed schema conversion options and validate persisted table contracts before appending.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6.1-sol
AI-Contributed/Feature: 13/13
AI-Contributed/UT: 81/81
@gyang94
gyang94 force-pushed the codex/kafka-produce-append branch from af1ec7e to fdaba29 Compare October 19, 2026 04:54
Keep Netty event loops active until accepted requests and channels have drained, then close protocol workers. Update the integration test to assert the current nullable Kafka schema contract at table creation.

Co-Authored-By: Codex <noreply@openai.com>
AI-Model: gpt-6.1-sol
AI-Contributed/Feature: 26/26
AI-Contributed/UT: 29/29
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.

[kafka] Integrate Produce with native Fluss append

1 participant