I wrote a consumer in Python as below:
from kafka import KafkaConsumer
import avro.schema
import avro.io
import io
# To consume messages
consumer = KafkaConsumer('test',
group_id='',
bootstrap_servers=['kafka:9092'])
schema = """
{
"namespace":"com.martinkl.bottledwater.dbschema.public",
"type":"record",
"name":"test",
"fields":[
{"name":"id","type":["int", "null"]},
{"name":"value","type":["string", "null"]}
]
}
"""
schema = avro.schema.parse(schema)
for msg in consumer:
bytes_reader = io.BytesIO(msg.value)
decoder = avro.io.BinaryDecoder(bytes_reader)
reader = avro.io.DatumReader(schema)
hello = reader.read(decoder)
print hello
Everything seems OK, but when i run insert data to Postgres:
postgres=# insert into test (value) values('hello world!');
The output of consumer is empty:
$ python consumer_bottledwater-pg.py
{u'id': 0, u'value': u''}
Please help me to fix it out. Thank you in advance.
答案 0 :(得分:3)
Bottled Water发布给Kafka的Avro编码消息带有5个字节的标头。第一个字节始终为零(保留供将来使用),接下来的4个字节是一个32位的大端数字,表示模式的ID。
在您的示例中,您已经在Python应用程序中对模式进行了硬编码,但是一旦上游数据库模式发生更改,该方法就会崩溃。这就是为什么瓶装水最好与schema registry一起使用。当您从Kafka读取消息时,首先解码标头以查找架构ID,如果之前没有看到该架构ID,则query the registry找到架构。然后,您可以使用该架构解码消息的其余部分。模式可以缓存在使用者中,因为注册表保证特定ID的模式是不可变的。
您还可以查看架构注册表附带的KafkaAvroDeserializer的代码,以了解如何在Java中完成此解码。您可以在Python中执行相同的操作。
答案 1 :(得分:0)
非常感谢@Martin Kleppmann。我按你的指导做了。它运作正常。
value = bytearray(msg.value)
bytes_reader = io.BytesIO(value[5:])
decoder = avro.io.BinaryDecoder(bytes_reader)
reader = avro.io.DatumReader(schema)
hello = reader.read(decoder)
print hello
上的详细信息