kafka+python安装及使用教程

kafka+python安装及使用教程

前几天学习kafka,从网上搜索了很多教程发现写的都比较肤浅,真正生产环境下是无法使用的,因为会有故障的情况。经过各种摸索以及查阅官方文档,总结了下面这一套教程,最大的改进是使用手动commit消费结果,并且写了一个直观的demo用于理解kafka offset,希望能帮助大家节省学习时间。有问题的话可以留言,题主看到会尽量回复。

安装kafka

使用docker部署kafka 3.4版本,最新版的kafka已经不需要zookeeper作为依赖
当然官方也保留了zookeeper的支持,具体部署方法可以查看https://hub.docker.com/r/bitnami/kafka。
为了开发方便,我们直接用一个kafka镜像即可。

创建文件docker-compose.yml:

version: "2"

services:
  broker:
    container_name: broker
    image: docker.io/bitnami/kafka:3.4
    ports:
      - "9092:9092"
    volumes:
      - "kafka_data:/bitnami"
    environment:
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092        # 使用者要用localhost为名才能访问
      - KAFKA_BROKER_ID=1
      - KAFKA_CFG_log_retention_hours=1     # KAFKA_CFG_  +  kafka 配置参数,无需映射配置文件


volumes:
  kafka_data:
    driver: local

注意 KAFKA_CFG_log_retention_hours=1 配置了一个小时前的数据都会清除,可以自己设置大一些的数字

其他配置参数都可以写成KAFKA_CFG_ + kafka配置的形式,会自动覆盖默认参数

启动:

docker compose up -d

python代码

首先安装官方维护的库

pip install confluent-kafka

kafka管理者脚本

kafka_admin.py

from confluent_kafka.admin import AdminClient
from confluent_kafka.admin import NewTopic,NewPartitions
from confluent_kafka.admin._metadata import ClusterMetadata

admin = AdminClient({'bootstrap.servers':'localhost:9092'})


# 创建一个topic
print(admin.create_topics(new_topics=[NewTopic('purchases',-1)]))

# 删除一个topic
# print(admin.delete_topics(topics=['new-topic']))

# 列出所有的topic
topics:ClusterMetadata = admin.list_topics()
print(topics.topics)       # 默认有一个__consumer_offsets ,用前缀过滤掉

print(admin.list_consumer_groups())

# admin.create_partitions(NewPartitions(topic='purchases',new_total_count=3))  # new_total_count 新增分片的数量到这个数,而不是新增的数量


生产者

producer.py

#!/usr/bin/env python

import sys
from random import choice
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Producer

if __name__ == '__main__':
 
    config = {'bootstrap.servers': 'localhost:9092'}
    producer = Producer(config)
    # Optional per-message delivery callback (triggered by poll() or flush())
    # when a message has been successfully delivered or permanently
    # failed delivery (after retries).
    def delivery_callback(err, msg):
        if err:
            print('ERROR: Message failed delivery: {}'.format(err))
        else:
            print("Produced event to topic {topic}: key = {key:12} value = {value:12}".format(
                topic=msg.topic(), key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))

    # Produce data by selecting random values from these lists.
    topic = "purchases"
    user_ids = ['eabara', 'jsmith', 'sgarcia', 'jbernard', 'htanaka', 'awalther']
    products = ['book', 'alarm clock', 't-shirts', 'gift card', 'batteries']

    count = 0
    for _ in range(10):
        user_id = choice(user_ids)
        product = choice(products)
        producer.produce(topic, product, user_id, callback=delivery_callback)
        count += 1

    print(len(producer))        # 查询当前有多少个等待传送给kafka的消息
    # 直到消息发送成功
    producer.poll(10000)      # 向kafka推送消息
    print(len(producer))    # 这里应该是0
    producer.flush()

创建消费者

consumer.py

#!/usr/bin/env python

import sys
from argparse import ArgumentParser, FileType
from configparser import ConfigParser
from confluent_kafka import Consumer, OFFSET_BEGINNING, TopicPartition, Message

def do_consume(msg,consumer):
    if msg.error():
        print("ERROR: %s".format(msg.error()))
    else:
		'''在这里消费你的数据'''
        print("消费到一条数据 from topic {topic}: key = {key:12} value = {value:12}".format(
            topic=msg.topic(), key=msg.key().decode('utf-8'), value=msg.value().decode('utf-8')))
        # print('当前的offset',consumer.position([TopicPartition(topic1,0)]))   # 获取消费者临时的offset(理解为缓存)
        # print('before commit offset',consumer.committed([TopicPartition(topic1,0)]))    # 获取kafka中的offset

        '''消费成功'''
        consumer.commit(msg,asynchronous=False)         # offset+1
        print('after commit offset',consumer.committed([TopicPartition(topic1,0)]))    # 获取kafka中的offset


def poll(consumer):
    # Poll for new messages from Kafka and print them.
    try:
        while True:
            msg:Message = consumer.poll(1.0)         # 消费一个单消息
            if msg is None:
                # Initial message consumption may take up to
                # `session.timeout.ms` for the consumer group to
                # rebalance and start consuming
                print("Waiting...")
            else:
                do_consume(msg,consumer)
    except KeyboardInterrupt:
        pass
    finally:
        # Leave group and commit final offsets
        consumer.close()

if __name__ == '__main__':
	consume_from_init = False    # 修改为True时,无视已消费的数据,从队头开始消费。否则从最后一个未消费的数据开始
   	config = {
        'bootstrap.servers': 'localhost:9092',   # 由于docker中的设置,这里必须是localhost
        'group.id': 'python_example_group_1', 
        'auto.offset.reset': 'earliest', 
        'enable.auto.commit': 'false'    # 关闭自动提交
    }
    consumer = Consumer(config)

    def reset_offset(consumer, partitions):
        if consume_from_init:
            for p in partitions:
                p.offset = OFFSET_BEGINNING
            consumer.assign(partitions)

    # Subscribe to topic
    topic1 = "purchases"
    topic2 = 'new-topic'
    consumer.subscribe([topic1,topic2], on_assign=reset_offset)

    # 获取当前高低水位,高水位代表当前队列里未消费消息数+offset+1 ,可以理解为队列最大长度
    low,high = consumer.get_watermark_offsets(TopicPartition(topic1,0))     # topic,partition index
    print(low,high)

    # 获取当前的offset
    broker_offset = consumer.committed([TopicPartition(topic1,0)])
    print('当前的offset',broker_offset[0].offset)    # 获取kafka中的offset

    current_wait_message = high - broker_offset[0].offset         # 当前队列中已入队,未消费的消息数

    print('当前队列中未消费消息数:',current_wait_message)

    poll(consumer)

注意我们需要在配置中将自动提交关闭:’enable.auto.commit’: ‘false’ ,这样才能实现未成功重复消费

注意这一行current_wait_message = high - broker_offset[0].offset ,我们首先获取到队列的高水位high,也就是队尾的offset,然后获取了当前的指针位置broker_offset[0].offset ,然后相减,就获得的当前未消费的数据量。这个current_wait_message 可以用于限流(>1000时拒收),故障判断(长时间>1000说明负载不够了)等应用。

使用

  • 运行python admin.py使用管理者脚本创建一个topic purchases,并可以自定义设置分片
  • 执行python consumer.py打开生产者,如果队列中有数据,会打印到控制台
  • 执行一次python producer.py,会向kafka推送十条数据,然后消费者就会收到对应的数据并打印出来。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

brandon_l

如果有用还请打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值