在kafka消息有效负载中添加时间戳

时间:2013-09-11 07:31:06

标签: message-queue apache-kafka

我有什么方法可以在Kafka消息有效负载中使用时间戳头吗?我想检查消息是在消费者端创建的,并根据它来应用自定义逻辑。

修改

我正在尝试找到一种方法将一些自定义值(基本上是时间戳)附加到生产者发布的消息,以便我可以在特定的持续时间内使用消息。现在Kafka只确保邮件按照它们放入队列的顺序传递。但在我的情况下,先前生成的记录可能在某个延迟之后到达(因此在时间T1生成的消息可能具有比在稍后的时间T2生成的具有偏移0的另一个更高的偏移1)。出于这个原因,它们将不符合我在消费者端的预期。所以我基本上是在寻找一种方法来以有序的方式消费它们。

当前的Kafka 0.8版本无法在生产者端附加除“消息密钥”之外的任何内容,发现了类似的主题here,建议在消息有效负载中对​​其进行编码。但我做了很多搜索,但找不到可能的方法。

此外,我不知道这种方法是否会对Kafka的整体性能产生任何影响,因为它在内部管理消息偏移,并且从this页面可以看到没有暴露此类API

真的很感谢任何线索,如果我正在考虑这种方式,或者有任何可能的方法,我都准备尝试一下

4 个答案:

答案 0 :(得分:4)

如果您想在特定的持续时间内使用消息,那么我可以为您提供解决方案,但是从该持续时间开始以有序的方式消费消息是困难的。我也在寻找同样的解决方案。请查看以下链接

Message Sorting in Kafka Qqueue

获取特定时间数据的解决方案

对于时间T1,T2,...... TN,其中T是时间范围;在N个分区中划分主题。现在使用Partitioner Class生成消息,使用消息生成时间来决定应该为此消息使用哪个分区。

同样在消费时订阅您想要消费的时间范围的确切分区。

答案 1 :(得分:1)

您可以创建一个包含分区信息的类和创建此消息时的时间戳,然后将其用作Kafka消息的密钥。然后,您可以使用包装器Serde将此类转换为字节数组并返回,因为Kafka只能理解字节。然后,当您在消费者端收到消息作为一个字节包时,您可以反序列化它并检索时间戳,然后将其传递到您的逻辑中。

例如:

public class KafkaKey implements Serializable {
    private long mTimeStampInSeconds;
    /* This contains other partitioning data that will be used by the
    appropriate partitioner in Kafka. */
    private PartitionData mPartitionData;

    public KafkaKey(long timeStamp, ...) {
        /* Initialize key */
        mTimeStampInSeconds = timestamp;
    }

    /* Simple getter for timestamp */
    public long getTimeStampInSeconds() {
        return mTimeStampInSeconds;
    }

    public static byte[] toBytes(KafkaKey kafkaKey) {
        /* Some serialization logic. */
    }

    public static byte[] toBytes(byte[] kafkaKey) throws Exception {
        /* Some deserialization logic. */
    }
}

/* Producer End */

KafkaKey kafkaKey = new KafkaKey(System.getCurrentTimeMillis(), ... );
KeyedMessage<byte[], byte[]> kafkaMessage = new KeyedMessage<>(topic, KafkaKey.toBytes(kafkaKey), KafkaValue.toBytes(kafkaValue));

/* Consumer End */
MessageAndMetadata<byte[],byte[]> receivedMessage = (get from consumer);
KafkaKey kafkaKey = KafkaKey.fromBytes(receivedMessage.key());

long timestamp = kafkaKey.getTimeStampInSeconds();
/*
 * And happily ever after */

这比使特定分区与时间间隔相对应更灵活。否则,你将不得不继续为不同的时间范围添加分区,并保持一个单独的同步列表,表明哪个分区对应于什么时间范围,这可能会很快变得难以处理。

答案 2 :(得分:0)

This看起来会帮助您实现目标。它允许您轻松定义和编写隐藏(反)序列化负担的消息头。您必须提供的唯一事情是(de)序列化器,用于您通过电线发送的实际对象。此实现实际上会尽可能地延迟有效负载对象的反序列化过程,这意味着您可以(以非常高性能和透明的方式)反序列化标头,检查时间戳并仅反序列化有效负载(重位)if / when你确定这个对象对你有用。

答案 3 :(得分:0)

请注意,Kafka根据此讨论为消息的内部表示引入了时间戳: https://cwiki.apache.org/confluence/display/KAFKA/KIP-32+-+Add+timestamps+to+Kafka+message

和这些门票: https://issues.apache.org/jira/browse/KAFKA-2511

它应该适用于所有版本的Kafka 0.10.0.0及更高版本。

这里的问题是您按照不再需要的顺序摄取了邮件。如果订单很重要,那么您需要放弃相关生产者的并行性。消费者层面的问题就消失了。