除了非常有用的已接受答案外,我还要添加一些其他详细信息
分区
默认情况下,Kafka使用消息的键来选择要写入的主题的分区。这是通过类似的方式完成的
hash(key) % number_of_partitions
如果没有提供密钥,则Kafka将以循环方式随机划分数据。
订购方式
如给定答案所述,Kafka保证仅在分区级别对消息进行排序。
假设您要在具有两个分区的Kafka主题中存储客户的财务交易。消息可能看起来像(key:value)
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": -1337}
null:{"customerId": 1, "changeInBankAccount": +200}
由于我们尚未定义键,因此两个分区可能看起来像
// partition 0
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}
// partition 1
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": -1337}
您的消费者在阅读该主题后可能会告诉您,特定时间该帐户的余额为600,尽管从来没有这样!只是因为它正在读取分区0中的所有消息,然后才读取分区1中的消息。
使用有意义的键(例如customerId),可以避免这种情况,因为partitoning如下所示:
// partition 0
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": -1337}
1:{"customerId": 1, "changeInBankAccount": +200}
// partition 1
2:{"customerId": 2, "changeInBankAccount": +100}
日志压缩
如果没有密钥作为消息的一部分,您将无法将主题配置设置cleanup.policy
为compacted
。根据文档, “日志压缩可确保Kafka将始终为单个主题分区的数据日志保留至少每个消息密钥的最后一个已知值”。
没有任何按键,将无法使用此好用且有用的设置。
按键用法
在实际的用例中,Kafka消息的密钥可能会对您的性能和业务逻辑的清晰度产生巨大影响。
例如,可以自然地使用密钥对数据进行分区。由于可以控制使用者从特定分区读取数据,因此可以用作有效的筛选器。此外,键可以在消息的实际值上包含一些元数据,以帮助您控制后续处理。键通常比值小,因此解析键而不是整个值更方便。同时,您可以将所有序列化和模式注册应用到您的值中,也可以通过密钥进行。
需要注意的是,还有Header概念可用于存储信息,请参阅文档。