(可能是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
构造函数提供一些额外的参数吗?
答案 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)