Skip to main content

Kafka Messages and Data Consistency

Kafka Message and Data Consistency


With its scalability and fault tolerance features, Kafak has been becoming more an more popular in large scale,  real time  enterprise applications. Kafka messages are published to partitions that are usually located on different nodes and consumed by multiple consumers, each of which read messages from a single partition. This raises a data consistency issue due to multiple partitions and consumers. For example, if a security in a trading system is modified twice within a very short time and the messages could be published to two different partitions. As a result, the two messages are processed by two consumers and there is no guarantee that the last message ends up in your application or your data storage. How can this issue be resolved?


Kafka Key With Single Threaded Consumer

Kafka message is published with a key and payload. The messages with the same key are published to the same partition that will be consumed by the same consumer. In this case, the early message is guaranteed to be consumed before the later messages by a single threaded consumer. The important point is that your consumer must be single threaded to prevent the earlier message from being persisted in your data storage. How to design the key for your message is important to avoid hot partition (one partition receives lots of messages while other partitions get very few messages) in Kafka topics. Suppose your system publishes messages of user information, the possible key could be user id plus email as the key. This helps better distribute your messages among kafka partitions.


Kafka Key, Transaction ID/Event Time and Multi-Threaded Consumer

This key based single threaded solution is good for small and medium sized applications. This will not work for a large size application, especially in its peak time. In a large application that needs to handle a large number of messages, the consumers have to be multi-threaded (usually through thread pool). Since the consumer is multi-threaded, there is still chance the first message could end up in your database than the second message. This can be solved with key plus a transaction id like version id or message timestamp. The message timestamp is the time at which the message is generated instead of the time the message is processed.

For example. A user message is composed of payload(userId, userName, versionId) and the kafka message key is userId. When the user modifies his info twice in a very short time, two messages are written into kafka log with versionId 1 and versionId 2. Suppose the user table is as follows,

      User( userId int, userName char(64), versionId int).

When the multiple-threaded consumer persists the message to the table, the update statement can be written as a conditional update as follows,

    Update User set userName = 'new name' where userId = #userId# and (versionId < #new versionId# )

Since the sql update is an atomic operation, the data consistency is guaranteed with versionId 2 sits in the data storage.

The same result can be achieved with event time. In this case, the table will be like

User( userId int, userName char(64), lastUpdatedTime datetime)

And the sql statement will be like

Update User set userName = 'new name' where userId = #userId# and (lastUpdateTime < #lastUpdateTime# )

Kafka Key, Compaction, and Data Consistency in Data Recovery

Kafka topic can be configured with compaction. Suppose two or more messages with the same key are written to the same partition, the first message will be deleted after a certain amount of time if the topic is enabled with compaction. This is very useful for data recovery in case your kafka consumers crashes or your data consumed from the kafka is corrupted. Because the data is compacted with earlier messages removed from the kafka log, there is no concern for data inconsistency when re-consuming the messages from the compacted topic.

Conclusion

It is a very common issue to keep data consistency in an application involving message producing and consumption. Kafka provides the technique with key and compaction to help solve the issue.








  

Comments

Popular posts from this blog

Apache Nifi and System Integration

Apache Nifi and System Integration Introduction Apache Nifi is a distributed data platform based on enterprise integration pattern(EIP). It is a very powerful tool to build data pipeline with its large number of built-in processors.In today's service orientated architecture or a system composed of micro services, the flow of data among systems is fundamental in building enterprise applications. Among integration tools (Mule ESB, Apache Camel, Apache Nifi), Nifi is my favorite due to its built-in processors, ease to use and dynamic/hot redeployment, all leading to high productivity. When it is used together with Kafka connector, we can build real time CDC(change data capture) bi-direction integration system. This feature is especially useful in application re-engineering and migration. Nifi Basics Unlike camel, Nifi is a web based integration tool where you configure your processors, the building block of Nifi, to pilepine your data from your source system to your target ...

Kafka Consumer: Why Group ID

Unlike  JMS consumers, Kafka consumers need group id. Why? Let's start the analysis from JMS consumers. JMS supports both queue and topic as follows,   point-to-point queue with multiple consumers, each of which receives a subset of the messages in the queue. publisher subscriber topic with multiple consumers, each of which receives a full copy of all the messages in the topic. JMS queue obviously has the advantage of load balancing in message consumption, while a topic has the advantage of supporting multiple subscribers. Now the question is how we combine JMS queue and topic into a single message model(without a separate queue and topic) with the advantage of both load balancing and multiple subscribers. With the introduction of group id , this objective is achieved in kafka. Specifically, a kafka consumer group is composed of one or more consumers with the same group id , and each consumes a subset of the messages based on kafka topic partition. Moreover...