We (Dinesh Kumar Ashokkumar and I) have recently debugged another issue related to Apache Kafka v0.8.2 (also exists in prior versions). The issue is not an issue per se but learning things hard way which is a side effects of a Kafka design choice.
I am assuming you know about Apache Kafka. If not, you may want to read my other post on Kafka which has short brief on it.
Problem: Clients of a topic rebalance every now and then, even if there are no connections or disconnections
Before we get into the details, let me lay down the context and conditions.
Apache Kafka uses Apache Zoo Keeper in different ways. Brokers use it for state management, and partition leader uses it for election and Consumer Clients use it for detecting the connects and disconnects of other Consumer Clients. It is Consumer Client usage that I am going to discuss here.
In Apache Kafka v0.8.2 (and prior versions), Consumer Clients are “thick” and “smart” clients in the sense that they coordinate between themselves for partition allocation (or assignment) among all the consumer connectors.
Apache Kafka High Level Consumer API, supports a single consumer connector to receive data of a given consumer group across multiple topics. That means, if you have completely different topics but have same consumer group name, you can use one connector to receive the data from all the topics. While this is a powerful feature when data has to be retrieved from multiple similar topics, it became a deadly feature for us.
Here are Zoo Keeper paths used by Kafka Consumers (kafka.consumer.ZookeeperConsumerConnector is the class that deals with zookeeper primarily):
|Purpose||Zoo Keeper Path||Value|
|Consumer Partition Owner Registry||/consumers/[group_id]/owner/[topic]/[broker_id-partition_id]||consumer_connector_id|
|Consumer Commit Offsets Registry||/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]||offset_counter_value|
|Consumer Identifiers Registry||/consumers/[group_id]/ids/[consumer_connector_id]|
Every consumer creates an ephemeral node under “Consumer Identifiers Registry” tree and registers itself as a watcher on the tree root. This helps a consumer client know about any new consumer client connects and any old consumer client disconnects.
As you can see this registry path is different from other registry paths of the consumer. Especially, Identifiers Registry is not tied to a topic but others are. This difference comes from the feature discussed above. If a consumer client connects with a consumer group name plus a set of topics, then that consumer client needs to be informed of client connects and disconnects in that consumer group across any topic. To facilitate that, Kafka team has chosen to not have topic in the Identifiers Registry Path.
Now, let’s dig little deep into the bug
Our topics are named aptly and we have put an effort to make sure the topic name clearly identifies its place in our architecture.
For a given topic, we have roughly 120+ partitions, and we chose to have separate consumer client (either a thread or a process) for each partition. That means, for a given topic and a given consumer group, we have about 120+ consumer clients.
For a given topic, we have a main consumer and it connects to that topic with consumer group name as “main”. Of course, there are other consumers of the same topic that connect to it with a different consumer group name. Like this we have completely different topics and each has different consumer clients connecting to it.
Now, in this situation if any topic has a new client or an existing client has disconnected, it is perfectly fine to have a rebalance of consumer clients of that particular topic. Instead what we have observed is that consumer clients of all topics have started rebalancing. While it is easy to say now (post finding the issue), it was not the same when the rebalances are happening, esp. since we did not know that all are nodes are rebalancing. While we were debugging the issue, we focused only on one topic and consumer group combo and tried to find a node is going into rebalance and never looked a macro picture. But after few days of debugging, we observed that whole gamut of consumer clients are rebalancing not just of one topic. We first suspected something seriously wrong with cluster (just a hunch, no real proof), so we have shutdown the Kafka cluster and brought it up. The problem disappeared!, hooray!
Well the problem did not disappear for long, it started again when one client of a topic disconnected, all clients across all topics started rebalancing again. We have understood that it is beyond a topic plus consumer combo logic that is tricking us in.
Feature or Trap?
This happens because of the Consumer Identifier Registry design. We have 10+ topics, with 120+ consumer clients using the consumer group name “main” for each topic, tallies to 1200+ consumers using consumer group name “main”. These many consumer clients get registered under Zoo Keeper path “/consumers/main/ids/” and every consumer client registers itself as a watcher on this whole tree.
If any consumer client of any topic disconnects, an ephemeral node of that consumer client under this Zoo Keeper path gets deleted and Zoo Keeper triggers all watchers of the tree path. That means, all 1200+ consumer clients (minus just disconnected consumer client) get notified by Zoo Keeper. Apache Kafka Client triggers rebalance as a response to this Watch event trigger.
As you can see, this is a well meaning feature for simplifying consumers to receive data from similar topics with same consumer group name has turned out to be disastrous for us.
What is the way out?
Solution is simple, just use a unique consumer group name. Avoid generic consumer group names by all means.
We had put a very good time in naming topics but not in consumer group names. This experience has led us to put good time in naming the consumer groups not only well, but unique.
Laxmi Narsimha Rao Oruganti
Grammar corrections (September 22, 2015)