You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

搭建MQTT与Kafka桥接时遇pykafka SocketDisconnectedError求助

问题描述

相关环境说明

  • 树莓派4
  • 运行Ubuntu 20.04(ARM64架构)
  • 通过ZeroTier+SSH远程连接
  • 已运行nodered、mosquitto、portainer、zookeeper、Kafka容器

Docker-Compose配置

zookeeper:
  image: ubuntu/zookeeper
  container_name: zookeeper
  ports:
    - "2181:2181"
kafka:
  image: ubuntu/kafka
  container_name: kafka
  ports:
    - "9092:9092"
  environment:
    - KAFKA_ADVERTISED_HOST_NAME=kafka
    - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
    - KAFKA_CREATE_TOPICS= "mqtt-sensor-1:1:1"
    - KAFKA_DELETE_TOPIC_ENABLE=true
  depends_on:
    - zookeeper
  restart: on-failure

现状与问题

MQTT发布订阅功能正常,可用的MQTT发布端代码:

import paho.mqtt.client as mqtt
from random import randrange, uniform
import time
import sys

client= mqtt.Client("GreenForges v1")

if client.connect("localhost",1883,60) !=0:
                print("could not connect to MQTT broker!")
                sys.exit(-1)
while True:
    randNumber = uniform(20.0, 21.0)
    client.publish("mqtt-sensor-1", randNumber)
    print("Just published " + str(randNumber) + " to Topic mqtt-sensor-1")
    time.sleep(10)

尝试用Python+pykafka编写MQTT-Kafka桥接代码时,创建kafka_producer环节持续失败,桥接代码:

import paho.mqtt.client as mqtt
from pykafka import KafkaClient
import time

mqtt_client = mqtt.Client("BridgeMQTT3Kafka")
mqtt_client.connect("localhost",1883,60)

kafka_client = KafkaClient(hosts='localhost:9092')
kafka_topic = kafka_client.topics['mqtt-sensor-1']
kafka_producer = kafka_topic.get_sync_producer()

def on_message(client, userdata, message):
    msg_payload = str(message.payload)
    print("Received MQTT message: ", msg_payload)
    kafka_producer.produce(str(msg_payload).encode('ascii'))
    print("KAFKA: Just published " + str(msg_payload) + " to topic mqtt-sensor-1")

mqtt_client.loop_start()
mqtt_client.subscribe("mqtt-sensor-1")
mqtt_client.on_message = on_message
time.sleep(300)
mqtt_client.loop_end()

报错信息

File "/home/green/.local/lib/python3.10/site-packages/pykafka/broker.py", line 44, in wrapped
    raise SocketDisconnectedError
pykafka.exceptions.SocketDisconnectedError

Kafka日志信息

Controller.log

[2022-09-09 15:45:16,117] INFO [Controller id=0] New partition creation callback for mqtt-sensor-1-0,mqtt-sensor-1-1 (kafka.controller.KafkaController)
[2022-09-09 15:47:59,406] INFO [Controller id=0] Processing automatic preferred replica leader election (kafka.controller.KafkaController)
[2022-09-09 15:47:59,406] TRACE [Controller id=0] Checking need to trigger auto leader balancing (kafka.controller.KafkaController)
[2022-09-09 15:47:59,417] DEBUG [Controller id=0] Topics not in preferred replica for broker 0 Map() (kafka.controller.KafkaController)
[2022-09-09 15:47:59,423] TRACE [Controller id=0] Leader imbalance ratio for broker 0 is 0.0 (kafka.controller.KafkaController)

server.log

[2022-09-09 15:45:16,001] INFO Creating topic mqtt-sensor-1 with configuration {} and initial partition assignment HashMap(0 -> ArrayBuffer(0), 1 -> ArrayBuffer(0)) (kafka.zk.AdminZkClient)
[2022-09-09 15:45:16,344] INFO [ReplicaFetcherManager on broker 0] Removed fetcher for partitions Set(mqtt-sensor-1-1, mqtt-sensor-1-0) (kafka.server.ReplicaFetcherManager)
[2022-09-09 15:45:16,596] INFO [LogLoader partition=mqtt-sensor-1-1, dir=/tmp/kafka-logs] Loading producer state till offset 0 with message format version 2 (kafka.log.UnifiedLog$)
[2022-09-09 15:45:16,649] INFO Created log for partition mqtt-sensor-1-1 in /tmp/kafka-logs/mqtt-sensor-1-1 with properties {} (kafka.log.LogManager)
[2022-09-09 15:45:16,658] INFO [Partition mqtt-sensor-1-1 broker=0] No checkpointed highwatermark is found for partition mqtt-sensor-1-1 (kafka.cluster.Partition) 
[2022-09-09 15:45:16,662] INFO [Partition mqtt-sensor-1-1 broker=0] Log loaded for partition mqtt-sensor-1-1 with initial high watermark 0 (kafka.cluster.Partition)
[2022-09-09 15:45:16,722] INFO [LogLoader partition=mqtt-sensor-1-0, dir=/tmp/kafka-logs] Loading producer state till offset 0 with message format version 2 (kafka.log.UnifiedLog$)
[2022-09-09 15:45:16,731] INFO Created log for partition mqtt-sensor-1-0 in /tmp/kafka-logs/mqtt-sensor-1-0 with properties {} (kafka.log.LogManager)
[2022-09-09 15:45:16,732] INFO [Partition mqtt-sensor-1-0 broker=0] No checkpointed highwatermark is found for partition mqtt-sensor-1-0 (kafka.cluster.Partition) 
[2022-09-09 15:45:16,734] INFO [Partition mqtt-sensor-1-0 broker=0] Log loaded for partition mqtt-sensor-1-0 with initial high watermark 0 (kafka.cluster.Partition)

进一步排查结果

  • 执行./bin/zookeeper-shell.sh localhost:2181 ls /brokers/ids返回连接拒绝:
Connecting to localhost:2181
[2022-09-09 16:18:36,326] WARN Session 0x0 for sever localhost/127.0.0.1:2181, Closing socket connection. Attempting reconnect except it is a SessionExpiredException. (org.apache.zookeeper.ClientCnxn)
java.net.ConnectException: Connection refused
        at java.base/sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:777)
        at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:344)
        at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1290)
KeeperErrorCode = ConnectionLoss for /brokers/ids
[2022-09-09 16:18:36,482] ERROR Exiting JVM with code 1 (org.apache.zookeeper.util.ServiceUtils)
  • 执行./bin/zookeeper-shell.sh localhost:9092 ls /brokers/ids返回会话超时:
Connecting to localhost:9092
[2022-09-09 16:19:44,858] WARN Client session timed out, have not heard from server in 30006ms for session id 0x0 (org.apache.zookeeper.ClientCnxn)
[2022-09-09 16:19:44,867] WARN Session 0x0 for sever localhost/127.0.0.1:9092, Closing socket connection. Attempting reconnect except it is a SessionExpiredException. (org.apache.zookeeper.ClientCnxn)
org.apache.zookeeper.ClientCnxn$SessionTimeoutException: Client session timed out, have not heard from server in 30006ms for session id 0x0
        at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1258)
KeeperErrorCode = ConnectionLoss for /brokers/ids
[2022-09-09 16:19:45,018] ERROR Exiting JVM with code 1 (org.apache.zookeeper.util.ServiceUtils)
  • Kafka命令行工具生产消费正常:
bin/kafka-console-consumer.sh --topic mqtt-sensor-1 --from-beginning --bootstrap-server localhost:9092
bin/kafka-console-producer.sh --topic mqtt-sensor-1 --bootstrap-server localhost:9092
解决方向

1. 调整Kafka的广告地址配置

当前Docker-Compose中KAFKA_ADVERTISED_HOST_NAME=kafka是容器内部主机名,宿主机(运行Python代码的环境)无法解析该名称。pykafka会从Kafka broker获取其广告地址,尝试连接时会因无法解析导致失败。

修改Docker-Compose中Kafka的环境变量:

environment:
  - KAFKA_ADVERTISED_HOST_NAME=localhost  # 替换为树莓派本地IP或localhost,确保宿主机可访问
  - KAFKA_ADVERTISED_PORT=9092
  - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
  - KAFKA_CREATE_TOPICS="mqtt-sensor-1:1:1"
  - KAFKA_DELETE_TOPIC_ENABLE=true

修改后重启Kafka容器:docker-compose restart kafka

2. 强制pykafka使用指定的Broker地址

若不想修改Kafka配置,可在创建KafkaClient时指定broker_version参数,强制使用传入的hosts地址,避免从Broker获取广告地址:

kafka_client = KafkaClient(hosts='localhost:9092', broker_version='2.8.0')  # 替换为你的Kafka实际版本

注意:pykafka维护活跃度低,对新版本Kafka兼容性有限,需确保版本匹配。

3. 检查容器网络连通性

确认宿主机能正常访问Kafka容器的9092端口:

nc -zv localhost 9092

若不通,检查Docker端口映射及容器运行状态:

docker ps | grep kafka

4. 替换pykafka为confluent-kafka

pykafka对新版本Kafka支持不足,改用维护更活跃的confluent-kafka库,示例代码:

import paho.mqtt.client as mqtt
from confluent_kafka import Producer
import time

# Kafka Producer配置
conf = {'bootstrap.servers': 'localhost:9092'}
kafka_producer = Producer(conf)

def delivery_report(err, msg):
    if err is not None:
        print(f'Message delivery failed: {err}')
    else:
        print(f'Message delivered to {msg.topic()} [{msg.partition()}]')

def on_message(client, userdata, message):
    msg_payload = message.payload.decode('utf-8')
    print("Received MQTT message: ", msg_payload)
    kafka_producer.produce('mqtt-sensor-1', value=msg_payload.encode('ascii'), callback=delivery_report)
    kafka_producer.poll(0)
    print("KAFKA: Just published " + msg_payload + " to topic mqtt-sensor-1")

# MQTT客户端配置
mqtt_client = mqtt.Client("BridgeMQTT3Kafka")
mqtt_client.connect("localhost", 1883, 60)
mqtt_client.subscribe("mqtt-sensor-1")
mqtt_client.on_message = on_message

mqtt_client.loop_start()
time.sleep(300)
mqtt_client.loop_end()

内容的提问来源于stack exchange,提问作者fneron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 06:51:17