Kafka 生产消费测试

本文讲述如何利用 Python 先定时向 Kafka 写入数据,再定时从 Kafka 取出数据进行下一步处理(示例写入指定文件),仅供参考学习。

测试过程

  • 第1步,登录服务器(示例 192.168.31.101),先安装 Kafka 3.5.0(过程省略)再创建一个 topic,示例 mytopic
#.删除topic
/data/kafka_9092/bin/kafka-topics.sh --bootstrap-server 192.168.31.101:9092 --delete --topic mytopic

#.创建topic
/data/kafka_9092/bin/kafka-topics.sh --bootstrap-server 192.168.31.101:9092 --create --replication-factor 1 --partitions 3 --topic mytopic

#.查看topic
/data/kafka_9092/bin/kafka-topics.sh --bootstrap-server 192.168.31.101:9092 --describe --topic mytopic
  • 第2步,安装 Python 3.12.3
curl -sL 'http://iso.sqlfans.cn/python/install_python_3123.sh' | bash
python3 --version
  • 第3步,安装 kafka-python

注:未安装 kafka-python 执行 python3 kafka_write.py 会报错 ModuleNotFoundError: No module named 'kafka'

pip3 install kafka-python
  • 第4步,利用 Python 每5秒向 Kafka 写入一条数据,将下面脚本保存为 kafka_write.py
import time
import json
import random
import warnings
from datetime import datetime
from kafka import KafkaProducer
from kafka.errors import KafkaError
warnings.filterwarnings("ignore")

# Kafka配置
KAFKA_BOOTSTRAP_SERVERS = '192.168.31.101:9092'
TOPIC_NAME = 'mytopic'

def create_producer():
    try:
        producer = KafkaProducer(
            bootstrap_servers=KAFKA_BOOTSTRAP_SERVERS,
            value_serializer=lambda v: json.dumps(v).encode('utf-8'),
            key_serializer=lambda v: v.encode('utf-8') if v else None,
            acks='all',
            retries=3,
            max_block_ms=5000
        )
        return producer
    except Exception as e:
        print(f"创建生产者失败: {e}")
        return None

def generate_data():
    return {
        'timestamp': datetime.now().isoformat(),
        'message_id': random.randint(1000, 9999),
        'temperature': round(random.uniform(20.0, 35.0), 2),
        'humidity': round(random.uniform(40.0, 80.0), 2),
        'status': random.choice(['normal', 'warning', 'error']),
        'data': f"sample_data_{random.randint(1, 100)}"
    }

def send_data_kafka(producer, topic, data):
    try:
        future = producer.send(topic, value=data)
        record_metadata = future.get(timeout=10)
        print(f"数据已发送 - 分区: {record_metadata.partition}, "
              f"偏移量: {record_metadata.offset}, "
              f"数据: {data}")
        return True
    except KafkaError as e:
        print(f"Error发送失败: {e}")
        return False
    except Exception as e:
        print(f"Unknown未知错误: {e}")
        return False

def main():
    producer = create_producer()
    if not producer:
        return

    count = 0
    try:
        while True:
            # 等待2秒,发送1条数据
            data = generate_data()
            success = send_data_kafka(producer, TOPIC_NAME, data)
            if success:
                count += 1
            time.sleep(2)

    except KeyboardInterrupt:
        print(f"\n 用户中断程序")
    except Exception as e:
        print(f" 程序异常: {e}")
    finally:
        if producer:
            producer.flush()
            producer.close()
            print(f" 生产者已关闭")
        print(f" 总共发送: {count} 条消息")

if __name__ == "__main__":
    main()
  • 第5步,运行脚本,模拟 Producer(生产者)持续向指定主题(示例 mytopic)发布消息

注:若执行 python3 kafka_write.py 报错 No module named 'kafka',改成python3完整路径即可,如下:

root@localhost:~# /usr/local/python3/bin/python3.12 kafka_write.py
数据已发送 - 分区: 2, 偏移量: 0, 数据: {'timestamp': '2026-07-24T18:15:30.079058', 'message_id': 4744, 'temperature': 29.22, 'humidity': 57.44, 'status': 'normal', 'data': 'sample_data_8'}
数据已发送 - 分区: 1, 偏移量: 0, 数据: {'timestamp': '2026-07-24T18:15:32.201306', 'message_id': 6586, 'temperature': 29.46, 'humidity': 41.33, 'status': 'error', 'data': 'sample_data_99'}
数据已发送 - 分区: 1, 偏移量: 1, 数据: {'timestamp': '2026-07-24T18:15:34.212115', 'message_id': 4128, 'temperature': 31.28, 'humidity': 53.67, 'status': 'error', 'data': 'sample_data_9'}
数据已发送 - 分区: 1, 偏移量: 2, 数据: {'timestamp': '2026-07-24T18:15:36.222534', 'message_id': 5927, 'temperature': 20.61, 'humidity': 69.11, 'status': 'normal', 'data': 'sample_data_83'}
数据已发送 - 分区: 1, 偏移量: 3, 数据: {'timestamp': '2026-07-24T18:15:38.233415', 'message_id': 8883, 'temperature': 34.24, 'humidity': 50.98, 'status': 'error', 'data': 'sample_data_11'}
数据已发送 - 分区: 1, 偏移量: 4, 数据: {'timestamp': '2026-07-24T18:15:40.245118', 'message_id': 6340, 'temperature': 29.93, 'humidity': 66.88, 'status': 'warning', 'data': 'sample_data_69'}
数据已发送 - 分区: 1, 偏移量: 5, 数据: {'timestamp': '2026-07-24T18:15:42.253378', 'message_id': 4797, 'temperature': 33.86, 'humidity': 47.79, 'status': 'warning', 'data': 'sample_data_50'}
数据已发送 - 分区: 2, 偏移量: 1, 数据: {'timestamp': '2026-07-24T18:15:44.262279', 'message_id': 7959, 'temperature': 21.11, 'humidity': 79.54, 'status': 'warning', 'data': 'sample_data_48'}
数据已发送 - 分区: 1, 偏移量: 6, 数据: {'timestamp': '2026-07-24T18:15:46.266677', 'message_id': 1128, 'temperature': 26.53, 'humidity': 68.53, 'status': 'normal', 'data': 'sample_data_30'}
数据已发送 - 分区: 1, 偏移量: 7, 数据: {'timestamp': '2026-07-24T18:15:48.274835', 'message_id': 4690, 'temperature': 28.22, 'humidity': 49.82, 'status': 'error', 'data': 'sample_data_81'}
数据已发送 - 分区: 0, 偏移量: 0, 数据: {'timestamp': '2026-07-24T18:15:50.283559', 'message_id': 4806, 'temperature': 32.27, 'humidity': 50.64, 'status': 'normal', 'data': 'sample_data_55'}
数据已发送 - 分区: 0, 偏移量: 1, 数据: {'timestamp': '2026-07-24T18:15:52.292744', 'message_id': 9001, 'temperature': 30.72, 'humidity': 65.27, 'status': 'warning', 'data': 'sample_data_42'}
数据已发送 - 分区: 0, 偏移量: 2, 数据: {'timestamp': '2026-07-24T18:15:54.301527', 'message_id': 3430, 'temperature': 25.49, 'humidity': 55.03, 'status': 'warning', 'data': 'sample_data_21'}
数据已发送 - 分区: 1, 偏移量: 8, 数据: {'timestamp': '2026-07-24T18:15:56.310459', 'message_id': 3990, 'temperature': 24.78, 'humidity': 71.34, 'status': 'error', 'data': 'sample_data_20'}
  • 第6步,利用 Python 每 1 分钟从 Kafka 消费数据,并按照时间间隔命名保存文件,将下面脚本保存为 kafka_read.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import time
import json
from datetime import datetime
from kafka import KafkaConsumer
from kafka.errors import KafkaError
import warnings
warnings.filterwarnings("ignore")

# Kafka配置
KAFKA_BOOTSTRAP_SERVERS = '192.168.31.101:9092'
TOPIC_NAME = 'mytopic'
CONSUMER_GROUP = 'mygroup'
OUTPUT_DIR = './kafka_data'  # 数据存储目录
INTERVAL_MINUTES = 1         # 时间间隔,单位分钟

class KafkaDataWriter:
    def __init__(self, bootstrap_servers, topic, group_id, output_dir):
        self.bootstrap_servers = bootstrap_servers
        self.topic = topic
        self.group_id = group_id
        self.output_dir = output_dir
        self.consumer = None
        self.interval_start_time = None
        os.makedirs(output_dir, exist_ok=True)
        self.current_file_path = self._get_file_path()
        self.data_buffer = []

    def _get_file_path(self):
        timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
        return os.path.join(self.output_dir, f"data_{timestamp}.json")

    def _flush_buffer(self):
        if not self.data_buffer:
            return
        self.current_file_path = self._get_file_path()
        with open(self.current_file_path, 'w', encoding='utf-8') as f:
            for data in self.data_buffer:
                f.write(json.dumps(data, ensure_ascii=False) + '\n')
        print(f"时间达到: {INTERVAL_MINUTES} 分钟, 数据写入: {self.current_file_path}, 共计: ({len(self.data_buffer)} 条)")
        self.data_buffer = []

    def connect(self):
        self.consumer = KafkaConsumer(
            self.topic,
            bootstrap_servers=self.bootstrap_servers,
            group_id=self.group_id,
            auto_offset_reset='earliest',   # 从最早的消息开始消费
            enable_auto_commit=True,
            auto_commit_interval_ms=5000,   # 每5秒提交一次
            value_deserializer=lambda v: json.loads(v.decode('utf-8')) if v else None,
            key_deserializer=lambda v: v.decode('utf-8') if v else None,
            consumer_timeout_ms=1000
        )
        self.interval_start_time = datetime.now()
        return True

    def consume_messages(self):
        print("\n" + "="*70)
        print(f"成功连接: {self.bootstrap_servers}")
        print(f"订阅主题: {self.topic}")
        print(f"消费者组: {self.group_id}")
        print(f"切换间隔: {INTERVAL_MINUTES} 分钟")
        print(f"注意事项: 开始消费 {self.topic}, 按 Ctrl+C 随时停止")
        print("="*70 + "\n")
        msg_count = 0

        try:
            while True:
                elapsed_minutes = (datetime.now() - self.interval_start_time).total_seconds() / 60.0
                if elapsed_minutes >= INTERVAL_MINUTES:
                    self._flush_buffer()
                    self.interval_start_time = datetime.now()

                for msg in self.consumer:
                    msg_count += 1
                    self.data_buffer.append({
                        'timestamp': datetime.now().isoformat(),
                        'partition': msg.partition,
                        'offset': msg.offset,
                        'key': msg.key,
                        'value': msg.value,
                    })
                    # 每10条消息打印一次状态
                    if msg_count % 10 == 0:
                        print(f"已接收: {msg_count} 条消息, 当前缓冲区: {len(self.data_buffer)} 条")

        except KeyboardInterrupt:
            print("\n用户中断")
        finally:
            self._flush_buffer()
            if self.consumer:
                self.consumer.close()
            print("程序结束")


def main():
    writer = KafkaDataWriter(
        bootstrap_servers=KAFKA_BOOTSTRAP_SERVERS,
        topic=TOPIC_NAME,
        group_id=CONSUMER_GROUP,
        output_dir=OUTPUT_DIR
    )
    writer.connect()
    writer.consume_messages()


if __name__ == "__main__":
    main()
  • 第7步,运行脚本,模拟持续消费指定主题(示例 mytopic)的消息
root@localhost:~# /usr/local/python3/bin/python3.12 kafka_read.py

======================================================================
成功连接: 192.168.31.101:9092
订阅主题: mytopic
消费者组: mygroup
切换间隔: 1 分钟
注意事项: 开始消费 mytopic, 按 Ctrl+C 随时停止
======================================================================

已接收: 10 条消息, 当前缓冲区: 10 条
已接收: 20 条消息, 当前缓冲区: 20 条
已接收: 30 条消息, 当前缓冲区: 30 条
已接收: 40 条消息, 当前缓冲区: 40 条
时间达到: 1 分钟, 数据写入: ./kafka_data/data_2026-07-24_18-20-18.json, 共计: (47 条)
已接收: 50 条消息, 当前缓冲区: 3 条
已接收: 60 条消息, 当前缓冲区: 13 条
已接收: 70 条消息, 当前缓冲区: 23 条
时间达到: 1 分钟, 数据写入: ./kafka_data/data_2026-07-24_18-21-20.json, 共计: (31 条)
已接收: 80 条消息, 当前缓冲区: 2 条
已接收: 90 条消息, 当前缓冲区: 12 条
已接收: 100 条消息, 当前缓冲区: 22 条
  • 第8步,查看特定消费组的延迟
#.查看特定消费组的延迟
root@localhost:~# /data/kafka_9092/bin/kafka-consumer-groups.sh --bootstrap-server 192.168.31.101:9092 --describe --group mygroup

GROUP           TOPIC           PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG             CONSUMER-ID                                             HOST            CLIENT-ID
mygroup         mytopic         0          35              35              0               kafka-python-3.0.8-5c8df861-d85d-402c-80fc-76ab4781aab3 /192.168.31.102 kafka-python-3.0.8
mygroup         mytopic         1          50              50              0               kafka-python-3.0.8-5c8df861-d85d-402c-80fc-76ab4781aab3 /192.168.31.102 kafka-python-3.0.8
mygroup         mytopic         2          51              51              0               kafka-python-3.0.8-5c8df861-d85d-402c-80fc-76ab4781aab3 /192.168.31.102 kafka-python-3.0.8
Copyright © www.sqlfans.cn 2021 - 2026 All Right Reserved更新时间: 2026-07-24 18:23:56

results matching ""

    No results matching ""