uwsgi多程式配合kafka-python訊息無法傳送
在工作中,使用uwsgi部署專案,其中uwsgi設定為多程式,並且python中使用了kafka-python模組作為生產者不斷產生資料,但上線不久後幾乎所有的生產者訊息都報:KafkaTimeoutError這個錯誤,並且在kafka伺服器中並沒有發現收到任何訊息。
於是看了看kafka-python原始碼,發現在執行send方法後,訊息並沒有立即傳送,而是放到本地的快取中,在生成KafkaProducer例項時,有個選項buffer_memory設定了快取的大小,預設為32M,然後如果這個buffer滿了就會報KafkaTimeoutError,所以初步判斷兩個原因:
1 生產者訊息並沒有傳送出去,
2 或者訊息傳送相對於訊息生成來說過於緩慢導致
同時又因為看到kafka伺服器中並沒有接收到任何訊息,遂排除第二個原因。也就是說生產者訊息沒有傳送出去。於是採用同樣的配置用寫了一個指令碼發現kafka伺服器可以接收到訊息,鑑定是我的生產者有問題,遂谷歌解決問題,找到該帖子:。釋出人情況和我差不多,作者回復到:
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,發現改文章:,其中說到:
預設情況下,uWSGI在第一個程式中載入整個應用,然後在載入完應用之後,會多次 fork() 自己。
我看看了我自己的程式碼我確實是在app生成之前生成了生產者例項,這就導致該例項被父程式與其子程式共享。問題終於明白,開始解決:
1 使用lazy-apps,這樣就可以了。
2 不使用lazy-apps,在程式碼層面解決問題:
# 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例項,而是在執行時再生成, 具體參考: """ 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)
作者:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1762/viewspace-2822049/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- (完美解決)chatGPT登陸正常卻無法傳送訊息ChatGPT
- 小程式傳送訂閱訊息
- django+小程式傳送模板訊息Django
- RocketMQ(八):訊息傳送MQ
- 【RocketMQ】MQ訊息傳送MQ
- 訊息中介軟體—RocketMQ訊息傳送MQ
- 用程式碼理解 ObjC 中的傳送訊息和訊息轉發OBJ
- TNW-傳送模板訊息TNW
- RocketMQ(九):訊息傳送(續)MQ
- 鴻蒙傳送訊息通知鴻蒙
- 6-RocketMQ傳送訊息MQ
- RocketMQ中Producer訊息的傳送MQ
- Runtime備忘-訊息傳送流程
- Python呼叫飛書傳送訊息Python
- Kafka -- 訊息傳送儲存流程Kafka
- 快速向 Google Chat 傳送訊息Go
- RocketMQ -- 訊息傳送儲存流程MQ
- 傳送不同型別的訊息型別
- 排查MQ訊息傳送和接收MQ
- 微信小程式 傳送模板訊息的功能實現微信小程式
- Android Handler 訊息傳送效能優化Android優化
- 分散式事務:訊息可靠傳送分散式
- 0x2_訊息的傳送
- WIN32傳送自定義訊息Win32
- 以事務方式傳送 Kafka 訊息Kafka
- RocketMQ - 生產者訊息傳送流程MQ
- 傳送kafka訊息的shell指令碼Kafka指令碼
- 千牛自動傳送訊息怎麼發?來試試UiBot千牛訊息傳送機器人UI機器人
- iOS 訊息傳送與轉發詳解iOS
- Laravel 佇列訊息與傳送郵件Laravel佇列
- RocketMQ(6)---傳送普通訊息(三種方式)MQ
- Spring Boot 整合 RabbitMQ 傳送延時訊息Spring BootMQ
- Pulsar訊息傳送、消費架構概述架構
- 一張圖進階 RocketMQ - 訊息傳送MQ
- OCX 控制元件主動傳送訊息給 MFC 視窗訊息控制元件
- 基於 EasyWechat 和 Laravel notification 傳送微信小程式模板訊息Laravel微信小程式
- 在python中使用itchat傳送微信訊息Python
- SpringBoot整合rabbitMq實現訊息延時傳送Spring BootMQ