Andrea Cosentino created CAMEL-24779:
----------------------------------------
Summary: camel-kafka - reduce per-message allocations on the
producer, consumer and transform hot paths
Key: CAMEL-24779
URL: https://issues.apache.org/jira/browse/CAMEL-24779
Project: Camel
Issue Type: Improvement
Components: camel-kafka
Reporter: Andrea Cosentino
This is a small, behaviour-preserving performance clean-up that bundles three
per-message hot-path allocation reductions in camel-kafka. No public API or
option changes.
h3. 1. Producer: redundant callback allocation on the single-message async path
{{KafkaProducer.process(Exchange, AsyncCallback)}} sends a single record via
{{doSend(exchange, record, producerCallBack)}}. Because the key (the exchange)
is non-null, {{doSend}} allocates a {{KafkaProducerMetadataCallBack}} *and* a
{{DelegatingCallback}} for every message. For the single-message case this is
redundant: the parent {{KafkaProducerCallBack}} already sets the exception and
the {{CamelKafkaRecordMeta}} header (a {{List<RecordMetadata>}}) on the same
exchange. Sending with the parent callback alone removes two short-lived
allocations per message and produces an identical {{CamelKafkaRecordMeta}}
result. The iterator/batch path is left unchanged (it genuinely needs a
per-element metadata callback).
h3. 2. Consumer: per-record Stream/lambda allocations in header propagation
{{KafkaRecordProcessor.propagateHeaders}} builds a {{Stream}} + spliterator +
two capturing lambdas for every consumed record, and re-resolves
{{exchange.getIn()}} per header. Replacing it with a plain enhanced-for loop
over {{consumerRecord.headers()}} with a hoisted {{Message}} removes the
per-record pipeline and lambda garbage. Behaviour is identical.
h3. 3. Transforms: ObjectMapper allocated per message
Six transform classes ({{HoistField}}, {{MaskField}}, {{ExtractField}},
{{ReplaceField}}, {{MessageTimestampRouter}}, {{ValueToKey}}) construct a {{new
ObjectMapper()}} on every invocation. {{ObjectMapper}} is expensive to
construct and thread-safe once configured; these back the corresponding Kamelet
actions and therefore run per message. Reusing a single shared static
{{ObjectMapper}} removes the allocation.
All three changes are behaviour-preserving and covered by existing unit tests
plus additions.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)