python kafka收不到消息_uwsgi多进程配合kafka-python消息无法发送

在工作中,使用uwsgi部署项目,其中uwsgi设置为多进程,并且python中使用了kafka-python模块作为生产者不断产生数据,但上线不久后几乎所有的生产者消息都报:KafkaTimeoutError这个错误,并且在kafka服务器中并没有发现收到任何消息。

于是看了看kafka-python源码,发现在执行send方法后,消息并没有立即发送,而是放到本地的缓存中,在生成KafkaProducer实例时,有个选项buffer_memory设置了缓存的大小,默认为32M,然后如果这个buffer满了就会报KafkaTimeoutError,所以初步判断两个原因:

1 生产者消息并没有发送出去,

2 或者消息发送相对于消息生成来说过于缓慢导致

同时又因为看到kafka服务器中并没有接收到任何消息,遂排除第二个原因。也就是说生产者消息没有发送出去。于是采用同样的配置用写了一个脚本发现kafka服务器可以接收到消息,鉴定是我的生产者有问题,遂谷歌解决问题,找到该帖子:https://github.com/dpkp/kafka-python/issues/721。发布人情况和我差不多,作者回复到:You cannot share producer instances across processes, only threads. I expect that is why the master process pattern is failing.

Second, producer.send() is async but is not guaranteed to deliver if you close the producer abruptly. In your final example I suspect that your producer instances are so short-lived that they are being reaped before flushing all pending messages. To guarantee delivery (or exception) call producer.send().get(timeout) or producer.flush() . otherwise you'll need to figure out how to get a producer instance per-uwsgi-thread and have it shared across requests (you would still want to flush before thread shutdown to guarantee no messages are dropped)

大体上说明了两点:

1 多进程共享同一个生产者实例有问题

2 send方法是异步的,当执行完send后立即关闭生产者实例的话可能会导致发送失败。

第二点错误我没有犯,沾沾自喜,继续看评论:Aha, thanks! After looking more closely at uWSGI options I discovered the lazy-apps option, which causes each worker to load the entire app itself. This seems to have resolved my issue.

提问者说他解决了该问题,于是查一查uwsgi中的lazy-apps,发现改文章:https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy,其中说到:默认情况下,uWSGI在第一个进程中加载整个应用,然后在加载完应用之后,会多次 fork() 自己。

我看看了我自己的代码我确实是在app生成之前生成了生产者实例,这就导致该实例被父进程与其子进程共享。问题终于明白,开始解决:

1 使用lazy-apps,这样就可以了。

2 不使用lazy-apps,在代码层面解决问题:

AAffA0nNPuCLAAAAAElFTkSuQmCC# producer.py文件import jsonfrom kafka import KafkaProducerclass Single(object):    """单例模式"""

def __new__(cls, *args, **kwargs):        if not hasattr(cls, "_instance"):

cls._instance = super().__new__(cls)            if hasattr(cls, "initialize"):

cls._instance.initialize(*args, **kwargs)        return cls._instanceclass MsgQueue(Single):    """

这个整成单例模式是因为:uwsgi配合kafka-python在多进程下会有问题,这里希望每个进程单独享有一个kafka producer实例,

也就是说当初始化app对象后,并不会生成producer实例,而是在运行时再生成,

具体参考:https://github.com/dpkp/kafka-python/issues/721    """

app = None    def initialize(self):

self.producer = KafkaProducer(bootstrap_servers=self.app.config["MQ_URI"],

api_version=self.app.config["KAFKA_API_VERSION"])

@classmethod    def init_app(cls, app):

cls.app = app    def send(self, topic, data):        """

:param topic:

:param data:

:return:        """

data = json.dumps(data, ensure_ascii=True)

self.producer.send(topic, data.encode())# app.py文件from producer import MsgQueue

...

MsgQueue.init_app(app)# 业务逻辑中用到生产者的文件from producer import MsgQueue

...

MsgQueue().send(msg)

AAffA0nNPuCLAAAAAElFTkSuQmCC

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kafka 读取不到数据的原因可能有很多,以下是一些常见的可能性: 1. 消息被消费完了:如果你在一个 topic 的所有 partition 中都消费了所有消息,那么 Kafka无法再读取到新的消息。你可以使用 `kafka-console-consumer` 命令行工具检查一下某个 topic 的 partition 中是否还有未消费的消息。 2. 消费者组没有正确配置:如果你的消费者组中有多个消费者,那么每个消费者应该配置不同的 `group.id`,否则它们会共享 partition 中的消息,导致消息重复消费或者某些消息没有被消费。另外,如果你的消费者组中有消费者挂掉了,那么 Kafka 会重新平衡 partition 的分配情况,这时你可能需要等待一段时间才能再次读取到消息。 3. 消费者的 offset 不正确:Kafka 中每个 partition 的消息都有一个 offset,表示消息在 partition 中的位置。消费者需要记录自己在每个 partition 上已经消费的最后一个 offset,这样下次消费的时候就可以从正确的位置开始。如果你的消费者的 offset 不正确,可能会导致消息被重复消费或者某些消息没有被消费。 4. 网络问题:如果你的 Kafka 集群和消费者之间的网络出现问题,可能会导致消费者无法读取到消息。你可以检查一下集群的网络连接情况,或者尝试使用其他消费者来读取同样的消息。 5. 其他问题:还有一些其他的可能性,比如消息过期、数据格式问题等,你可以通过查看 Kafka 的日志或者启用更详细的日志来进一步排查问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值