[ 
https://issues.apache.org/jira/browse/KAFKA-21363?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18133807#comment-18133807
 ] 

Matthias J. Sax commented on KAFKA-21363:
-----------------------------------------

{quote}On the producer side, if I read it right, sendOffsetsToTransaction 
returns straight away when the map is empty, so neither AddOffsetsToTxn nor 
TxnOffsetCommit goes out. That seems to have come in with KAFKA-13319 (3.1.0), 
to avoid markers piling up in __consumer_offsets.
{quote}
That's what I expected...
{quote}On the broker side, KafkaApis.handleTxnOffsetCommitRequest looks like it 
answers a TxnOffsetCommit without topics by itself, without going to the group 
coordinator (I saw the same on 3.0 and trunk). So my understanding is that 
allowing an empty map would need a broker change too, and older brokers would 
still skip the check.
{quote}
That would be a pickle... Maybe [~jolshan] can chime in? (Given that 
punctuations and EOS are in general kind of an anti-pattern, I would personally 
be ok to only fix for newer version is we need a broker change).

> Streams EOS: member cut off from the group coordinator keeps committing 
> punctuator writes unfenced, and its store diverges from the changelog after a 
> clean restart
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: KAFKA-21363
>                 URL: https://issues.apache.org/jira/browse/KAFKA-21363
>             Project: Kafka
>          Issue Type: Bug
>          Components: streams
>    Affects Versions: 4.4.0
>            Reporter: Eswarar Siva
>            Priority: Major
>
> With exactly_once_v2 and the classic group protocol, a Streams instance that 
> cannot reach the group coordinator keeps its active task and keeps committing 
> what its wall clock punctuator writes, while the group has already given the 
> same task to another instance. Both instances write the same changelog 
> partition and neither is fenced. If the cut off instance is then closed 
> cleanly, it keeps its state directory, and on restart it restores only from 
> its own checkpoint offset onwards. The other instance's records below that 
> offset are never applied, so the store no longer matches its changelog.
> Reproduced twice end to end with 4.4.0 clients against 4.3.0 brokers. Line 
> numbers below are at 4.4.0, the same code is on trunk. The streams group 
> protocol (KIP-1071) was not tested.
> Why the instance keeps the task:
> -> ConsumerCoordinator.poll calls pollHeartbeat (525), then returns early 
> while the coordinator is unknown (526-528), before the rejoin check at 530. 
> The task is never revoked or marked lost.
> -> In the heartbeat thread (AbstractCoordinator 1513-1531) the 
> coordinatorUnknown() branch only looks up the coordinator again and backs 
> off. The session timeout branch at 1523 only marks the coordinator unknown, 
> and the poll timeout leave at 1528 is an else-if after 1513, so it is not 
> reached while the coordinator is unknown.
> Why EOS does not fence it:
> -> A punctuator only commit has no input offsets. 
> TaskExecutor.commitOffsetsOrTransaction still commits because a transaction 
> is in flight (181-186) and passes an empty map to 
> StreamsProducer.commitTransaction, which calls sendOffsetsToTransaction (249).
> -> KafkaProducer.sendOffsetsToTransaction only contacts the group coordinator 
> when the map is not empty (800, from KAFKA-13319). The transaction commits 
> against the transaction coordinator, which is still reachable, and group 
> membership is never checked.
> -> The two instances have different transactional ids, so they do not fence 
> each other either. Their changelog records interleave.
> Why the store stays wrong:
> -> A clean close keeps the task directory. StateManagerUtil only wipes on an 
> unclean close (168-169, 183-189; transactional state stores were off).
> -> On restart ProcessorStateManager initialises the store offset from the 
> store's own committed offset (334-338) and StoreChangelogReader seeks to that 
> offset + 1 (1028-1032). Nothing below it is read again.
> Setup:
> # Three KRaft brokers. __consumer_offsets on broker 2, __transaction_state on 
> broker 1, the input topic (1 partition) and the changelog on broker 3.
> # Two instances A and B, exactly_once_v2, commit.interval.ms=100, 
> session.timeout.ms=6000, heartbeat.interval.ms=2000, one persistent 
> KeyValueStore, a 1 s wall clock punctuator that puts a new key each time. No 
> input traffic.
> # Blackhole the route from the instance that owns 0_0 (A) to broker 2 only. 
> Within 30 s B has 0_0 active while A still reports 0_0 active, stays RUNNING 
> and keeps punctuating.
> # After one to two minutes close A cleanly (end of run in the first run, 
> SIGTERM in the second). One "Closed clean", task directory kept.
> # Restart A on the same state directory. Restore a third instance from an 
> empty state directory as the reference.
> Results:
> ||Run||A records in changelog||B records in changelog||A restarted from 
> checkpoint||B keys in reference store||B keys in restarted A||Missing||
> |1|208 (offsets 0 to 626)|554 (offsets 204 to 1522)|626|554|448|106, all at 
> offsets 204 to 624|
> |2|178 (offsets 0 to 522)|85 (offsets 188 to 524)|522|85|1|84, all at offsets 
> 188 to 520|
> Restarted A logs "State store store initialized from checkpoint with offset 
> 626" (run 1) and restores from 627 on. A's own keys are all there. Nothing 
> repairs this later since the checkpoint looks valid to Streams.
> Not run, only follows from the same path: a key B deleted below A's 
> checkpoint offset keeps A's old value after the restart.
> What I think could be done: check group membership on the transactional 
> commit even when there are no offsets to send, or treat a coordinator that 
> stays unknown past the session timeout as losing the assignment, or let the 
> poll timeout leave run outside the coordinatorUnknown() branch. Not sure 
> which one fits best.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to