Matthias J. Sax created KAFKA-20887:
---------------------------------------

             Summary: IQ metadata is incomplete during "streams" protocol 
rebalances, causing incorrect IQ results
                 Key: KAFKA-20887
                 URL: https://issues.apache.org/jira/browse/KAFKA-20887
             Project: Kafka
          Issue Type: Bug
          Components: streams
    Affects Versions: 4.1.0
            Reporter: Matthias J. Sax


Setting "Affects Version" to 4.1.0, even if "streams" is only "early access" in 
4.1.0, and should not be used in production.

Using the new "streams" groups, KafkaStreams#queryMetadataForKey() can compute 
the wrong partition for a key *_during a rebalance_* and return the wrong host, 
so IQ may return a "not found" for a keys that exist. Note, this is not an 
exception, but an incorrectly empty query result. This problem is affecting all 
IQ queries across IQv1 and IQv2, leading to incorrect query results that the 
user cannot detect.

*Root cause*

The client infers each source topic's partition count from the reported "host 
endpoint information":

- StreamThread → getTopicPartitionInfo(activeHostInfoMap) → 
StreamsMetadataState#onChange → partitionsByTopic
- SourceTopicsInfo#maxPartitions = partitionsByTopic.get(topic).size()
- keyQueryMetadataForKey passes maxPartitions to StreamPartitioner#partitions 
as the modulo

This assumes every task is present in the reported "host endpoint" metadata at 
all times. In the "classic" protocol this invariant is guaranteed — 
partitionsByHost is built from the assignor's complete target 
(StreamsPartitionAssignor Step Three), before cooperative revocation withholds 
anything.

However, it does not hold for the "streams" protocol. 
EndpointToPartitionsManager builds each EndpointToPartitions entry from that 
member's current assignedTasks(), and during reconciliation a migrating task 
sits in the old owner's tasksPendingRevocation — in no member's 
assignedTasks(), so in no entry at all.

It was a deliberate improvement via KIP-1071 (and the impact on IQ was missed): 
if a task is not assigned, IQ metadata should not claim it is, resulting in 
spurious user facing exception ("task migrated to another instance"), requiring 
user-code retries.

*Impact*

An in-flight task on a 4-partition topic drops the count to 3, so keys hash % 3 
instead of % 4. Roughly 75% of keys resolve to a wrong partition, and each maps 
to a host that legitimately owns that partition — live, store open — which may 
answers "key not found". No exception, no retry signal. Only the migrating 
partition's own keys should have been unavailable.

*Proposal*

Have the broker send the missing information in StreamsGroupHeartbeatResponse 
instead of the client inferring it — e.g. a field "unassigned partitions" or 
similar as part of `EndpointInformationEpoch` field, so the client's existing 
derivation keeps working with minimal client-side change.

Deriving the topic/partition metadata from the "host metadata" map was a 
deliberate choice to avoid an extra RPC from the client to the broker to fetch 
topic metadata, so having the client query the cluster is not the desired 
direction.

*Note:* The new fields must also consider tasks assigned to a client with 
`application.server=null`. – These tasks are filtered out from the "host 
endpoint" map, too.

The `application.server` issue is actually a long standing bug also affecting 
"classic". It's a corner case, of a mis-configured application. Applications 
should be configured such that all KafkaStreams clients set 
`application.server` or none; a mixed configuration is a wrong config – 
nevertheless, it should not break IQ's correctness, but rather only result in 
that the client with the missing config cannot be queried, ie, some tasks would 
be unavailable for IQ.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to