# -*- coding: utf-8 -*- ''' @Author : dingjiawen @Date : 2023/5/16 19:51 @Usage : @Desc : 一些使用kafka的demo ''' ''' 参考: [1] https://blog.csdn.net/fenglepeng/article/details/109454576 [2] https://zhuanlan.zhihu.com/p/279784873 ''' from kafka import KafkaProducer, KafkaConsumer from kafka.errors import kafka_errors import traceback import json # TODO KafkaProducer(**configs):参数 ''' bootstrap_servers –'host[:port]'字符串,或者由'host[:port]'组成的字符串,形如['10.202.24.5:9096', '10.202.24.6:9096', '10.202.24.7:9096']),其中,host为broker(Broker:缓存代理,Kafka集群中的单台服务器)地址,默认值为 localhost, port默认值为9092,这里可以不用填写所有broker的host和port,但必须保证至少有一个broker) key_serializer (可调用对象) –用于转换用户提供的key值为字节,必须返回字节数据。 如果为None,则等同调用f(key)。 默认值: None. value_serializer(可调用对象) – 用于转换用户提供的value消息值为字节,必须返回字节数据。 如果为None,则等同调用f(value)。 默认值: None. ''' # TODO TODO send(topic, value=None, key=None, headers=None, partition=None, timestamp_ms=None) ''' 函数返回FutureRecordMetadata类型的RecordMetadata数据 topic(str) – 设置消息将要发布到的主题,即消息所属主题 value(可选) – 消息内容,必须为字节数据,或者通过value_serializer序列化后的字节数据。如果为None,则key必填,消息等同于“删除”。( If value is None, key is required and message acts as a ‘delete’) partition (int, 可选) – 指定分区。如果未设置,则使用配置的partitioner key (可选) – 和消息对应的key,可用于决定消息发送到哪个分区。如果partition为None,则相同key的消息会被发布到相同分区(但是如果key为None,则随机选取分区)(If partition is None (and producer’s partitioner config is left as default), then messages with the same key will be delivered to the same partition (but if key is None, partition is chosen randomly)). 必须为字节数据或者通过配置的key_serializer序列化后的字节数据. headers (可选) – 设置消息header,header-value键值对表示的list。list项为元组:格式 (str_header,bytes_value) timestamp_ms (int, 可选) –毫秒数 (从1970 1月1日 UTC算起) ,作为消息时间戳。默认为当前时间 ''' def producer_demo(): # 假设生产的消息为键值对(不是一定要键值对),且序列化方式为json producer = KafkaProducer( bootstrap_servers=['192.168.118.202:9092'], key_serializer=lambda v: json.dumps(v).encode('utf-8'), value_serializer=lambda v: json.dumps(v).encode('utf-8'), ) # # producer = KafkaProducer( # bootstrap_servers=['192.168.118.202:9092'], # key_serializer=str.encode('utf-8'), # value_serializer=str.encode('utf-8'), # ) # producer = KafkaProducer( # bootstrap_servers=['192.168.118.202:9092'] # ) # 发送三条消息 for i in range(0, 3): data = {"status": 0, "msg": "", "data": [{"name": "海门", "value": 1}, {"name": "鄂尔多斯", "value": 1}]} print(json.dumps(data)) print(type(json.dumps(data))) # send_data = json.dumps(data).encode('GBK') data_send = json.dumps(data) future = producer.send( 'pykafka_demo', value=data_send ) # 向分区1发送消息 print("send {}".format( data_send)) try: future.get(timeout=10) # 监控是否发送成功 except kafka_errors: # 发送失败抛出kafka_errors traceback.format_exc() # TODO class kafka.KafkaConsumer(*topics, **configs) ''' *topics (str) – 可选,设置需要订阅的topic,如果未设置,需要在消费记录前调用subscribe或者assign。 bootstrap_servers –'host[:port]'字符串,或者由'host[:port]'组成的字符串,形如['10.202.24.5:9096', '10.202.24.6:9096', '10.202.24.7:9096']),其中,host为broker(Broker:缓存代理,Kafka集群中的单台服务器)地址,默认值为 localhost, port默认值为9092,这里可以不用填写所有broker的host和port,但必须保证至少有一个broker) client_id (str) – 客户端名称,默认值: ‘kafka-python-{version}’ group_id (str or None) – 消费组名称。如果为None,则通过group coordinator auto-partition分区分配,offset提交被禁用。默认为None auto_offset_reset (str) – 重置offset策略: 'earliest'将移动到最老的可用消息, 'latest'将移动到最近消息。 设置为其它任何值将抛出异常。默认值:'latest'。 enable_auto_commit (bool) – 如果为True,将自动定时提交消费者offset。默认为True。 auto_commit_interval_ms (int) – 自动提交offset之间的间隔毫秒数。如果enable_auto_commit 为true,默认值为: 5000。 value_deserializer(可调用对象) - 携带原始消息value并返回反序列化后的value consumer_timeout_ms – 毫秒数,若不指定 consumer_timeout_ms,默认一直循环等待接收,若指定,则超时返回,不再等待 max_poll_interval_ms – 毫秒数,它表示最大的poll数据间隔,如果超过这个间隔没有发起pool请求,但heartbeat仍旧在发,就认为该 consumer 处于 livelock 状态,进行 reblancing session_timout_ms – 毫秒数,控制心跳超时时间。在分布式系统中,由于网络问题你不清楚没接收到心跳,是因为对方真正挂了还是只是因为负载过重没来得及发生心跳或是网络堵塞。所以一般会约定一个时间,超时即判定对方挂了 heartbeat_interval_ms – 毫秒数,控制心跳发送频率,频率越高越不容易被误判,但也会消耗更多资源。 max_pool_record(int),kafka 每次 pool 拉取消息的最大数量 ''' def consumer_demo(): consumer = KafkaConsumer( 'aaa', bootstrap_servers=['192.168.118.202:9092'], group_id='test' ) for message in consumer: message1 = str(message.value, encoding="utf-8") print(message1) print(type(message1)) # print("receive, key: {}, value: {}".format( # json.loads(message.key), # json.loads(message.value) # ) # ) pass if __name__ == '__main__': consumer_demo() # producer_demo()