Kafka-python基础实践

780 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

Kafka基本概念

Kafka 是一种分布式的,基于发布 / 订阅的消息系统。主要设计目标如下:

  • 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。
  • 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒 100K 条以上消息的传输。
  • 支持 Kafka Server 间的消息分区,及分布式消费,同时保证每个 Partition 内的消息顺序传输。
  • 同时支持离线数据处理和实时数据处理。
  • Scale out:支持在线水平扩展。

以上内容引自 Kafka【入门】就这一篇

我的理解Kafka就是流数据的中转站或者说流数据落库之前的大缓存,为了解决流数据发送速度与落库速度不匹配而设置的“妈妈驿站”。

Kafka-Python实践

官方文档:kafka-python.readthedocs.io/en/master/i…

安装

pip install kafka-python

生产者

作用是发送(生产)消息到Kafka,初步设置如下

from kafka import KafkaProducer

'''ip地址:端口号,server也可为一个字符串列表,代表一个服务器集群'''
server_name = "xxx.xxx.x.xx:yyyy" 

'''
producer在创建时还有很多参数,比如:
retries(int):发送失败时的重发次数,默认值0
request_timeout_ms(int):客户端请求超时,单位:ms,默认值30000
更多请见官方文档
'''
producer = KafkaProducer(bootstrap_servers=server_name)

此时可以通过bootstrap_connected()来验证是否连接上服务器,连接上时会返回True。之后可以指定要发送的topic,使用send()来发送消息,注意发送的消息必须是bytes类型

import json
data = {'fruits':'apple', 'animal':'cat'}
data = json.dumps(data, ensure_ascii=False).encode('utf-8')
producer.send('test',data)

image.png 也可以在创建生产者时使用参数value_serializer格式化消息,而不用每次自己单独再格式化

from kafka import KafkaProducer
import json
producer = KafkaProducer(bootstrap_servers=server_name, value_serializer=lambda m: json.dumps(m).encode('utf-8'))
data = {'fruits':'apple', 'animal':'cat'}
producer.send('test',data)

可以在Offset Explorer中查看发送的数据。同样的,我们可以用get()方法来验证该条消息有没有成功发送。该方法会返回一条RecordMetadata数据,包含发送消息的所有信息,如topic/partition/offset等

future = producer.send('test',data)
print(future.get(timeout=10))

image.png

send()时可以添加add_callback()add_errback()来更方便地获取消息发送的情况;

producer.flush()可以将程序暂时阻塞,直到缓冲区所有的消息都被发送,方便异步发送:

def on_send_success(record_metadata):
    print(record_metadata.topic)
    print(record_metadata.partition)
    print(record_metadata.offset)

def on_send_error(excp):
    log.error('I am an errback', exc_info=excp)
  

data = {'fruits':'banana', 'animal':'dog'}
producer.send('test', data).add_callback(on_send_success).add_errback(on_send_error)
producer.flush()

消费者

作用是从Kafka上获取(消费)数据,初步设置如下:

from kafka import KafkaConsumer

server_name = "xxx.xxx.x.xx:yyyy" 
get_topic_name = "test"

'''
其他可选参数包括:
enable_auto_commit(bool):消费者消费完后是否自动提交消费位置, 默认值True.若该项为True, 则两次提交的间隔为auto_commit_interval_ms
consumer_timeout_ms(int):何时停止监听消息的迭代, 单位:ms, 默认值永不停止[float('inf')]
更多请见官方文档
'''
consumer = KafkaConsumer(
                get_topic_name, # 要消费的topic
                bootstrap_servers=server_name,  # kafka集群地址
                # group_id=consumer_gid,  # 消费组id
                auto_offset_reset="latest",  # 消费模式:earliest,latest
            )

其中group_id是消费者的分组,broker中的每一条数据只能被消费组中的一个consumer消费,不同组的consumer可以同时消费同一个topic。

而auto_offset_reset可以设置消费模式,即从哪一个offset开始消费,如果要从头消费(从尚未消费的地方开始消费),可以设置为earliest;要从当前时刻开始消费,可以设置为latest。

监听topic是通过循环迭代来实现的:

import json

for message in consumer:
    print("%s:%d: key=%s value=%s" % (message.topic, message.offset, message.key, message.value))
    print("RECV:{}".format(json.loads(message.value.decode('utf-8'))))

image.png

可以看到,消费消息时拿到的仍然时bytes类的数据,因此常常需要用json.loads()对其进行解码。同样的,我们也可以在创建消费者时用value_deserializer参数设置自动格式化value,如:value_deserializer=lambda m: json.loads(m.decode('utf-8'))

根据需要,也可以获取到消息的offset/key/topic等信息。

需要注意的是,根据实际的工程化环境和性能要求,可能要设置多个消费者线程或者队列一起消费,就会产生同步/异步的问题,如果之后有遇到会在进行记录