We're using the 'roundrobin' partition assignment strategy, and sometimes I get segfaults in rdk:main. I looked at one of these in more detail:
~~~~
member_cnt=<optimized out>, eligible_topics=0x7fc0b805bfa0, eligible_topic_cnt=12, errstr=0x7fc0d97f9a00 "", errstr_size=8, opaque=0x0) at rdkafka_roundrobin_assignor.c:80
member_cnt=member_cnt@entry=2, errstr=errstr@entry=0x7fc0d97f9a00 "", errstr_size=512) at rdkafka_assignor.c:331
at rdkafka_cgrp.c:671
opaque=opaque@entry=0x0) at rdkafka_queue.c:481
~~~~
Note:
It seems that in rd_kafka_roundrobin_assignor_assign_cb the code is running over the length of the members array:
(gdb) up
#1 0x00007fc0f32d7fb4 in rd_kafka_roundrobin_assignor_assign_cb (rk=0x7fc0d4002e50, member_id=<optimized out>, protocol_name=<optimized out>, metadata=<optimized out>, members=0x7fc0b806a2e0,
member_cnt=<optimized out>, eligible_topics=0x7fc0b805bfa0, eligible_topic_cnt=12, errstr=0x7fc0d97f9a00 "", errstr_size=8, opaque=0x0) at rdkafka_roundrobin_assignor.c:80
80 for (partition = 0 ;
(gdb) p next
$12 = 2
(cf. "2", an index, to the member_cnt "2" seen in frame 2).
(gdb) p members[2]
$13 = {rkgm_subscription = 0x0, rkgm_assignment = 0x3885, rkgm_eligible = {rl_size = 0, rl_cnt = 0, rl_elems = 0xf4240, rl_free_cb = 0x0, rl_flags = 2, rl_elemsize = 0, rl_p = 0x8000000007},
rkgm_member_id = 0xff, rkgm_userdata = 0xd00000100, rkgm_member_metadata = 0x700}
I also looked the subscriptions involved for members[0]:
(gdb) p *members[0].rkgm_subscription
$21 = {cnt = 12, size = 24, elems = 0x7fc0b80591c0}
(gdb) p members[0].rkgm_subscription->elems[0]
$23 = {topic = 0x7fc0b8017ad0 "collaborne-commands", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[1]
$24 = {topic = 0x7fc0b8056e10 "collaborne-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[2]
$25 = {topic = 0x7fc0b805c110 "ml1-commands", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[3]
$26 = {topic = 0x7fc0b8016620 "ml1-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[4]
$27 = {topic = 0x7fc0b8016670 "ml2-commands", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[5]
$28 = {topic = 0x7fc0b8015bf0 "ml2-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[6]
$29 = {topic = 0x7fc0b803e260 "ml3-commands", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[7]
$30 = {topic = 0x7fc0b8058170 "ml3-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[8]
$31 = {topic = 0x7fc0b803e2b0 "ml4-commands", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[9]
$32 = {topic = 0x7fc0b80508f0 "ml4-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[10]
$33 = {topic = 0x7fc0b805ee50 "qa-commands", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[0].rkgm_subscription->elems[11]
$34 = {topic = 0x7fc0b80378d0 "qa-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
... and members[1]:
(gdb) p *members[1].rkgm_subscription
$50 = {cnt = 5, size = 10, elems = 0x7fc0b8015660}
(gdb) p members[1].rkgm_subscription->elems[0]
$42 = {topic = 0x7fc0b8057760 "collaborne-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[1].rkgm_subscription->elems[1]
$43 = {topic = 0x7fc0b8046c10 "ml1-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[1].rkgm_subscription->elems[2]
$44 = {topic = 0x7fc0b805e730 "ml2-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[1].rkgm_subscription->elems[3]
$45 = {topic = 0x7fc0b8037340 "ml3-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
(gdb) p members[1].rkgm_subscription->elems[4]
$46 = {topic = 0x7fc0b803d9e0 "qa-events", partition = -1, offset = -1001, metadata = 0x0, metadata_size = 0, opaque = 0x0, err = RD_KAFKA_RESP_ERR_NO_ERROR, _private = 0x0}
The crash doesn't always happen, and looking at the subscriptions there seems to be a good chance that it is caused by some form of concurrent modifications to the subscription list. This would not be impossible, our consumer does see changes in subscribed topics sometimes.
Looking at https://github.com/edenhill/librdkafka/blob/d7d58e5407852d17485cf8a82841523eb2b8f6d1/src/rdkafka_roundrobin_assignor.c#L85-L90: It seems that next++ should be guarded over the length of the members, for example:
next = (next+1) % member_cnt;
I'm also a bit in doubt about the later part in https://github.com/edenhill/librdkafka/blob/d7d58e5407852d17485cf8a82841523eb2b8f6d1/src/rdkafka_roundrobin_assignor.c#L105: Instead of checking the eligible topic this should probably use member_cnt as well.
Please provide the following information:
v0.11.5 (from pkgconfig)2.0.0partition.assignment.strategy=roundrobin (and others)Fedora 29/x86_64debug=.. as necessary) from librdkafkaCan you provide:
This way I can reproduce this locally.
the number of partitions for each subscribed topic
1 partition per topic.
the number of members and each member's topics subscription
2 members in total. The subscriptions seen in the gdb status seem reasonable to me, in the sense that members[1] was starting up and adding subscriptions, while members[0] was running already with a full set. The crash happened before the second member was fully started.
In other words:
member0 subscriptions: collaborne-commands, collaborne-events, ml1-commands, ml1-events, ml2-commands, ml2-events, ml3-commands, ml3-events, ml4-commands, ml4-events, qa-commands, qa-events
member1 subscriptions: collaborne-events, ml1-events, ml2-events, ml3-events, qa-events
The application startup works by incrementally adding subscriptions to the ...-events topics to the consumer, and then adding further subscriptions to the linked ...-commands topic a while later. The crash seemed to have happened at the starting phase of the second member, so seeing only some ...-events there "makes complete sense to me" :)
Unfortunately I wasn't able to capture the logs of this run, and I had to learn the hard way that coredumpctl debug (or something related to that thing) for some reason decided to delete the crash dump on me.
I have tried to debug the situation with loglevel set to cgrp, but wasn't able so far to get anything there.
FWIW: I now have a specific container image and matching coredump, so I can again look into the state. I've also checked how often this happens for us, and it seems to be very frequent, so that for now I'll have to switch back to the "range" strategy for our production systems.
It might be worthwhile to recompile librdkafka with --disable-optimization to get better backtraces, and then do the full gdb dance to provide enough information for me to create a reproducible test case
https://github.com/edenhill/librdkafka/pull/2650
I ran into this while using roundrobin assignment, it seemed to be caused by a race condition where a new topic is picked up by a subset of the consumers, and the code handling the case of an unsubscribed consumer overflows memory.
Reproducing:
Okay, so it sounds like it is a problem with asymetric subscriptions, we should add a unit test to trigger this.
When is this expected to be completed/closed?
I want to prevent bias of messages caused by range strategy.
This will be addressed after the transactions PR has been merged.
Most helpful comment
https://github.com/edenhill/librdkafka/pull/2650
I ran into this while using roundrobin assignment, it seemed to be caused by a race condition where a new topic is picked up by a subset of the consumers, and the code handling the case of an unsubscribed consumer overflows memory.
Reproducing: