kafka-python 1.3.3:带有显式键的KafkaProducer.send无法向代理发送消息

时间:2017-08-02 20:09:04

标签: kafka-producer-api kafka-python

可能Can't send a keyedMessage to brokers with partitioner.class=kafka.producer.DefaultPartitioner的副本,虽然该问题的OP没有提及kafka-python。无论如何,它从来没有得到答案。)

我有一个Python程序已成功(几个月)向Kafka代理发送消息,主要使用以下逻辑:

producer = kafka.KafkaProducer(bootstrap_servers=[some_addr],
                               retries=3)
...
msg = json.dumps(some_message)
res = producer.send(some_topic, value=msg)

最近,我尝试升级它,根据​​从邮件中提取的明确密钥值将邮件发送到不同的分区:

producer = kafka.KafkaProducer(bootstrap_servers=[some_addr],
                               key_serializer=str.encode,
                               retries=3)
...
try: 
    key = some_message[0]
except:
    key = None
msg = json.dumps(some_message)
res = producer.send(some_topic, value=msg, key=key)

但是,使用此代码, no 消息可以将其从程序中删除。我已经验证从some_message中提取的键值始终是有效字符串。据推测,我不需要定义自己的partitioner,因为根据文档:

  

默认分区程序实现使用与java客户端相同的murmur2算法对每个非None键进行哈希处理,以便将具有相同键的消息分配给同一分区。

此外,使用新代码,当我尝试通过调用send(获取res.get)来确定kafka.FutureRecordMetadata发生的事情时, 调用会抛出TypeError个异常,并显示消息descriptor 'encode' requires a 'str' object but received a 'unicode'

(作为一个附带问题,如果我真的能够得到它,我并不完全确定我对FutureRecordMetadata做了什么。基于kafka-python源代码,我假设我想要调用其succeeded或其failed方法,但文档中没有提及。文档确实表示返回值send"已解决为" RecordMetadata,但我无法从文档或代码中找出"解析为"" ;在这种情况下意味着。)

无论如何:我不能成为使用kafka-python 1.3.3的唯一一个曾经尝试使用分区键发送消息的人,我还没有看到任何描述类似问题的Intertubes (除了我在本文顶部引用的SO问题)。

我当然愿意相信我做错了什么,但我不知道那可能是什么。我需要为KafkaProducer构造函数提供一些额外的参数吗?

2 个答案:

答案 0 :(得分:0)

基本问题是我的关键值是<ul class="menu"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li class="menu-item-has-children"><a href="#">Services</a> <ul class="sub-menu"> <li><a href="#">Plumbing</a></li> <li class="menu-item-has-children"><a href="#">Heating</a> <ul class="sub-menu sub-menu2"> <li><a href="#">Residential</a></li> <li><a href="#">Commercial</a></li> <li><a href="#">Industrial</a></li> </ul> </li> <li><a href="#">Electrical</a></li> </ul> </li> <li><a href="#">Pricing</a></li> <li><a href="#">Contact Us</a></li> </ul>,尽管我确信它是unicode。因此,为str选择str.encode是不合适的,这是导致key_serializer例外的原因。省略res.get并调用key_serializer足以让我的邮件发布,并按预期进行分区。

对于这个问题(对我来说)的默默无闻的一个主要原因是kafka-python 1.3.3 documentation没有详细说明key.encode('utf-8')究竟是什么,也不是什么应该以例外的方式期望它的FutureRecordMetadata方法可以提高。文档中唯一的用法示例:

get

建议它引发的唯一一种例外是# Asynchronous by default future = producer.send('my-topic', b'raw_bytes') # Block for 'synchronous' sends try: record_metadata = future.get(timeout=10) except KafkaError: # Decide what to do if produce request failed... log.exception() pass 这不是真的。实际上,KafkaError可以并且将(重新)提出异常发布机制在尝试将消息传出门外时遇到的任何异常。

答案 1 :(得分:0)

我也遇到了同样的错误。一旦我在发送密钥的同时添加了json.dumps,它就起作用了。

producer.send(topic="first_topic", key=json.dumps(key)
.encode('utf-8'), value=json.dumps(msg)
.encode('utf-8'))
.add_callback(on_send_success).add_errback(on_send_error)