Kafka教程(三)—— Python操作kafka

        kafka的producer是支持多线程的因为其会把topic里面的消息存储在各个partition里面,可以多线程操作。但是consumer不支持多线程,如果多线程操作的话,会造成offset紊乱无序。下面我们从两部分来介绍python是如何操作kafka的。

        第一部分是只有一个position的topic,此时我们模拟一个发布-订阅模式,即多个consumer同时消费一个topic,此外还会介绍如何读取自定义offset的数据。(即多个consumer消费一个topic,互不干预,每个consumer单独消费这个topic)

        第二部分是针对包含多个position的topic,此时生产者不需指定partition,因为zookeeper会根据一定的策略将消息存储在不同的partition,但是消费者可以指定position读取,这样可以实现多个consumer并行消费同一个topic。(即多个consumer消费一个topic,分区消费,每个consumer共同消费这个topic)

        ps:对于生产消费者的解释可以直接看代码里面的注释


1、一个partition的topic的消费

(1)生产者

"""
    生产者代码是线程安全的,支持多线程,而消费者则不然
"""

import time
import json
import datetime
from kafka import KafkaProducer

# 发送json数据
# producer = KafkaProducer(bootstrap_servers=["192.168.10.39:9092"], value_serializer=lambda v: json.dumps(v).encode('utf-8'), api_version=(0, 10))

# 发送普通数据
producer = KafkaProducer(bootstrap_servers=["192.168.10.39:9092"])

i = 0
for m in range(30):
    i+=1
    time_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(time_now, i)
    result = {
        "key": str(i),
        "value": time_now
    }

    # 向指定分区生产json数据
    # producer.send("testTopic", result, partition=0).get(timeout=30)

    # 生产key-value数据,不指定分区
    producer.send("testTopic", key=b'msg%d'%i, value=str.encode(time_now), partition=0).get(timeout=30)

    time.sleep(3)

(2)消费者 - zookeeper记录上次消费的offset,该程序可以复制多份,即多个consumer分别消费一个topic。我们也可以设置consumer group,试验一个partition只能被consumer group里面的一个consumer消费。

import json
from kafka import KafkaConsumer
from kafka.structs import TopicPartition

# auto_offset_reset - latest,消费kafka中最近的数据;earliest,消费最早的数据
# enable_auto_commit - 自动给zookeeper提交消费者的offset,这样consumer断开之后重新连接时,就可以沿着上次断开时的offset继续读下去
# auto_commit_interval_ms - 自动提交消费者offset的时间间隔
# group_id - 消费者加入的消费者群组,用于获取和提交偏移的名称,因此在需要设置auto_offset_reset时,必须添加group_id
# consumer_timeout_ms - 如果n秒内kafka中没有可供消费的数据,自动退出
# client_id - 消费者客户端的id,便于区分消费者群组中各个消费者

my_group_id = "my_group_1"
consumer = KafkaConsumer('testTopic', group_id=my_group_id, client_id='cliend2', bootstrap_servers="192.168.10.39:9092", auto_offset_reset='latest', enable_auto_commit=True)

for message in consumer:

    # 读取json数据
    # mes = str(message.value, encoding="utf-8")
    # mes_json = json.loads(mes)
    # print(message.partition, message.offset, message.offset, mes_json)

    # 读取普通key-value数据
    print(my_group_id, message.partition, message.offset, message.key, message.value)

(3)消费者 - 自定义offset

"""
    kafka的消费者不是线程安全的,不能多线程启用
    kafka不像其他的MQ,消费完数据,直接丢掉,而是会默认存储7天,存储7天后自动清除,故而可以从头开始消费
    从指定topic的partiotion的指定setoff开始消费
"""

import json
from kafka import KafkaConsumer
from kafka.structs import TopicPartition

consumer = KafkaConsumer(bootstrap_servers="192.168.10.39:9092")

# 获取topic分区信息
print("分区信息 = ", consumer.partitions_for_topic("testTopic"))

# 获取当前消费者订阅的topic
print("当前topic = ", consumer.subscription())

# 获取当前消费者topic、分区信息
print("当前topic和分区信息 = ", consumer.assignment())

# 获取当前消费者可消费的偏移量
print("可消费偏移量 = ", consumer.beginning_offsets(consumer.assignment()))

# 重置偏移量
partition = TopicPartition(topic='testTopic', partition=0)
consumer.assign([partition]) # 必须声明,consumer有两种订阅模式,一种是subscribe即topic粒度、使用group管理,一种是assign即topic-partition粒度、用户自己去管理
consumer.seek(partition, 5)

for message in consumer:

    # 读取json数据
    # mes = str(message.value, encoding="utf-8")
    # mes_json = json.loads(mes)
    # print(message.partition, message.offset, message.offset, mes_json)

    # 读取普通key-value数据
    print(message.partition, message.offset, message.key, message.value)

2、多个partition的topic的消费

        首先我们需要新建一个多partition的topic,命令如下:

# 创建包含2个partition的topic
bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 2 --topic test

# 查看topic详情
bin/kafka-topics.sh --describe --bootstrap-server localhost:9092 --topic test

(1)生产者

"""
    生产者代码是线程安全的,支持多线程,而消费者则不然
"""

import time
import json
import datetime
from kafka import KafkaProducer

# 发送json数据
# producer = KafkaProducer(bootstrap_servers=["192.168.10.39:9092"], value_serializer=lambda v: json.dumps(v).encode('utf-8'), api_version=(0, 10))

# 发送普通数据
producer = KafkaProducer(bootstrap_servers=["192.168.10.39:9092"])

i = 0
for m in range(30):
    i+=1
    time_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(time_now, i)
    result = {
        "key": str(i),
        "value": time_now
    }

    # 向指定分区生产json数据
    # producer.send("testTopic", result, partition=0).get(timeout=30)

    # 生产key-value数据,不指定分区
    producer.send("testTopicPartition", key=b'msg%d'%i, value=str.encode(time_now)).get(timeout=30)

    time.sleep(3)

(2)指定partition消费一

"""
    kafka的消费者不是线程安全的,不能多线程启用
    kafka不像其他的MQ,消费完数据,直接丢掉,而是会默认存储7天,存储7天后自动清除,故而可以从头开始消费
    从指定topic的partiotion的指定setoff开始消费
"""

import json
from kafka import KafkaConsumer
from kafka.structs import TopicPartition

consumer = KafkaConsumer(bootstrap_servers="192.168.10.39:9092")

# 获取topic分区信息
print("分区信息 = ", consumer.partitions_for_topic("testTopic"))

# 获取当前消费者订阅的topic
print("当前topic = ", consumer.subscription())

# 获取当前消费者topic、分区信息
print("当前topic和分区信息 = ", consumer.assignment())

# 获取当前消费者可消费的偏移量
print("可消费偏移量 = ", consumer.beginning_offsets(consumer.assignment()))

# 重置偏移量
partition = TopicPartition(topic='testTopicPartition', partition=0)
consumer.assign([partition]) # 必须声明,consumer有两种订阅模式,一种是subscribe即topic粒度、使用group管理,一种是assign即topic-partition粒度、用户自己去管理

for message in consumer:

    # 读取json数据
    # mes = str(message.value, encoding="utf-8")
    # mes_json = json.loads(mes)
    # print(message.partition, message.offset, message.offset, mes_json)

    # 读取普通key-value数据
    print(message.partition, message.offset, message.key, message.value)

(3)指定partition消费二

"""
    kafka的消费者不是线程安全的,不能多线程启用
    kafka不像其他的MQ,消费完数据,直接丢掉,而是会默认存储7天,存储7天后自动清除,故而可以从头开始消费
    从指定topic的partiotion的指定setoff开始消费
"""

import json
from kafka import KafkaConsumer
from kafka.structs import TopicPartition

consumer = KafkaConsumer(bootstrap_servers="192.168.10.39:9092")

# 获取topic分区信息
print("分区信息 = ", consumer.partitions_for_topic("testTopic"))

# 获取当前消费者订阅的topic
print("当前topic = ", consumer.subscription())

# 获取当前消费者topic、分区信息
print("当前topic和分区信息 = ", consumer.assignment())

# 获取当前消费者可消费的偏移量
print("可消费偏移量 = ", consumer.beginning_offsets(consumer.assignment()))

# 重置偏移量
partition = TopicPartition(topic='testTopicPartition', partition=1)
consumer.assign([partition]) # 必须声明,consumer有两种订阅模式,一种是subscribe即topic粒度、使用group管理,一种是assign即topic-partition粒度、用户自己去管理

for message in consumer:

    # 读取json数据
    # mes = str(message.value, encoding="utf-8")
    # mes_json = json.loads(mes)
    # print(message.partition, message.offset, message.offset, mes_json)

    # 读取普通key-value数据
    print(message.partition, message.offset, message.key, message.value)

 

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值