【消息中间件】基于Kafka的消息中间件封装组件
基于Kafka的消息中间件组件封装,老样子直接上代码:
import json
import threading
import uuid
from typing import Union
try:
from kafka import KafkaConsumer
from kafka import KafkaProducer
except:
import os
os.system(' pip install -i https://pypi.tuna.tsinghua.edu.cn/simple kafka-python ')
from kafka import KafkaConsumer
from kafka import KafkaProducer
class KafkaMQ():
producer = None # 生产者
consumer = None # 消费者
consumer_channel = None # 订阅的频道
def __init__(self,
nodes: Union[list, str],
topics=None,
group_id=None,
username=None,
pwd=None,
security_protocol='PLAINTEXT',
create_producter=True
):
"""
:param nodes:kafka集群节点地址可以是列表或者逗号分隔字符。集群地址必须是:ip:port组成。
:param topics:消息主题,可以是列表或者逗号分隔字符,可以在创建对象后分配。
:param group_id:多个拥有相同group_id的消费者被判定为一组,一条数据记录只会被同一个组中的一个消费者消费。一般不设置!
:param client_id:客户端id,默认时随机编号
:param username:用户名
:param pwd:密码
:param create_producter:默认创建生产者
"""
if topics is None:
self.consumer_channel = []
else:
self.consumer_channel = topics
self.nodes = nodes
self.group_id = group_id
self.client_id = f'{uuid.uuid4()}'
self.security_protocol = security_protocol
# 生产者
if create_producter:
self._setPorducter(username=username, pwd=pwd)
# 消费者
self._setConsumer(topics=self.consumer_channel, username=username, pwd=pwd)
# 创建消费者
def _setConsumer(self, topics=None, username=None, pwd=None):
self.consumer = KafkaConsumer(
*topics,
bootstrap_servers=self.nodes, # kafka集群地址
# group_id=self.group_id, # 消费组id
client_id=self.client_id, # 客户端id
enable_auto_commit=True, # 每过一段时间自动提交所有已消费的消息(在迭代时提交)
auto_commit_interval_ms=5000, # 自动提交的周期(毫秒)
sasl_mechanism='PLAIN',
security_protocol=self.security_protocol,
sasl_plain_username=username,
sasl_plain_password=pwd,
# api_version=(0,10)
)
def _setPorducter(self, username=None, pwd=None):
self.producer = KafkaProducer(
value_serializer=lambda v: json.dumps(v).encode('utf-8'),
bootstrap_servers=self.nodes, # kafka集群地址
sasl_mechanism='PLAIN',
security_protocol=self.security_protocol,
sasl_plain_username=username,
sasl_plain_password=pwd,
# api_version=(0,10)
)
def publish(self, channel, message):
'''发送消息,指定频道'''
future = self.producer.send(channel, message)
try:
future.get(timeout=10)
return True, ''
except Exception as e:
# print(str(e))
return False, str(e)
# 连接对象全局存在,不用关闭
# self.producer.close()
def subscribe(self, topic):
'''订阅单个频道'''
self.consumer.subscribe(topic)
def psubscribe(self, topics: list):
'''订阅多个频道'''
self.consumer.subscribe(topics)
def unsubscribe(self):
'''取消订阅所有主题'''
self.consumer.unsubscribe()
def continue_psubscribe(self, topics=[]):
'''持续监听多个频道,返回解析数据'''
if topics:
self.psubscribe(topics)
while True:
# for msg in self.consumer:
msg = next(self.consumer)
t,m = msg.topic, msg.value.decode()
return t,m
def close(self):
self.consumer.close(autocommit=True)
self.producer.close()
# def _parse_recv_data(self,res):
# '''数据解析'''
# # print("接收到的数据:", res)
# try:
# channel = res.topic
# data = res.value
#
# print('')
# print('频道:', channel)
# print('数据:', data)
# return data
# except:
# print(f'【警告】收到无法解析的异常数据!!\nres:'
# + json.dumps(res, indent=4, ensure_ascii=False)
# )
# return False
def recv_command(self,obj,TOPIC,handler) -> None:
'''接收指令'''
if TOPIC:
self.psubscribe(TOPIC)
while True:
# for msg in self.consumer:
msg = next(self.consumer)
t,m = msg.topic, msg.value.decode()
print(t,m)
handler(obj,m)
def listen(self,obj,TOPIC_handler:dict) -> bool:
try:
for TOPIC,handler in TOPIC_handler.items():
print(f'【监听】频道:{TOPIC},消息监听程序启动!')
t3 = threading.Thread(target=self.recv_command,args=(obj,TOPIC,handler)) # 单次消费
t3.start()
return True
except Exception as e:
print(e)
return False
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统