What Differs from Kafka
Understand the KubeMQ Kafka behaviors that need attention before moving a production workload from Apache Kafka, including share groups.
KubeMQ accepts standard Kafka clients, but three behaviors need an explicit check before a production migration. Workloads that use share groups (KIP-932) have their own list, in Share groups below.
Delivery acknowledgements
On a multi-node deployment, use acks=1 or acks=all. An acks=0 produce sent to a follower is not forwarded to the leader and is dropped without a response. A single-node deployment has no follower, so this case does not apply. See Durability and retention.
Retention limits
retention.ms can evict records when it is set to a finite positive value. retention.bytes is accepted and returned by the API, but it does not enforce a size limit. Set a time retention limit and monitor storage until size-based retention is available. See Durability and retention.
Keyed partitioning
The Kafka client chooses the partition for a keyed record. Java and franz-go use a murmur2-based hash by default, while librdkafka-based clients such as kcat and confluent-kafka use CRC32. The same key can therefore land on different partitions when producer libraries differ. Use one partitioning strategy for a topic that depends on per-key ordering. See Partitions and ordering.
Share groups
Share groups are generally available. These are the deliberate differences from Apache Kafka 4.3 — documented scope limits, not open defects. The first three are the ones most likely to matter. See Share Groups for how each setting named here works.
- A dead consumer's records come back later. When a consumer dies holding records, KubeMQ hands them out again only when their acquisition lock expires — 30 seconds by default, the group's
share.record.lock.duration.ms. Kafka releases them as soon as the connection drops. Nothing is lost; redelivery is only slower. ShareFetchdoes not wait. It answers as soon as it has a result, instead of waiting up to the client's requested maximum wait.- The in-flight limit counts stored batches.
share.partition.max.record.locks(2000 by default) counts the batches a producer sent, not records, so with a batching producer more than 2000 records can be in flight. - Fetch sizes count stored batches.
share.acquire.mode=record_limitis honored in whole stored batches, and the defaultbatch_optimizedmode also counts stored batches, so a fetch can return more thanmax.poll.recordsrecords. - Release and renew act on the whole stored batch. A Release, a renew, and any acknowledgement deferred behind a renew apply to every record in the same stored batch, so records you already accepted in a released record's batch come back as duplicates.
share.assignment.interval.msis refused. Every member is assigned every partition, so there is no interval to tune.- Describing all group configs lists only groups with members.
ListConfigResources(key 74) is not served, sokafka-configs.sh --entity-type groups --describewithout--entity-namelists only groups that have members. - A leader change counts a delivery attempt. Every record in flight when a partition's leader changes — a killed node, any restart including a clean one, each step of a rolling upgrade — counts one delivery attempt. A low
share.delivery.count.limitcan therefore archive a healthy record early; keep it at 5 or higher on groups that must survive rolling restarts. WithCONNECTORS_KAFKA_SHARE_FEATURE_VERSION=1, a record released because its consumer left, was evicted, or dropped the topic from its subscription is handed out again without counting. - Some late acknowledgements are not refused. An Accept, Release or Reject for a record the consumer no longer holds is refused
INVALID_RECORD_STATEwith nothing applied, as in Kafka, when another consumer holds the record now. When nobody holds it, KubeMQ does not refuse it: a released record takes the Accept or Reject, and a record already acknowledged or never acquired ignores it. Kafka answersINVALID_RECORD_STATEin those cases, so on KubeMQ a late acknowledgement from a consumer whose lock expired can be reported as successful. - A new partition starts on the next heartbeat. A partition the group first sees after it joined starts at the group's start position on the member's next heartbeat.
by_durationuses ingest time.share.auto.offset.reset=by_duration:<ISO-8601>compares KubeMQ's own ingest time, not the producer'sCreateTime.- Group configuration outlives the group. A group's configuration is kept when the group is deleted (not verified against Kafka's own behavior), a value stored after clamping is never re-clamped when the server's bounds later tighten, and no config synonyms are reported.
- An unknown group describes as
Dead.ShareGroupDescribefor a group that never existed answers stateDead, notGROUP_ID_NOT_FOUND. - Deleting start offsets resets to the log start.
DeleteShareGroupOffsetsmoves the group to the start of the log, where Kafka 4.3 re-appliesshare.auto.offset.reset. - Stricter group ids.
AlterShareGroupOffsetsrefuses a group id no KubeMQ consumer could join (containing/,*or>, a leading or trailing dot,.., or empty) withINVALID_GROUP_ID. Every API that can create group state refuses a group id that is not valid UTF-8, where Kafka substitutes the invalid bytes and proceeds: the group APIs,ShareGroupHeartbeatandAlterShareGroupOffsetsanswerINVALID_GROUP_ID;ShareFetch,ShareAcknowledgeand group-config requests answerINVALID_REQUEST. - A
read_committededge case costs one attempt. An aborted-transaction record or transaction marker acquired just before the share coordinator stops costs one counted delivery attempt before it is discarded. The consumer never sees it. - A cap on the number of share groups. Share groups count against
CONNECTORS_KAFKA_MAX_GROUPS(10000 by default), separately from classic groups, and keep counting until they are deleted. Apache Kafka 4.3 has no such limit. - librdkafka's share consumer stays advisory. It is an upstream preview; KubeMQ checks it but does not certify it.
Not built yet: a dead-letter queue for share groups (KIP-1191, arriving in Kafka 4.4), and acknowledgements inside transactions.
Upgrades: a cluster must follow the share-group upgrade rule when moving from a release before share groups became generally available — see Upgrading a cluster.
Was this page helpful?
Durability & Retention
How Kafka durability maps to KubeMQ — the acks 0/1/all contract, quorum-fsynced zero-acked-loss, retention by time and size, and log compaction.
Getting Started
Start kubemq-server, then produce and consume your first message over the Kafka wire protocol with kcat and seven client libraries — a full round-trip.