本文已参与「新人创作礼」活动,一起开启掘金创作之路
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)
也可以在创建生产者时使用参数
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))
在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'))))
可以看到,消费消息时拿到的仍然时bytes类的数据,因此常常需要用json.loads()对其进行解码。同样的,我们也可以在创建消费者时用value_deserializer参数设置自动格式化value,如:value_deserializer=lambda m: json.loads(m.decode('utf-8'))
根据需要,也可以获取到消息的offset/key/topic等信息。
需要注意的是,根据实际的工程化环境和性能要求,可能要设置多个消费者线程或者队列一起消费,就会产生同步/异步的问题,如果之后有遇到会在进行记录