Python消息队列:Celery + Redis RabbitMQ Apache Kafka

消息队列对比

特性 Celery + Redis RabbitMQ Apache Kafka

消息模型 任务队列 消息代理 事件流平台

持久化 可选 支持 强持久化

消息顺序 不保证 队列内保证 分区内保证

吞吐量 中等 中等 非常高

延迟 低 低 低到中等

适用场景 异步任务、定时任务 应用解耦、复杂路由 事件流、数据管道

复杂度 低 中等 高

数据重放 不支持 有限支持 完整支持

生态系统 Python生态 多语言支持 完整流生态

业务场景:电商订单处理系统

消息队列需求:

  • 订单创建后的异步处理(库存扣减、积分计算、通知发送)
  • 支付结果异步通知
  • 物流状态更新
  • 用户行为追踪
  • 数据同步和ETL处理
  • 延迟任务(订单超时取消)

Celery + Redis 实现

text 复制代码
celery_redis_project/
├── app.py
├── config.py
├── tasks/
│   ├── __init__.py
│   ├── order_tasks.py
│   ├── payment_tasks.py
│   ├── notification_tasks.py
│   └── user_tasks.py
├── models/
│   └── order.py
├── workers/
│   ├── __init__.py
│   ├── order_worker.py
│   └── notification_worker.py
└── requirements.txt

config.py

python 复制代码
import os
from datetime import timedelta

class Config:
	REDIS_URL = os.getenv("REDIS_URL","redis://localhost:6379/0")

	#Celery配置
	CELERY_BROKER_URL = REDIS_URL
	CELERY_RESULT_BACKEND = REDIS_URL
    CELERY_TIMEZONE = "Asia/Shanghai"
    CELERY_ENABLE_UTC = True
    
    # 任务路由
    CELERY_TASK_ROUTES = {
        'tasks.order_tasks.*': {'queue': 'orders'},
        'tasks.payment_tasks.*': {'queue': 'payments'},
        'tasks.notification_tasks.*': {'queue': 'notifications'},
        'tasks.user_tasks.*': {'queue': 'users'},
    }
    
    # 定时任务
    CELERY_BEAT_SCHEDULE = {
        'check-order-timeout': {
            'task': 'tasks.order_tasks.check_order_timeout',
            'schedule': timedelta(minutes=1),  # 每分钟检查一次
        },
        'clean-expired-carts': {
            'task': 'tasks.order_tasks.clean_expired_carts',
            'schedule': timedelta(hours=1),  # 每小时清理一次
        },
        'send-daily-stats': {
            'task': 'tasks.notification_tasks.send_daily_stats',
            'schedule': timedelta(days=1),  # 每天发送统计
        },
    }
    
    # 并发配置
    CELERY_WORKER_CONCURRENCY = 4
    CELERY_WORKER_PREFETCH_MULTIPLIER = 1
    CELERY_TASK_ACKS_LATE = True  # 任务执行完成后确认
    CELERY_TASK_REJECT_ON_WORKER_LOST = True
    
    # 重试配置
    CELERY_TASK_DEFAULT_RETRY_DELAY = 30  # 30秒后重试
    CELERY_TASK_MAX_RETRIES = 3

config = Config()
	

app.py

python 复制代码
from celery import Celery
from config import Config

def create_celery_app():
	"""创建Celery应用"""
	app = Celery('ecommerce')

	#配置Celery
	app.config_from_objecct(Config)

	#自动发现任务
	app.autodiscover_tasks([
        'tasks.order_tasks',
        'tasks.payment_tasks', 
        'tasks.notification_tasks',
        'tasks.user_tasks'
    ])
    return app

#创建全局Celery实例
celery_app = create_celery_app()

if __name__ == '__main__':
	celery_app.start()

tasks/order_tasks.py

python 复制代码
import time
import logging
from datetime import datetime,timedelta
from celery.exceptions import MaxRetriesExceededError
from app import celery_app
from models.order import Order,OrderItem,Inventory

logger = logging.getLogger(__name__)

@celery_app.task(bind=True, max_retries=3, default_retry_delay=30)
def process_order_creation(self, order_id):
	"""
	处理订单创建后的异步任务
    - 库存扣减
    - 积分计算
    - 订单状态更新
    """
    try:
    	logger.info(f"开始处理订单 {order_id}")

		#模拟获取订单数据
		order = get_order_by_id(order_id)
		if not order:
			logger.error(f"订单 {order_id} 不存在")
			return False
		
		# 1.扣减库存
		if not debuct_inventory():
			logger.error(f"订单 {order_id} 库存扣减失败")
			raise Exception("库存扣减失败")

		# 2.计算积分
		calculate_points.delay(order_id,order['user_id'],order['total_amount'])

		# 3.发送订单创建通知
		send_order_created_notification.delay(order_id,order['user_id'])

		# 4.更新订单状态为确认
		update_order_status(order_id,'confirmed')

		logger.info(f"订单 {order_id} 处理完成")
		return True

	except Exception as exc:
		logger.error(f"订单处理失败: {exc}")
		try:
			#重试任务
			raise self.retry(exc=exc,countdown=60)
		except MaxRetiresExceededError:
			#重试次数用尽,标记订单为失败
			update_order_status(order_id,'failed')
			logger.error(f"订单 {order_id} 处理失败,已达到最大重试次数")
			return False
			
@celery_app.task(bind=True)
def deduct_inventory(self, order):
    """扣减库存"""
    try:
    	for item in order['items']]:
    		#遍历每个订单条目
    		product_id = item['product_id']
    		quantity = item['quantity']

			#模拟库存扣减
			logger.info(f"扣减商品 {product_id} 库存 {quantity}")
            time.sleep(0.1)  # 模拟数据库操作

			# 这里应该是实际的库存扣减逻辑
            # inventory = Inventory.get(product_id=product_id)
            # if inventory.quantity < quantity:
            #     raise Exception(f"商品 {product_id} 库存不足")
            # inventory.quantity -= quantity
            # inventory.save()
        
        return True
    except Exception as exc:
    	logger.error(f"库存扣减失败: {exc}")
    	raise exc	

@celery_app.task
def calculate_points(order_id, user_id, amount):
    """计算用户积分"""
    try:
        points = int(amount)  # 1元=1积分
        logger.info(f"为用户 {user_id} 计算积分 {points}")
        
        # 模拟积分计算
        time.sleep(0.2)
        
        # 这里应该是实际的积分计算逻辑
        # user = User.get(user_id)
        # user.points += points
        # user.save()
        
        # 发送积分变动通知
        send_points_notification.delay(user_id, points, 'order_created')
        
        return True
    except Exception as exc:
        logger.error(f"积分计算失败: {exc}")
        return False

@celery_app.task(bind=True, max_retries=5)
def check_order_timeout(self):
    """检查超时未支付订单"""
    try:
        logger.info("开始检查超时订单")
        
        # 获取超时订单(创建时间超过30分钟未支付)
        timeout_threshold = datetime.now() - timedelta(minutes=30)
        # timeout_orders = Order.query.filter(
        #     Order.status == 'pending',
        #     Order.created_at < timeout_threshold
        # ).all()
        
        # 模拟超时订单
        timeout_orders = [1, 2, 3]  # 模拟订单ID
        
        for order_id in timeout_orders:
            cancel_unpaid_order.delay(order_id)
        
        logger.info(f"找到 {len(timeout_orders)} 个超时订单")
        return len(timeout_orders)
        
    except Exception as exc:
        logger.error(f"检查超时订单失败: {exc}")
        raise self.retry(exc=exc)

@celery_app.task
def cancel_unpaid_order(order_id):
    """取消未支付订单"""
    try:
        logger.info(f"取消未支付订单 {order_id}")
        
        # 1. 恢复库存
        # order = Order.get(order_id)
        # for item in order.items:
        #     inventory = Inventory.get(product_id=item.product_id)
        #     inventory.quantity += item.quantity
        #     inventory.save()
        
        # 2. 更新订单状态
        # order.status = 'cancelled'
        # order.cancelled_at = datetime.now()
        # order.save()
        
        # 3. 发送取消通知
        send_order_cancelled_notification.delay(order_id)
        
        logger.info(f"订单 {order_id} 已取消")
        return True
        
    except Exception as exc:
        logger.error(f"取消订单失败: {exc}")
        return False

@celery_app.task
def clean_expired_carts():
    """清理过期购物车"""
    try:
        logger.info("开始清理过期购物车")
        
        # 清理24小时未更新的购物车
        # expired_time = datetime.now() - timedelta(hours=24)
        # expired_carts = Cart.query.filter(
        #     Cart.updated_at < expired_time
        # ).delete()
        
        expired_carts = 10  # 模拟清理数量
        logger.info(f"清理了 {expired_carts} 个过期购物车")
        return expired_carts
        
    except Exception as exc:
        logger.error(f"清理购物车失败: {exc}")
        return 0

# 模拟函数
def get_order_by_id(order_id):
    """模拟获取订单"""
    return {
        'id': order_id,
        'user_id': 1,
        'total_amount': 199.99,
        'status': 'pending',
        'items': [
            {'product_id': 1, 'quantity': 2, 'price': 99.99},
            {'product_id': 2, 'quantity': 1, 'price': 50.00}
        ]
    }

def update_order_status(order_id, status):
    """模拟更新订单状态"""
    logger.info(f"更新订单 {order_id} 状态为 {status}")
    return True		

tasks/payment_tasks.py

python 复制代码
import logging
from datetime import datetime
from app import celery_app

logger = logging.getLogger(__name__)

@celery_app.task(bind=True,max_retries=3)
def process_payment_callback(self, payment_id, status, amount):
	"""处理支付回调"""
	try:
		logger.info(f"处理支付回调: {payment_id}, 状态: {status}, 金额: {amount}")
        
        # 1. 更新支付状态
        update_payment_status(payment_id, status)
        
        if status == 'success':
            # 支付成功处理
            handle_successful_payment.delay(payment_id)
        elif status == 'failed':
            # 支付失败处理
            handle_failed_payment.delay(payment_id)
        elif status == 'refunded':
            # 退款处理
            handle_refund.delay(payment_id)
        
        return True
	except Exception as exc:
		logger.error(f"支付回调处理失败: {exc}")
        raise self.retry(exc=exc)

@celery_app.task
def handle_successful_payment(payment_id):
    """处理成功支付"""
	try:
        logger.info(f"处理成功支付: {payment_id}")
        
        # 1. 获取关联订单
        order_id = get_order_by_payment(payment_id)
        
        # 2. 更新订单状态为已支付
        update_order_status(order_id, 'paid')
        update_order_paid_time(order_id, datetime.now())
        
        # 3. 触发后续流程
        from .order_tasks import process_order_creation
        process_order_creation.delay(order_id)
        
        # 4. 发送支付成功通知
        from .notification_tasks import send_payment_success_notification
        send_payment_success_notification.delay(payment_id, order_id)
        
        logger.info(f"支付 {payment_id} 处理完成")
        return True
        
    except Exception as exc:
        logger.error(f"成功支付处理失败: {exc}")
        return False
@celery_app.task
def handle_failed_payment(payment_id):
    """处理失败支付"""
    try:
        logger.info(f"处理失败支付: {payment_id}")
        
        # 1. 获取关联订单
        order_id = get_order_by_payment(payment_id)
        
        # 2. 更新订单状态
        update_order_status(order_id, 'payment_failed')
        
        # 3. 发送支付失败通知
        from .notification_tasks import send_payment_failed_notification
        send_payment_failed_notification.delay(payment_id, order_id)
        
        logger.info(f"失败支付 {payment_id} 处理完成")
        return True
        
    except Exception as exc:
        logger.error(f"失败支付处理失败: {exc}")
        return False

@celery_app.task
def handle_refund(payment_id):
    """处理退款"""
    try:
        logger.info(f"处理退款: {payment_id}")
        
        # 1. 获取退款详情
        refund_amount = get_refund_amount(payment_id)
        
        # 2. 执行退款逻辑
        execute_refund(payment_id, refund_amount)
        
        # 3. 更新相关状态
        update_refund_status(payment_id, 'completed')
        
        # 4. 发送退款通知
        from .notification_tasks import send_refund_notification
        send_refund_notification.delay(payment_id, refund_amount)
        
        logger.info(f"退款 {payment_id} 处理完成")
        return True
        
    except Exception as exc:
        logger.error(f"退款处理失败: {exc}")
        return False

# 模拟函数
def update_payment_status(payment_id, status):
    logger.info(f"更新支付 {payment_id} 状态为 {status}")
    return True

def get_order_by_payment(payment_id):
    return 1  # 模拟订单ID

def update_order_paid_time(order_id, paid_time):
    logger.info(f"更新订单 {order_id} 支付时间为 {paid_time}")
    return True

def get_refund_amount(payment_id):
    return 100.0  # 模拟退款金额

def execute_refund(payment_id, amount):
    logger.info(f"执行退款: {payment_id}, 金额: {amount}")
    return True

def update_refund_status(payment_id, status):
    logger.info(f"更新退款状态: {payment_id} -> {status}")
    return True

tasks/notification_tasks.py

python 复制代码
import time
import logging
from datetime import datetime
from app import celery_app

logger = logging.getLogger(__name__)

@celery_app.task(bind=True, max_retries=3)
def send_order_created_notification(self, order_id, user_id):
    """发送订单创建通知"""
    try:
        logger.info(f"发送订单创建通知: 订单 {order_id}, 用户 {user_id}")
        
        # 1. 准备通知数据
        order_data = get_order_data(order_id)
        user_data = get_user_data(user_id)
        
        # 2. 发送邮件
        if user_data.get('email'):
            send_email.delay(
                to_email=user_data['email'],
                subject="订单创建成功",
                template="order_created",
                data={'order': order_data, 'user': user_data}
            )
        
        # 3. 发送短信
        if user_data.get('phone'):
            send_sms.delay(
                to_phone=user_data['phone'],
                template="order_created",
                data={'order': order_data}
            )
        
        # 4. 发送App推送
        send_app_push.delay(
            user_id=user_id,
            title="订单创建成功",
            content=f"您的订单 {order_id} 已创建",
            data={'order_id': order_id}
        )
        
        logger.info(f"订单创建通知发送完成: {order_id}")
        return True
        
    except Exception as exc:
        logger.error(f"订单创建通知发送失败: {exc}")
        raise self.retry(exc=exc)

@celery_app.task
def send_payment_success_notification(payment_id, order_id):
    """发送支付成功通知"""
    logger.info(f"发送支付成功通知: {payment_id}, 订单 {order_id}")
    
    # 模拟发送通知
    time.sleep(0.1)
    return True

@celery_app.task
def send_payment_failed_notification(payment_id, order_id):
    """发送支付失败通知"""
    logger.info(f"发送支付失败通知: {payment_id}, 订单 {order_id}")
    
    # 模拟发送通知
    time.sleep(0.1)
    return True

@celery_app.task
def send_order_cancelled_notification(order_id):
    """发送订单取消通知"""
    logger.info(f"发送订单取消通知: {order_id}")
    
    # 模拟发送通知
    time.sleep(0.1)
    return True

@celery_app.task
def send_refund_notification(payment_id, amount):
    """发送退款通知"""
    logger.info(f"发送退款通知: {payment_id}, 金额 {amount}")
    
    # 模拟发送通知
    time.sleep(0.1)
    return True

@celery_app.task
def send_points_notification(user_id, points, reason):
    """发送积分变动通知"""
    logger.info(f"发送积分通知: 用户 {user_id}, 积分 {points}, 原因 {reason}")
    
    # 模拟发送通知
    time.sleep(0.1)
    return True

@celery_app.task
def send_daily_stats():
    """发送每日统计"""
    try:
        logger.info("发送每日统计")
        
        # 1. 生成统计报告
        stats = generate_daily_stats()
        
        # 2. 发送给管理员
        send_email.delay(
            to_email="admin@example.com",
            subject="每日统计报告",
            template="daily_stats",
            data={'stats': stats}
        )
        
        logger.info("每日统计发送完成")
        return True
        
    except Exception as exc:
        logger.error(f"每日统计发送失败: {exc}")
        return False

@celery_app.task
def send_email(to_email, subject, template, data):
    """发送邮件任务"""
    logger.info(f"发送邮件到 {to_email}: {subject}")
    time.sleep(0.2)  # 模拟邮件发送
    return True

@celery_app.task
def send_sms(to_phone, template, data):
    """发送短信任务"""
    logger.info(f"发送短信到 {to_phone}")
    time.sleep(0.1)  # 模拟短信发送
    return True

@celery_app.task
def send_app_push(user_id, title, content, data):
    """发送App推送"""
    logger.info(f"发送App推送给用户 {user_id}: {title}")
    time.sleep(0.1)  # 模拟推送发送
    return True

# 模拟函数
def get_order_data(order_id):
    return {'id': order_id, 'total_amount': 199.99}

def get_user_data(user_id):
    return {'id': user_id, 'email': 'user@example.com', 'phone': '13800138000'}

def generate_daily_stats():
    return {
        'date': datetime.now().strftime('%Y-%m-%d'),
        'new_orders': 150,
        'total_revenue': 29985.50,
        'active_users': 1200
    }

tasks/user_tasks.py

python 复制代码
# tasks/user_tasks.py
import time
import logging
from datetime import datetime, timedelta
from app import celery_app

logger = logging.getLogger(__name__)

@celery_app.task
def track_user_behavior(user_id, action, data):
    """追踪用户行为"""
    try:
        logger.info(f"追踪用户行为: 用户 {user_id}, 动作 {action}")
        
        # 1. 记录到分析系统
        record_user_analytics(user_id, action, data)
        
        # 2. 更新用户画像
        update_user_profile(user_id, action, data)
        
        # 3. 检查是否触发营销活动
        check_marketing_campaigns.delay(user_id, action, data)
        
        return True
        
    except Exception as exc:
        logger.error(f"用户行为追踪失败: {exc}")
        return False

@celery_app.task
def check_marketing_campaigns(user_id, action, data):
    """检查营销活动"""
    try:
        logger.info(f"检查营销活动: 用户 {user_id}, 动作 {action}")
        
        # 基于用户行为触发不同的营销活动
        if action == 'product_view':
            # 商品浏览后推荐相似商品
            recommend_similar_products.delay(user_id, data.get('product_id'))
        
        elif action == 'add_to_cart':
            # 加入购物车后发送优惠券
            if data.get('cart_count', 0) > 2:
                send_abandoned_cart_coupon.delay(user_id)
        
        elif action == 'purchase_completed':
            # 购买完成后发送感谢邮件和推荐
            send_thank_you_email.delay(user_id, data.get('order_id'))
            recommend_related_products.delay(user_id, data.get('product_ids', []))
        
        return True
        
    except Exception as exc:
        logger.error(f"营销活动检查失败: {exc}")
        return False

@celery_app.task
def recommend_similar_products(user_id, product_id):
    """推荐相似商品"""
    logger.info(f"为用户 {user_id} 推荐相似商品,基于商品 {product_id}")
    time.sleep(0.1)
    return True

@celery_app.task
def send_abandoned_cart_coupon(user_id):
    """发送购物车放弃优惠券"""
    logger.info(f"为用户 {user_id} 发送购物车放弃优惠券")
    time.sleep(0.1)
    return True

@celery_app.task
def send_thank_you_email(user_id, order_id):
    """发送感谢邮件"""
    logger.info(f"为用户 {user_id} 发送感谢邮件,订单 {order_id}")
    time.sleep(0.1)
    return True

@celery_app.task
def recommend_related_products(user_id, product_ids):
    """推荐相关商品"""
    logger.info(f"为用户 {user_id} 推荐相关商品")
    time.sleep(0.1)
    return True

@celery_app.task
def sync_user_data_to_es(user_id):
    """同步用户数据到Elasticsearch"""
    try:
        logger.info(f"同步用户 {user_id} 数据到ES")
        
        # 获取用户数据
        user_data = get_user_data_for_es(user_id)
        
        # 同步到ES
        # es.index(index='users', id=user_id, body=user_data)
        
        logger.info(f"用户 {user_id} 数据同步完成")
        return True
        
    except Exception as exc:
        logger.error(f"用户数据同步失败: {exc}")
        return False

# 模拟函数
def record_user_analytics(user_id, action, data):
    logger.info(f"记录用户分析数据: {user_id}, {action}")
    return True

def update_user_profile(user_id, action, data):
    logger.info(f"更新用户画像: {user_id}, {action}")
    return True

def get_user_data_for_es(user_id):
    return {
        'user_id': user_id,
        'name': f'用户{user_id}',
        'last_active': datetime.now().isoformat()
    }

workers/order_worker.py

python 复制代码
# workers/order_worker.py
#!/usr/bin/env python3
"""
订单处理Worker启动脚本
"""
import os
import sys
from app import celery_app

if __name__ == '__main__':
    # 启动订单队列的Worker
    argv = [
        'worker', 
        '--loglevel=info',
        '--queues=orders,payments',
        '--concurrency=2',
        '--hostname=order_worker@%h'
    ]
    
    celery_app.worker_main(argv)

workers/notification_worker.py

python 复制代码
# workers/notification_worker.py
#!/usr/bin/env python3
"""
通知处理Worker启动脚本
"""
import os
import sys
from app import celery_app

if __name__ == '__main__':
    # 启动通知队列的Worker
    argv = [
        'worker', 
        '--loglevel=info',
        '--queues=notifications',
        '--concurrency=4',  # 通知任务可以更多并发
        '--hostname=notification_worker@%h'
    ]
    
    celery_app.worker_main(argv)
python 复制代码
# 使用示例 - API接口
from flask import Flask, request, jsonify
from tasks.order_tasks import process_order_creation
from tasks.payment_tasks import process_payment_callback
from tasks.user_tasks import track_user_behavior
import logging

app = Flask(__name__)

@app.route('/api/orders', methods=['POST'])
def create_order():
    """创建订单接口"""
    try:
        data = request.get_json()
        
        # 1. 创建订单(同步)
        order_id = create_order_in_db(data)
        
        # 2. 异步处理订单后续任务
        process_order_creation.delay(order_id)
        
        # 3. 追踪用户行为
        track_user_behavior.delay(
            user_id=data['user_id'],
            action='create_order',
            data={'order_id': order_id, 'amount': data['total_amount']}
        )
        
        return jsonify({
            'success': True,
            'order_id': order_id,
            'message': '订单创建成功'
        })
        
    except Exception as e:
        logging.error(f"订单创建失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/payments/callback', methods=['POST'])
def payment_callback():
    """支付回调接口"""
    try:
        data = request.get_json()
        
        # 异步处理支付回调
        process_payment_callback.delay(
            payment_id=data['payment_id'],
            status=data['status'],
            amount=data['amount']
        )
        
        return jsonify({'success': True})
        
    except Exception as e:
        logging.error(f"支付回调处理失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

def create_order_in_db(data):
    """模拟创建订单到数据库"""
    return 12345  # 返回订单ID

if __name__ == '__main__':
    app.run(debug=True)

RabbitMQ 实现

text 复制代码
rabbitmq_project/
├── producer/
│   ├── __init__.py
│   ├── order_producer.py
│   ├── payment_producer.py
│   └── notification_producer.py
├── consumer/
│   ├── __init__.py
│   ├── order_consumer.py
│   ├── payment_consumer.py
│   └── notification_consumer.py
├── common/
│   ├── __init__.py
│   ├── connection.py
│   └── message_schema.py
└── requirements.txt

common/connection.py

python 复制代码
import pika
import json
import logging
from typing import Any,Dict,Callable
import threading

logger = logging.getLogger(__name__)

class RabbitMQConnection:
	"""RabbitMQ连接管理"""
	_instance = None
	_lock = threading.Lock()

	def __new__(cls):
		with cls._lock:
			if cls._instance is None:
                cls._instance = super().__new__(cls)
                cls._instance._connections = {}
            return cls._instance

	def get_connection(self, connection_name='default'):
        """获取RabbitMQ连接"""
        if connection_name not in self._connections:
            self._create_connection(connection_name)
        return self._connections[connection_name]
    
    def _create_connection(self, connection_name):
        """创建新的连接"""
        try:
            # RabbitMQ连接参数
            credentials = pika.PlainCredentials(
                username='guest',  # 生产环境使用环境变量
                password='guest'
            )
            
            parameters = pika.ConnectionParameters(
                host='localhost',
                port=5672,
                credentials=credentials,
                heartbeat=600,
                blocked_connection_timeout=300
            )
            
            connection = pika.BlockingConnection(parameters)
            self._connections[connection_name] = connection
            
            logger.info(f"RabbitMQ连接 {connection_name} 创建成功")
            
        except Exception as e:
            logger.error(f"RabbitMQ连接创建失败: {e}")
            raise
    
    def close_all(self):
        """关闭所有连接"""
        for name, connection in self._connections.items():
            try:
                connection.close()
                logger.info(f"RabbitMQ连接 {name} 已关闭")
            except Exception as e:
                logger.error(f"关闭连接 {name} 失败: {e}")
        
        self._connections.clear()

# 全局连接管理器
connection_manager = RabbitMQConnection()
python 复制代码
# common/message_schema.py
from pydantic import BaseModel, Field
from typing import Any, Dict, Optional
from datetime import datetime
from enum import Enum

class MessageType(str, Enum):
    ORDER_CREATED = "order.created"
    ORDER_UPDATED = "order.updated"
    ORDER_CANCELLED = "order.cancelled"
    PAYMENT_SUCCESS = "payment.success"
    PAYMENT_FAILED = "payment.failed"
    NOTIFICATION_SEND = "notification.send"
    USER_BEHAVIOR = "user.behavior"

class BaseMessage(BaseModel):
    """基础消息模型"""
    message_id: str = Field(..., description="消息ID")
    message_type: MessageType = Field(..., description="消息类型")
    timestamp: datetime = Field(default_factory=datetime.now, description="消息时间戳")
    source: str = Field(..., description="消息来源")
    version: str = Field(default="1.0", description="消息版本")
    
    class Config:
        use_enum_values = True

class OrderMessage(BaseMessage):
    """订单消息"""
    order_id: int = Field(..., description="订单ID")
    user_id: int = Field(..., description="用户ID")
    total_amount: float = Field(..., description="订单总金额")
    items: list = Field(default=[], description="订单商品")
    metadata: Dict[str, Any] = Field(default={}, description="扩展数据")

class PaymentMessage(BaseMessage):
    """支付消息"""
    payment_id: str = Field(..., description="支付ID")
    order_id: int = Field(..., description="订单ID")
    amount: float = Field(..., description="支付金额")
    status: str = Field(..., description="支付状态")
    payment_method: str = Field(..., description="支付方式")
    metadata: Dict[str, Any] = Field(default={}, description="扩展数据")

class NotificationMessage(BaseMessage):
    """通知消息"""
    user_id: int = Field(..., description="用户ID")
    notification_type: str = Field(..., description="通知类型")
    title: str = Field(..., description="通知标题")
    content: str = Field(..., description="通知内容")
    channels: list = Field(default=[], description="发送渠道")
    metadata: Dict[str, Any] = Field(default={}, description="扩展数据")

class UserBehaviorMessage(BaseMessage):
    """用户行为消息"""
    user_id: int = Field(..., description="用户ID")
    action: str = Field(..., description="用户行为")
    page: Optional[str] = Field(None, description="页面")
    product_id: Optional[int] = Field(None, description="商品ID")
    metadata: Dict[str, Any] = Field(default={}, description="扩展数据")
python 复制代码
# producer/order_producer.py
import json
import logging
import uuid
from datetime import datetime
from common.connection import connection_manager
from common.message_schema import OrderMessage, MessageType

logger = logging.getLogger(__name__)

class OrderProducer:
    """订单消息生产者"""
    
    def __init__(self):
        self.connection = connection_manager.get_connection('order_producer')
        self.channel = self.connection.channel()
        
        # 声明交换机和队列
        self._setup_infrastructure()
    
    def _setup_infrastructure(self):
        """设置RabbitMQ基础设施"""
        # 声明主题交换机
        self.channel.exchange_declare(
            exchange='order_events',
            exchange_type='topic',
            durable=True
        )
        
        # 声明订单相关队列
        queues = [
            ('order_processing', 'order.created'),
            ('order_notifications', 'order.*'),
            ('order_analytics', 'order.#'),
        ]
        
        for queue_name, routing_key in queues:
            self.channel.queue_declare(queue=queue_name, durable=True)
            self.channel.queue_bind(
                exchange='order_events',
                queue=queue_name,
                routing_key=routing_key
            )
        
        logger.info("订单消息基础设施设置完成")
    
    def send_order_created(self, order_data: dict):
        """发送订单创建消息"""
        try:
            message = OrderMessage(
                message_id=str(uuid.uuid4()),
                message_type=MessageType.ORDER_CREATED,
                source="order_service",
                order_id=order_data['id'],
                user_id=order_data['user_id'],
                total_amount=order_data['total_amount'],
                items=order_data.get('items', []),
                metadata=order_data.get('metadata', {})
            )
            
            self._publish_message(
                exchange='order_events',
                routing_key='order.created',
                message=message
            )
            
            logger.info(f"订单创建消息发送成功: {order_data['id']}")
            return True
            
        except Exception as e:
            logger.error(f"订单创建消息发送失败: {e}")
            return False
    
    def send_order_updated(self, order_data: dict):
        """发送订单更新消息"""
        try:
            message = OrderMessage(
                message_id=str(uuid.uuid4()),
                message_type=MessageType.ORDER_UPDATED,
                source="order_service",
                order_id=order_data['id'],
                user_id=order_data['user_id'],
                total_amount=order_data['total_amount'],
                metadata=order_data.get('metadata', {})
            )
            
            self._publish_message(
                exchange='order_events',
                routing_key='order.updated',
                message=message
            )
            
            logger.info(f"订单更新消息发送成功: {order_data['id']}")
            return True
            
        except Exception as e:
            logger.error(f"订单更新消息发送失败: {e}")
            return False
    
    def send_order_cancelled(self, order_data: dict):
        """发送订单取消消息"""
        try:
            message = OrderMessage(
                message_id=str(uuid.uuid4()),
                message_type=MessageType.ORDER_CANCELLED,
                source="order_service",
                order_id=order_data['id'],
                user_id=order_data['user_id'],
                total_amount=order_data['total_amount'],
                metadata={'reason': order_data.get('cancel_reason', 'unknown')}
            )
            
            self._publish_message(
                exchange='order_events',
                routing_key='order.cancelled',
                message=message
            )
            
            logger.info(f"订单取消消息发送成功: {order_data['id']}")
            return True
            
        except Exception as e:
            logger.error(f"订单取消消息发送失败: {e}")
            return False
    
    def _publish_message(self, exchange: str, routing_key: str, message: OrderMessage):
        """发布消息到RabbitMQ"""
        self.channel.basic_publish(
            exchange=exchange,
            routing_key=routing_key,
            body=message.json(),
            properties=pika.BasicProperties(
                delivery_mode=2,  # 持久化消息
                content_type='application/json',
                timestamp=int(datetime.now().timestamp())
            )
        )
    
    def close(self):
        """关闭连接"""
        if self.channel and not self.channel.is_closed:
            self.channel.close()
        logger.info("订单生产者连接已关闭")
python 复制代码
# producer/payment_producer.py
import json
import logging
import uuid
from datetime import datetime
from common.connection import connection_manager
from common.message_schema import PaymentMessage, MessageType

logger = logging.getLogger(__name__)

class PaymentProducer:
    """支付消息生产者"""
    
    def __init__(self):
        self.connection = connection_manager.get_connection('payment_producer')
        self.channel = self.connection.channel()
        
        # 声明交换机和队列
        self._setup_infrastructure()
    
    def _setup_infrastructure(self):
        """设置RabbitMQ基础设施"""
        # 声明直连交换机
        self.channel.exchange_declare(
            exchange='payment_events',
            exchange_type='direct',
            durable=True
        )
        
        # 声明支付相关队列
        queues = [
            ('payment_processing', 'payment.success'),
            ('payment_processing', 'payment.failed'),
            ('payment_notifications', 'payment.success'),
            ('payment_notifications', 'payment.failed'),
            ('payment_analytics', 'payment.success'),
            ('payment_analytics', 'payment.failed'),
        ]
        
        for queue_name, routing_key in queues:
            self.channel.queue_declare(queue=queue_name, durable=True)
            self.channel.queue_bind(
                exchange='payment_events',
                queue=queue_name,
                routing_key=routing_key
            )
        
        logger.info("支付消息基础设施设置完成")
    
    def send_payment_success(self, payment_data: dict):
        """发送支付成功消息"""
        try:
            message = PaymentMessage(
                message_id=str(uuid.uuid4()),
                message_type=MessageType.PAYMENT_SUCCESS,
                source="payment_service",
                payment_id=payment_data['id'],
                order_id=payment_data['order_id'],
                amount=payment_data['amount'],
                status='success',
                payment_method=payment_data.get('method', 'unknown'),
                metadata=payment_data.get('metadata', {})
            )
            
            self._publish_message(
                exchange='payment_events',
                routing_key='payment.success',
                message=message
            )
            
            logger.info(f"支付成功消息发送成功: {payment_data['id']}")
            return True
            
        except Exception as e:
            logger.error(f"支付成功消息发送失败: {e}")
            return False
    
    def send_payment_failed(self, payment_data: dict):
        """发送支付失败消息"""
        try:
            message = PaymentMessage(
                message_id=str(uuid.uuid4()),
                message_type=MessageType.PAYMENT_FAILED,
                source="payment_service",
                payment_id=payment_data['id'],
                order_id=payment_data['order_id'],
                amount=payment_data['amount'],
                status='failed',
                payment_method=payment_data.get('method', 'unknown'),
                metadata={
                    'error_code': payment_data.get('error_code'),
                    'error_message': payment_data.get('error_message'),
                    **payment_data.get('metadata', {})
                }
            )
            
            self._publish_message(
                exchange='payment_events',
                routing_key='payment.failed',
                message=message
            )
            
            logger.info(f"支付失败消息发送成功: {payment_data['id']}")
            return True
            
        except Exception as e:
            logger.error(f"支付失败消息发送失败: {e}")
            return False
    
    def _publish_message(self, exchange: str, routing_key: str, message: PaymentMessage):
        """发布消息到RabbitMQ"""
        self.channel.basic_publish(
            exchange=exchange,
            routing_key=routing_key,
            body=message.json(),
            properties=pika.BasicProperties(
                delivery_mode=2,  # 持久化消息
                content_type='application/json',
                timestamp=int(datetime.now().timestamp())
            )
        )
    
    def close(self):
        """关闭连接"""
        if self.channel and not self.channel.is_closed:
            self.channel.close()
        logger.info("支付生产者连接已关闭")
python 复制代码
# consumer/order_consumer.py
import json
import logging
import time
from common.connection import connection_manager
from common.message_schema import OrderMessage, PaymentMessage

logger = logging.getLogger(__name__)

class OrderConsumer:
    """订单消息消费者"""
    
    def __init__(self):
        self.connection = connection_manager.get_connection('order_consumer')
        self.channel = self.connection.channel()
        
        # 配置QoS
        self.channel.basic_qos(prefetch_count=1)
    
    def start_consuming(self):
        """开始消费消息"""
        try:
            # 消费订单处理队列
            self.channel.basic_consume(
                queue='order_processing',
                on_message_callback=self._process_order_message,
                auto_ack=False
            )
            
            # 消费支付处理队列(用于订单状态更新)
            self.channel.basic_consume(
                queue='payment_processing',
                on_message_callback=self._process_payment_message,
                auto_ack=False
            )
            
            logger.info("订单消费者开始监听消息...")
            self.channel.start_consuming()
            
        except Exception as e:
            logger.error(f"订单消费者启动失败: {e}")
            raise
    
    def _process_order_message(self, ch, method, properties, body):
        """处理订单消息"""
        try:
            message_data = json.loads(body)
            message = OrderMessage(**message_data)
            
            logger.info(f"处理订单消息: {message.message_type}, 订单ID: {message.order_id}")
            
            if message.message_type == "order.created":
                self._handle_order_created(message)
            elif message.message_type == "order.updated":
                self._handle_order_updated(message)
            elif message.message_type == "order.cancelled":
                self._handle_order_cancelled(message)
            
            # 确认消息
            ch.basic_ack(delivery_tag=method.delivery_tag)
            logger.info(f"订单消息处理完成: {message.message_id}")
            
        except Exception as e:
            logger.error(f"订单消息处理失败: {e}")
            # 拒绝消息并重新入队
            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
    
    def _process_payment_message(self, ch, method, properties, body):
        """处理支付消息"""
        try:
            message_data = json.loads(body)
            message = PaymentMessage(**message_data)
            
            logger.info(f"处理支付消息: {message.message_type}, 支付ID: {message.payment_id}")
            
            if message.message_type == "payment.success":
                self._handle_payment_success(message)
            elif message.message_type == "payment.failed":
                self._handle_payment_failed(message)
            
            # 确认消息
            ch.basic_ack(delivery_tag=method.delivery_tag)
            logger.info(f"支付消息处理完成: {message.message_id}")
            
        except Exception as e:
            logger.error(f"支付消息处理失败: {e}")
            # 拒绝消息并重新入队
            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
    
    def _handle_order_created(self, message: OrderMessage):
        """处理订单创建"""
        logger.info(f"处理订单创建: {message.order_id}")
        
        # 1. 扣减库存
        self._deduct_inventory(message.order_id, message.items)
        
        # 2. 计算积分
        self._calculate_points(message.user_id, message.total_amount)
        
        # 3. 更新订单状态
        self._update_order_status(message.order_id, 'confirmed')
        
        logger.info(f"订单创建处理完成: {message.order_id}")
    
    def _handle_order_updated(self, message: OrderMessage):
        """处理订单更新"""
        logger.info(f"处理订单更新: {message.order_id}")
        # 订单更新逻辑
        time.sleep(0.1)
    
    def _handle_order_cancelled(self, message: OrderMessage):
        """处理订单取消"""
        logger.info(f"处理订单取消: {message.order_id}")
        
        # 1. 恢复库存
        self._restore_inventory(message.order_id, message.items)
        
        # 2. 更新订单状态
        self._update_order_status(message.order_id, 'cancelled')
        
        logger.info(f"订单取消处理完成: {message.order_id}")
    
    def _handle_payment_success(self, message: PaymentMessage):
        """处理支付成功"""
        logger.info(f"处理支付成功: {message.payment_id}, 订单: {message.order_id}")
        
        # 1. 更新订单支付状态
        self._update_order_payment_status(message.order_id, 'paid')
        
        # 2. 触发订单处理
        self._handle_order_created_after_payment(message.order_id)
        
        logger.info(f"支付成功处理完成: {message.payment_id}")
    
    def _handle_payment_failed(self, message: PaymentMessage):
        """处理支付失败"""
        logger.info(f"处理支付失败: {message.payment_id}, 订单: {message.order_id}")
        
        # 更新订单支付状态
        self._update_order_payment_status(message.order_id, 'payment_failed')
        
        logger.info(f"支付失败处理完成: {message.payment_id}")
    
    def _deduct_inventory(self, order_id, items):
        """扣减库存"""
        logger.info(f"为订单 {order_id} 扣减库存")
        for item in items:
            logger.info(f"扣减商品 {item.get('product_id')} 库存 {item.get('quantity')}")
            time.sleep(0.05)
    
    def _restore_inventory(self, order_id, items):
        """恢复库存"""
        logger.info(f"为订单 {order_id} 恢复库存")
        for item in items:
            logger.info(f"恢复商品 {item.get('product_id')} 库存 {item.get('quantity')}")
            time.sleep(0.05)
    
    def _calculate_points(self, user_id, amount):
        """计算积分"""
        points = int(amount)
        logger.info(f"为用户 {user_id} 计算积分 {points}")
        time.sleep(0.1)
    
    def _update_order_status(self, order_id, status):
        """更新订单状态"""
        logger.info(f"更新订单 {order_id} 状态为 {status}")
        time.sleep(0.05)
    
    def _update_order_payment_status(self, order_id, status):
        """更新订单支付状态"""
        logger.info(f"更新订单 {order_id} 支付状态为 {status}")
        time.sleep(0.05)
    
    def _handle_order_created_after_payment(self, order_id):
        """支付后处理订单创建"""
        logger.info(f"支付后处理订单创建: {order_id}")
        # 这里可以执行支付后的特定逻辑
    
    def stop_consuming(self):
        """停止消费"""
        if self.channel and self.channel.is_consuming():
            self.channel.stop_consuming()
        logger.info("订单消费者已停止")

if __name__ == '__main__':
    consumer = OrderConsumer()
    try:
        consumer.start_consuming()
    except KeyboardInterrupt:
        consumer.stop_consuming()
    finally:
        connection_manager.close_all()
python 复制代码
# consumer/notification_consumer.py
import json
import logging
import time
from common.connection import connection_manager
from common.message_schema import OrderMessage, PaymentMessage, NotificationMessage

logger = logging.getLogger(__name__)

class NotificationConsumer:
    """通知消息消费者"""
    
    def __init__(self):
        self.connection = connection_manager.get_connection('notification_consumer')
        self.channel = self.connection.channel()
        
        # 配置QoS
        self.channel.basic_qos(prefetch_count=2)  # 通知任务可以更高并发
    
    def start_consuming(self):
        """开始消费消息"""
        try:
            # 消费订单通知队列
            self.channel.basic_consume(
                queue='order_notifications',
                on_message_callback=self._process_order_notification,
                auto_ack=False
            )
            
            # 消费支付通知队列
            self.channel.basic_consume(
                queue='payment_notifications',
                on_message_callback=self._process_payment_notification,
                auto_ack=False
            )
            
            logger.info("通知消费者开始监听消息...")
            self.channel.start_consuming()
            
        except Exception as e:
            logger.error(f"通知消费者启动失败: {e}")
            raise
    
    def _process_order_notification(self, ch, method, properties, body):
        """处理订单通知"""
        try:
            message_data = json.loads(body)
            
            if 'order_id' in message_data:
                message = OrderMessage(**message_data)
                logger.info(f"处理订单通知: {message.message_type}, 订单ID: {message.order_id}")
                
                if message.message_type == "order.created":
                    self._send_order_created_notification(message)
                elif message.message_type == "order.cancelled":
                    self._send_order_cancelled_notification(message)
                
            # 确认消息
            ch.basic_ack(delivery_tag=method.delivery_tag)
            logger.info(f"订单通知处理完成: {message.message_id}")
            
        except Exception as e:
            logger.error(f"订单通知处理失败: {e}")
            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
    
    def _process_payment_notification(self, ch, method, properties, body):
        """处理支付通知"""
        try:
            message_data = json.loads(body)
            message = PaymentMessage(**message_data)
            
            logger.info(f"处理支付通知: {message.message_type}, 支付ID: {message.payment_id}")
            
            if message.message_type == "payment.success":
                self._send_payment_success_notification(message)
            elif message.message_type == "payment.failed":
                self._send_payment_failed_notification(message)
            
            # 确认消息
            ch.basic_ack(delivery_tag=method.delivery_tag)
            logger.info(f"支付通知处理完成: {message.message_id}")
            
        except Exception as e:
            logger.error(f"支付通知处理失败: {e}")
            ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
    
    def _send_order_created_notification(self, message: OrderMessage):
        """发送订单创建通知"""
        logger.info(f"发送订单创建通知: 订单 {message.order_id}, 用户 {message.user_id}")
        
        # 发送邮件
        self._send_email(
            to_email=get_user_email(message.user_id),
            subject="订单创建成功",
            content=f"您的订单 {message.order_id} 已创建,金额: {message.total_amount}"
        )
        
        # 发送短信
        self._send_sms(
            to_phone=get_user_phone(message.user_id),
            content=f"订单创建成功,订单号: {message.order_id}"
        )
        
        time.sleep(0.2)  # 模拟通知发送
    
    def _send_order_cancelled_notification(self, message: OrderMessage):
        """发送订单取消通知"""
        logger.info(f"发送订单取消通知: 订单 {message.order_id}")
        
        reason = message.metadata.get('reason', '未知原因')
        self._send_email(
            to_email=get_user_email(message.user_id),
            subject="订单已取消",
            content=f"您的订单 {message.order_id} 已取消,原因: {reason}"
        )
        
        time.sleep(0.1)
    
    def _send_payment_success_notification(self, message: PaymentMessage):
        """发送支付成功通知"""
        logger.info(f"发送支付成功通知: 支付 {message.payment_id}")
        
        self._send_email(
            to_email=get_user_email_by_order(message.order_id),
            subject="支付成功",
            content=f"您的订单 {message.order_id} 支付成功,金额: {message.amount}"
        )
        
        time.sleep(0.1)
    
    def _send_payment_failed_notification(self, message: PaymentMessage):
        """发送支付失败通知"""
        logger.info(f"发送支付失败通知: 支付 {message.payment_id}")
        
        error_msg = message.metadata.get('error_message', '未知错误')
        self._send_email(
            to_email=get_user_email_by_order(message.order_id),
            subject="支付失败",
            content=f"您的订单 {message.order_id} 支付失败,错误: {error_msg}"
        )
        
        time.sleep(0.1)
    
    def _send_email(self, to_email: str, subject: str, content: str):
        """发送邮件"""
        logger.info(f"发送邮件到 {to_email}: {subject}")
        # 实际邮件发送逻辑
        time.sleep(0.1)
    
    def _send_sms(self, to_phone: str, content: str):
        """发送短信"""
        logger.info(f"发送短信到 {to_phone}")
        # 实际短信发送逻辑
        time.sleep(0.05)
    
    def stop_consuming(self):
        """停止消费"""
        if self.channel and self.channel.is_consuming():
            self.channel.stop_consuming()
        logger.info("通知消费者已停止")

# 模拟函数
def get_user_email(user_id):
    return f"user{user_id}@example.com"

def get_user_phone(user_id):
    return "13800138000"

def get_user_email_by_order(order_id):
    return f"user{order_id}@example.com"

if __name__ == '__main__':
    consumer = NotificationConsumer()
    try:
        consumer.start_consuming()
    except KeyboardInterrupt:
        consumer.stop_consuming()
    finally:
        connection_manager.close_all()
python 复制代码
# 使用示例 - API接口
from flask import Flask, request, jsonify
from producer.order_producer import OrderProducer
from producer.payment_producer import PaymentProducer
import logging

app = Flask(__name__)

# 创建生产者实例
order_producer = OrderProducer()
payment_producer = PaymentProducer()

@app.route('/api/orders', methods=['POST'])
def create_order():
    """创建订单接口"""
    try:
        data = request.get_json()
        
        # 1. 创建订单(同步)
        order_id = create_order_in_db(data)
        order_data = {
            'id': order_id,
            'user_id': data['user_id'],
            'total_amount': data['total_amount'],
            'items': data.get('items', []),
            'metadata': data.get('metadata', {})
        }
        
        # 2. 发送订单创建消息
        order_producer.send_order_created(order_data)
        
        return jsonify({
            'success': True,
            'order_id': order_id,
            'message': '订单创建成功'
        })
        
    except Exception as e:
        logging.error(f"订单创建失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/payments/callback', methods=['POST'])
def payment_callback():
    """支付回调接口"""
    try:
        data = request.get_json()
        
        payment_data = {
            'id': data['payment_id'],
            'order_id': data['order_id'],
            'amount': data['amount'],
            'method': data.get('method', 'alipay'),
            'metadata': data.get('metadata', {})
        }
        
        if data['status'] == 'success':
            payment_producer.send_payment_success(payment_data)
        else:
            payment_data.update({
                'error_code': data.get('error_code'),
                'error_message': data.get('error_message')
            })
            payment_producer.send_payment_failed(payment_data)
        
        return jsonify({'success': True})
        
    except Exception as e:
        logging.error(f"支付回调处理失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/orders/<int:order_id>/cancel', methods=['POST'])
def cancel_order(order_id):
    """取消订单接口"""
    try:
        data = request.get_json()
        
        order_data = {
            'id': order_id,
            'user_id': data['user_id'],
            'total_amount': 0,  # 实际应该从数据库获取
            'cancel_reason': data.get('reason', '用户取消')
        }
        
        # 发送订单取消消息
        order_producer.send_order_cancelled(order_data)
        
        return jsonify({
            'success': True,
            'message': '订单取消请求已受理'
        })
        
    except Exception as e:
        logging.error(f"订单取消失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

def create_order_in_db(data):
    """模拟创建订单到数据库"""
    return 12345  # 返回订单ID

@app.teardown_appcontext
def close_producers(exception=None):
    """关闭生产者连接"""
    order_producer.close()
    payment_producer.close()

if __name__ == '__main__':
    app.run(debug=True)

Apache Kafka 实现

text 复制代码
kafka_project/
├── producer/
│   ├── __init__.py
│   ├── kafka_producer.py
│   └── event_producer.py
├── consumer/
│   ├── __init__.py
│   ├── order_consumer.py
│   ├── analytics_consumer.py
│   └── notification_consumer.py
├── schemas/
│   ├── __init__.py
│   └── events.py
└── requirements.txt
python 复制代码
# schemas/events.py
from pydantic import BaseModel, Field
from typing import Any, Dict, List, Optional
from datetime import datetime
from enum import Enum
import json

class EventType(str, Enum):
    ORDER_CREATED = "order_created"
    ORDER_UPDATED = "order_updated"
    ORDER_CANCELLED = "order_cancelled"
    PAYMENT_COMPLETED = "payment_completed"
    PAYMENT_FAILED = "payment_failed"
    USER_REGISTERED = "user_registered"
    USER_LOGGED_IN = "user_logged_in"
    PRODUCT_VIEWED = "product_viewed"

class BaseEvent(BaseModel):
    """基础事件模型"""
    event_id: str = Field(..., description="事件ID")
    event_type: EventType = Field(..., description="事件类型")
    event_time: datetime = Field(default_factory=datetime.now, description="事件时间")
    source: str = Field(..., description="事件来源")
    version: str = Field(default="1.0.0", description="事件版本")
    correlation_id: Optional[str] = Field(None, description="关联ID")
    
    class Config:
        use_enum_values = True
        json_encoders = {
            datetime: lambda v: v.isoformat()
        }

class OrderEvent(BaseEvent):
    """订单事件"""
    order_id: int = Field(..., description="订单ID")
    user_id: int = Field(..., description="用户ID")
    total_amount: float = Field(..., description="订单金额")
    currency: str = Field(default="CNY", description="货币")
    items: List[Dict[str, Any]] = Field(default=[], description="订单项")
    shipping_address: Optional[Dict[str, Any]] = Field(None, description="配送地址")
    metadata: Dict[str, Any] = Field(default={}, description="元数据")

class PaymentEvent(BaseEvent):
    """支付事件"""
    payment_id: str = Field(..., description="支付ID")
    order_id: int = Field(..., description="订单ID")
    amount: float = Field(..., description="支付金额")
    currency: str = Field(default="CNY", description="货币")
    payment_method: str = Field(..., description="支付方式")
    status: str = Field(..., description="支付状态")
    gateway_response: Optional[Dict[str, Any]] = Field(None, description="支付网关响应")
    metadata: Dict[str, Any] = Field(default={}, description="元数据")

class UserEvent(BaseEvent):
    """用户事件"""
    user_id: int = Field(..., description="用户ID")
    session_id: Optional[str] = Field(None, description="会话ID")
    user_agent: Optional[str] = Field(None, description="用户代理")
    ip_address: Optional[str] = Field(None, description="IP地址")
    device_info: Optional[Dict[str, Any]] = Field(None, description="设备信息")
    metadata: Dict[str, Any] = Field(default={}, description="元数据")

class ProductEvent(BaseEvent):
    """商品事件"""
    product_id: int = Field(..., description="商品ID")
    user_id: Optional[int] = Field(None, description="用户ID")
    category_id: Optional[int] = Field(None, description="分类ID")
    price: Optional[float] = Field(None, description="价格")
    action: str = Field(..., description="操作类型")
    metadata: Dict[str, Any] = Field(default={}, description="元数据")
python 复制代码
# producer/kafka_producer.py
import json
import logging
import uuid
from datetime import datetime
from confluent_kafka import Producer, KafkaError
from typing import Dict, Any, Optional

logger = logging.getLogger(__name__)

class KafkaEventProducer:
    """Kafka事件生产者"""
    
    def __init__(self, bootstrap_servers: str = 'localhost:9092'):
        self.bootstrap_servers = bootstrap_servers
        self.producer = self._create_producer()
        
        # 主题映射
        self.topic_mapping = {
            'order_events': ['order_created', 'order_updated', 'order_cancelled'],
            'payment_events': ['payment_completed', 'payment_failed'],
            'user_events': ['user_registered', 'user_logged_in'],
            'product_events': ['product_viewed'],
        }
    
    def _create_producer(self) -> Producer:
        """创建Kafka生产者"""
        config = {
            'bootstrap.servers': self.bootstrap_servers,
            'client.id': 'ecommerce-producer',
            'acks': 'all',  # 等待所有副本确认
            'retries': 5,   # 重试次数
            'retry.backoff.ms': 1000,  # 重试间隔
            'compression.type': 'snappy',  # 压缩类型
            'batch.num.messages': 1000,  # 批量消息数量
            'linger.ms': 10,  # 批量发送延迟
            'queue.buffering.max.messages': 100000,  # 队列大小
            'queue.buffering.max.kbytes': 1048576,   # 队列大小(KB)
        }
        
        return Producer(config)
    
    def get_topic_for_event(self, event_type: str) -> str:
        """根据事件类型获取对应的Kafka主题"""
        for topic, events in self.topic_mapping.items():
            if event_type in events:
                return topic
        return 'default_events'  # 默认主题
    
    def produce_event(self, event_data: Dict[str, Any]) -> bool:
        """生产事件到Kafka"""
        try:
            event_type = event_data.get('event_type')
            if not event_type:
                logger.error("事件类型不能为空")
                return False
            
            # 获取目标主题
            topic = self.get_topic_for_event(event_type)
            
            # 确保事件有ID和时间戳
            if 'event_id' not in event_data:
                event_data['event_id'] = str(uuid.uuid4())
            if 'event_time' not in event_data:
                event_data['event_time'] = datetime.now().isoformat()
            
            # 序列化消息
            message_value = json.dumps(event_data, ensure_ascii=False).encode('utf-8')
            
            # 发送消息
            self.producer.produce(
                topic=topic,
                value=message_value,
                key=event_data['event_id'].encode('utf-8'),  # 使用事件ID作为Key
                callback=self._delivery_callback
            )
            
            # 立即刷新(生产环境应该批量处理)
            self.producer.poll(0)
            
            logger.info(f"事件发送成功: {event_data['event_id']} -> {topic}")
            return True
            
        except Exception as e:
            logger.error(f"事件发送失败: {e}")
            return False
    
    def _delivery_callback(self, err, msg):
        """消息发送回调"""
        if err:
            logger.error(f"消息发送失败: {err}")
        else:
            logger.debug(f"消息发送成功: {msg.topic()} [{msg.partition()}] @ {msg.offset()}")
    
    def flush(self, timeout: float = 5.0):
        """刷新生产者,确保所有消息都已发送"""
        self.producer.flush(timeout)
    
    def close(self):
        """关闭生产者"""
        self.flush()
        logger.info("Kafka生产者已关闭")

class EventProducer:
    """事件生产者(业务层封装)"""
    
    def __init__(self, kafka_producer: KafkaEventProducer):
        self.producer = kafka_producer
    
    def send_order_created(self, order_data: Dict[str, Any]) -> bool:
        """发送订单创建事件"""
        event = {
            'event_type': 'order_created',
            'source': 'order_service',
            'order_id': order_data['id'],
            'user_id': order_data['user_id'],
            'total_amount': order_data['total_amount'],
            'items': order_data.get('items', []),
            'metadata': order_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_order_updated(self, order_data: Dict[str, Any]) -> bool:
        """发送订单更新事件"""
        event = {
            'event_type': 'order_updated',
            'source': 'order_service',
            'order_id': order_data['id'],
            'user_id': order_data['user_id'],
            'total_amount': order_data['total_amount'],
            'metadata': order_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_order_cancelled(self, order_data: Dict[str, Any]) -> bool:
        """发送订单取消事件"""
        event = {
            'event_type': 'order_cancelled',
            'source': 'order_service',
            'order_id': order_data['id'],
            'user_id': order_data['user_id'],
            'metadata': {
                'reason': order_data.get('cancel_reason', 'unknown'),
                **order_data.get('metadata', {})
            }
        }
        return self.producer.produce_event(event)
    
    def send_payment_completed(self, payment_data: Dict[str, Any]) -> bool:
        """发送支付完成事件"""
        event = {
            'event_type': 'payment_completed',
            'source': 'payment_service',
            'payment_id': payment_data['id'],
            'order_id': payment_data['order_id'],
            'amount': payment_data['amount'],
            'payment_method': payment_data.get('method', 'unknown'),
            'status': 'completed',
            'gateway_response': payment_data.get('gateway_response'),
            'metadata': payment_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_payment_failed(self, payment_data: Dict[str, Any]) -> bool:
        """发送支付失败事件"""
        event = {
            'event_type': 'payment_failed',
            'source': 'payment_service',
            'payment_id': payment_data['id'],
            'order_id': payment_data['order_id'],
            'amount': payment_data['amount'],
            'payment_method': payment_data.get('method', 'unknown'),
            'status': 'failed',
            'metadata': {
                'error_code': payment_data.get('error_code'),
                'error_message': payment_data.get('error_message'),
                **payment_data.get('metadata', {})
            }
        }
        return self.producer.produce_event(event)
    
    def send_user_registered(self, user_data: Dict[str, Any]) -> bool:
        """发送用户注册事件"""
        event = {
            'event_type': 'user_registered',
            'source': 'user_service',
            'user_id': user_data['id'],
            'metadata': user_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_product_viewed(self, product_data: Dict[str, Any]) -> bool:
        """发送商品浏览事件"""
        event = {
            'event_type': 'product_viewed',
            'source': 'web_frontend',
            'product_id': product_data['id'],
            'user_id': product_data.get('user_id'),
            'category_id': product_data.get('category_id'),
            'price': product_data.get('price'),
            'action': 'view',
            'metadata': product_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
python 复制代码
# producer/kafka_producer.py
import json
import logging
import uuid
from datetime import datetime
from confluent_kafka import Producer, KafkaError
from typing import Dict, Any, Optional

logger = logging.getLogger(__name__)

class KafkaEventProducer:
    """Kafka事件生产者"""
    
    def __init__(self, bootstrap_servers: str = 'localhost:9092'):
        self.bootstrap_servers = bootstrap_servers
        self.producer = self._create_producer()
        
        # 主题映射
        self.topic_mapping = {
            'order_events': ['order_created', 'order_updated', 'order_cancelled'],
            'payment_events': ['payment_completed', 'payment_failed'],
            'user_events': ['user_registered', 'user_logged_in'],
            'product_events': ['product_viewed'],
        }
    
    def _create_producer(self) -> Producer:
        """创建Kafka生产者"""
        config = {
            'bootstrap.servers': self.bootstrap_servers,
            'client.id': 'ecommerce-producer',
            'acks': 'all',  # 等待所有副本确认
            'retries': 5,   # 重试次数
            'retry.backoff.ms': 1000,  # 重试间隔
            'compression.type': 'snappy',  # 压缩类型
            'batch.num.messages': 1000,  # 批量消息数量
            'linger.ms': 10,  # 批量发送延迟
            'queue.buffering.max.messages': 100000,  # 队列大小
            'queue.buffering.max.kbytes': 1048576,   # 队列大小(KB)
        }
        
        return Producer(config)
    
    def get_topic_for_event(self, event_type: str) -> str:
        """根据事件类型获取对应的Kafka主题"""
        for topic, events in self.topic_mapping.items():
            if event_type in events:
                return topic
        return 'default_events'  # 默认主题
    
    def produce_event(self, event_data: Dict[str, Any]) -> bool:
        """生产事件到Kafka"""
        try:
            event_type = event_data.get('event_type')
            if not event_type:
                logger.error("事件类型不能为空")
                return False
            
            # 获取目标主题
            topic = self.get_topic_for_event(event_type)
            
            # 确保事件有ID和时间戳
            if 'event_id' not in event_data:
                event_data['event_id'] = str(uuid.uuid4())
            if 'event_time' not in event_data:
                event_data['event_time'] = datetime.now().isoformat()
            
            # 序列化消息
            message_value = json.dumps(event_data, ensure_ascii=False).encode('utf-8')
            
            # 发送消息
            self.producer.produce(
                topic=topic,
                value=message_value,
                key=event_data['event_id'].encode('utf-8'),  # 使用事件ID作为Key
                callback=self._delivery_callback
            )
            
            # 立即刷新(生产环境应该批量处理)
            self.producer.poll(0)
            
            logger.info(f"事件发送成功: {event_data['event_id']} -> {topic}")
            return True
            
        except Exception as e:
            logger.error(f"事件发送失败: {e}")
            return False
    
    def _delivery_callback(self, err, msg):
        """消息发送回调"""
        if err:
            logger.error(f"消息发送失败: {err}")
        else:
            logger.debug(f"消息发送成功: {msg.topic()} [{msg.partition()}] @ {msg.offset()}")
    
    def flush(self, timeout: float = 5.0):
        """刷新生产者,确保所有消息都已发送"""
        self.producer.flush(timeout)
    
    def close(self):
        """关闭生产者"""
        self.flush()
        logger.info("Kafka生产者已关闭")

class EventProducer:
    """事件生产者(业务层封装)"""
    
    def __init__(self, kafka_producer: KafkaEventProducer):
        self.producer = kafka_producer
    
    def send_order_created(self, order_data: Dict[str, Any]) -> bool:
        """发送订单创建事件"""
        event = {
            'event_type': 'order_created',
            'source': 'order_service',
            'order_id': order_data['id'],
            'user_id': order_data['user_id'],
            'total_amount': order_data['total_amount'],
            'items': order_data.get('items', []),
            'metadata': order_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_order_updated(self, order_data: Dict[str, Any]) -> bool:
        """发送订单更新事件"""
        event = {
            'event_type': 'order_updated',
            'source': 'order_service',
            'order_id': order_data['id'],
            'user_id': order_data['user_id'],
            'total_amount': order_data['total_amount'],
            'metadata': order_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_order_cancelled(self, order_data: Dict[str, Any]) -> bool:
        """发送订单取消事件"""
        event = {
            'event_type': 'order_cancelled',
            'source': 'order_service',
            'order_id': order_data['id'],
            'user_id': order_data['user_id'],
            'metadata': {
                'reason': order_data.get('cancel_reason', 'unknown'),
                **order_data.get('metadata', {})
            }
        }
        return self.producer.produce_event(event)
    
    def send_payment_completed(self, payment_data: Dict[str, Any]) -> bool:
        """发送支付完成事件"""
        event = {
            'event_type': 'payment_completed',
            'source': 'payment_service',
            'payment_id': payment_data['id'],
            'order_id': payment_data['order_id'],
            'amount': payment_data['amount'],
            'payment_method': payment_data.get('method', 'unknown'),
            'status': 'completed',
            'gateway_response': payment_data.get('gateway_response'),
            'metadata': payment_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_payment_failed(self, payment_data: Dict[str, Any]) -> bool:
        """发送支付失败事件"""
        event = {
            'event_type': 'payment_failed',
            'source': 'payment_service',
            'payment_id': payment_data['id'],
            'order_id': payment_data['order_id'],
            'amount': payment_data['amount'],
            'payment_method': payment_data.get('method', 'unknown'),
            'status': 'failed',
            'metadata': {
                'error_code': payment_data.get('error_code'),
                'error_message': payment_data.get('error_message'),
                **payment_data.get('metadata', {})
            }
        }
        return self.producer.produce_event(event)
    
    def send_user_registered(self, user_data: Dict[str, Any]) -> bool:
        """发送用户注册事件"""
        event = {
            'event_type': 'user_registered',
            'source': 'user_service',
            'user_id': user_data['id'],
            'metadata': user_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
    
    def send_product_viewed(self, product_data: Dict[str, Any]) -> bool:
        """发送商品浏览事件"""
        event = {
            'event_type': 'product_viewed',
            'source': 'web_frontend',
            'product_id': product_data['id'],
            'user_id': product_data.get('user_id'),
            'category_id': product_data.get('category_id'),
            'price': product_data.get('price'),
            'action': 'view',
            'metadata': product_data.get('metadata', {})
        }
        return self.producer.produce_event(event)
python 复制代码
# consumer/order_consumer.py
import json
import logging
import time
from typing import Dict, Any
from confluent_kafka import Consumer, KafkaError, KafkaException
from schemas.events import OrderEvent, PaymentEvent

logger = logging.getLogger(__name__)

class OrderEventConsumer:
    """订单事件消费者"""
    
    def __init__(self, bootstrap_servers: str = 'localhost:9092', group_id: str = 'order-processor'):
        self.bootstrap_servers = bootstrap_servers
        self.group_id = group_id
        self.consumer = self._create_consumer()
        self.running = False
        
        # 订阅主题
        self.topics = ['order_events', 'payment_events']
    
    def _create_consumer(self) -> Consumer:
        """创建Kafka消费者"""
        config = {
            'bootstrap.servers': self.bootstrap_servers,
            'group.id': self.group_id,
            'auto.offset.reset': 'earliest',  # 从最早开始消费
            'enable.auto.commit': False,  # 手动提交偏移量
            'max.poll.interval.ms': 300000,  # 最大poll间隔
            'session.timeout.ms': 10000,  # 会话超时
            'heartbeat.interval.ms': 3000,  # 心跳间隔
        }
        
        consumer = Consumer(config)
        consumer.subscribe(self.topics)
        
        return consumer
    
    def start_consuming(self):
        """开始消费事件"""
        self.running = True
        logger.info("订单事件消费者开始监听...")
        
        try:
            while self.running:
                msg = self.consumer.poll(1.0)  # 1秒超时
                
                if msg is None:
                    continue
                if msg.error():
                    if msg.error().code() == KafkaError._PARTITION_EOF:
                        # 分区结束,正常情况
                        continue
                    else:
                        logger.error(f"消费者错误: {msg.error()}")
                        continue
                
                try:
                    # 处理消息
                    self._process_message(msg)
                    
                    # 手动提交偏移量
                    self.consumer.commit(asynchronous=False)
                    
                except Exception as e:
                    logger.error(f"消息处理失败: {e}")
                    # 可以选择将失败消息发送到死信队列
                    self._send_to_dlq(msg, str(e))
        
        except KeyboardInterrupt:
            logger.info("收到中断信号,停止消费...")
        except Exception as e:
            logger.error(f"消费者异常: {e}")
        finally:
            self.stop_consuming()
    
    def _process_message(self, msg):
        """处理单个消息"""
        try:
            # 反序列化消息
            event_data = json.loads(msg.value().decode('utf-8'))
            topic = msg.topic()
            
            logger.info(f"处理事件: {event_data.get('event_type')} from {topic}")
            
            if topic == 'order_events':
                self._handle_order_event(event_data)
            elif topic == 'payment_events':
                self._handle_payment_event(event_data)
            
        except json.JSONDecodeError as e:
            logger.error(f"消息JSON解析失败: {e}")
        except Exception as e:
            logger.error(f"消息处理异常: {e}")
            raise
    
    def _handle_order_event(self, event_data: Dict[str, Any]):
        """处理订单事件"""
        event = OrderEvent(**event_data)
        
        if event.event_type == 'order_created':
            self._handle_order_created(event)
        elif event.event_type == 'order_updated':
            self._handle_order_updated(event)
        elif event.event_type == 'order_cancelled':
            self._handle_order_cancelled(event)
    
    def _handle_payment_event(self, event_data: Dict[str, Any]):
        """处理支付事件"""
        event = PaymentEvent(**event_data)
        
        if event.event_type == 'payment_completed':
            self._handle_payment_completed(event)
        elif event.event_type == 'payment_failed':
            self._handle_payment_failed(event)
    
    def _handle_order_created(self, event: OrderEvent):
        """处理订单创建"""
        logger.info(f"处理订单创建: {event.order_id}")
        
        # 1. 扣减库存
        self._deduct_inventory(event.order_id, event.items)
        
        # 2. 计算积分
        self._calculate_points(event.user_id, event.total_amount)
        
        # 3. 更新订单状态
        self._update_order_status(event.order_id, 'confirmed')
        
        logger.info(f"订单创建处理完成: {event.order_id}")
    
    def _handle_order_updated(self, event: OrderEvent):
        """处理订单更新"""
        logger.info(f"处理订单更新: {event.order_id}")
        # 订单更新逻辑
        time.sleep(0.1)
    
    def _handle_order_cancelled(self, event: OrderEvent):
        """处理订单取消"""
        logger.info(f"处理订单取消: {event.order_id}")
        
        # 1. 恢复库存
        self._restore_inventory(event.order_id, event.items)
        
        # 2. 更新订单状态
        self._update_order_status(event.order_id, 'cancelled')
        
        logger.info(f"订单取消处理完成: {event.order_id}")
    
    def _handle_payment_completed(self, event: PaymentEvent):
        """处理支付完成"""
        logger.info(f"处理支付完成: {event.payment_id}, 订单: {event.order_id}")
        
        # 1. 更新订单支付状态
        self._update_order_payment_status(event.order_id, 'paid')
        
        # 2. 触发订单处理
        self._handle_order_created_after_payment(event.order_id)
        
        logger.info(f"支付完成处理完成: {event.payment_id}")
    
    def _handle_payment_failed(self, event: PaymentEvent):
        """处理支付失败"""
        logger.info(f"处理支付失败: {event.payment_id}, 订单: {event.order_id}")
        
        # 更新订单支付状态
        self._update_order_payment_status(event.order_id, 'payment_failed')
        
        logger.info(f"支付失败处理完成: {event.payment_id}")
    
    def _deduct_inventory(self, order_id: int, items: list):
        """扣减库存"""
        logger.info(f"为订单 {order_id} 扣减库存")
        for item in items:
            logger.info(f"扣减商品 {item.get('product_id')} 库存 {item.get('quantity')}")
            time.sleep(0.05)
    
    def _restore_inventory(self, order_id: int, items: list):
        """恢复库存"""
        logger.info(f"为订单 {order_id} 恢复库存")
        for item in items:
            logger.info(f"恢复商品 {item.get('product_id')} 库存 {item.get('quantity')}")
            time.sleep(0.05)
    
    def _calculate_points(self, user_id: int, amount: float):
        """计算积分"""
        points = int(amount)
        logger.info(f"为用户 {user_id} 计算积分 {points}")
        time.sleep(0.1)
    
    def _update_order_status(self, order_id: int, status: str):
        """更新订单状态"""
        logger.info(f"更新订单 {order_id} 状态为 {status}")
        time.sleep(0.05)
    
    def _update_order_payment_status(self, order_id: int, status: str):
        """更新订单支付状态"""
        logger.info(f"更新订单 {order_id} 支付状态为 {status}")
        time.sleep(0.05)
    
    def _handle_order_created_after_payment(self, order_id: int):
        """支付后处理订单创建"""
        logger.info(f"支付后处理订单创建: {order_id}")
        # 这里可以执行支付后的特定逻辑
    
    def _send_to_dlq(self, msg, error: str):
        """发送到死信队列"""
        try:
            # 在实际项目中,这里应该将失败消息发送到专门的死信队列
            logger.error(f"消息发送到死信队列: {msg.topic()}[{msg.partition()}]@{msg.offset()}, 错误: {error}")
        except Exception as e:
            logger.error(f"发送到死信队列失败: {e}")
    
    def stop_consuming(self):
        """停止消费"""
        self.running = False
        self.consumer.close()
        logger.info("订单事件消费者已停止")

if __name__ == '__main__':
    consumer = OrderEventConsumer()
    try:
        consumer.start_consuming()
    except KeyboardInterrupt:
        pass
python 复制代码
# consumer/analytics_consumer.py
import json
import logging
import time
from datetime import datetime
from typing import Dict, Any
from confluent_kafka import Consumer, KafkaError
from schemas.events import OrderEvent, PaymentEvent, UserEvent, ProductEvent

logger = logging.getLogger(__name__)

class AnalyticsConsumer:
    """分析事件消费者"""
    
    def __init__(self, bootstrap_servers: str = 'localhost:9092', group_id: str = 'analytics-processor'):
        self.bootstrap_servers = bootstrap_servers
        self.group_id = group_id
        self.consumer = self._create_consumer()
        self.running = False
        
        # 订阅所有事件主题
        self.topics = ['order_events', 'payment_events', 'user_events', 'product_events']
    
    def _create_consumer(self) -> Consumer:
        """创建Kafka消费者"""
        config = {
            'bootstrap.servers': self.bootstrap_servers,
            'group.id': self.group_id,
            'auto.offset.reset': 'earliest',
            'enable.auto.commit': False,
            'max.poll.interval.ms': 300000,
        }
        
        consumer = Consumer(config)
        consumer.subscribe(self.topics)
        
        return consumer
    
    def start_consuming(self):
        """开始消费事件"""
        self.running = True
        logger.info("分析事件消费者开始监听...")
        
        try:
            while self.running:
                msg = self.consumer.poll(1.0)
                
                if msg is None:
                    continue
                if msg.error():
                    if msg.error().code() == KafkaError._PARTITION_EOF:
                        continue
                    else:
                        logger.error(f"消费者错误: {msg.error()}")
                        continue
                
                try:
                    self._process_message(msg)
                    self.consumer.commit(asynchronous=False)
                    
                except Exception as e:
                    logger.error(f"分析事件处理失败: {e}")
        
        except KeyboardInterrupt:
            logger.info("收到中断信号,停止消费...")
        except Exception as e:
            logger.error(f"分析消费者异常: {e}")
        finally:
            self.stop_consuming()
    
    def _process_message(self, msg):
        """处理分析事件"""
        try:
            event_data = json.loads(msg.value().decode('utf-8'))
            event_type = event_data.get('event_type')
            topic = msg.topic()
            
            logger.info(f"处理分析事件: {event_type} from {topic}")
            
            if topic == 'order_events':
                self._analyze_order_event(event_data)
            elif topic == 'payment_events':
                self._analyze_payment_event(event_data)
            elif topic == 'user_events':
                self._analyze_user_event(event_data)
            elif topic == 'product_events':
                self._analyze_product_event(event_data)
            
            # 批量更新分析数据(在实际项目中)
            self._batch_update_analytics()
            
        except Exception as e:
            logger.error(f"分析事件处理异常: {e}")
            raise
    
    def _analyze_order_event(self, event_data: Dict[str, Any]):
        """分析订单事件"""
        event = OrderEvent(**event_data)
        
        if event.event_type == 'order_created':
            # 记录订单创建指标
            self._record_order_metrics(event)
            
            # 用户行为分析
            self._analyze_user_behavior(event.user_id, 'order_created', {
                'order_id': event.order_id,
                'amount': event.total_amount
            })
        
        elif event.event_type == 'order_cancelled':
            # 记录订单取消指标
            self._record_cancellation_metrics(event)
    
    def _analyze_payment_event(self, event_data: Dict[str, Any]):
        """分析支付事件"""
        event = PaymentEvent(**event_data)
        
        if event.event_type == 'payment_completed':
            # 记录支付成功指标
            self._record_payment_success_metrics(event)
            
            # 收入统计
            self._record_revenue_metrics(event)
        
        elif event.event_type == 'payment_failed':
            # 记录支付失败指标
            self._record_payment_failure_metrics(event)
    
    def _analyze_user_event(self, event_data: Dict[str, Any]):
        """分析用户事件"""
        event = UserEvent(**event_data)
        
        if event.event_type == 'user_registered':
            # 新用户注册统计
            self._record_user_registration(event)
        
        elif event.event_type == 'user_logged_in':
            # 用户登录统计
            self._record_user_login(event)
    
    def _analyze_product_event(self, event_data: Dict[str, Any]):
        """分析商品事件"""
        event = ProductEvent(**event_data)
        
        if event.event_type == 'product_viewed':
            # 商品浏览统计
            self._record_product_view(event)
    
    def _record_order_metrics(self, event: OrderEvent):
        """记录订单指标"""
        logger.info(f"记录订单指标: 订单 {event.order_id}, 金额 {event.total_amount}")
        # 实际应该写入时序数据库或分析数据库
        time.sleep(0.02)
    
    def _record_cancellation_metrics(self, event: OrderEvent):
        """记录取消指标"""
        logger.info(f"记录取消指标: 订单 {event.order_id}")
        time.sleep(0.02)
    
    def _record_payment_success_metrics(self, event: PaymentEvent):
        """记录支付成功指标"""
        logger.info(f"记录支付成功指标: 支付 {event.payment_id}")
        time.sleep(0.02)
    
    def _record_payment_failure_metrics(self, event: PaymentEvent):
        """记录支付失败指标"""
        logger.info(f"记录支付失败指标: 支付 {event.payment_id}")
        time.sleep(0.02)
    
    def _record_revenue_metrics(self, event: PaymentEvent):
        """记录收入指标"""
        logger.info(f"记录收入指标: 金额 {event.amount}")
        time.sleep(0.01)
    
    def _record_user_registration(self, event: UserEvent):
        """记录用户注册"""
        logger.info(f"记录用户注册: 用户 {event.user_id}")
        time.sleep(0.01)
    
    def _record_user_login(self, event: UserEvent):
        """记录用户登录"""
        logger.info(f"记录用户登录: 用户 {event.user_id}")
        time.sleep(0.01)
    
    def _record_product_view(self, event: ProductEvent):
        """记录商品浏览"""
        logger.info(f"记录商品浏览: 商品 {event.product_id}")
        time.sleep(0.01)
    
    def _analyze_user_behavior(self, user_id: int, action: str, data: Dict[str, Any]):
        """分析用户行为"""
        logger.info(f"分析用户行为: 用户 {user_id}, 动作 {action}")
        time.sleep(0.05)
    
    def _batch_update_analytics(self):
        """批量更新分析数据"""
        # 在实际项目中,这里会批量更新分析数据库
        # 例如:每100条消息或每10秒更新一次
        pass
    
    def stop_consuming(self):
        """停止消费"""
        self.running = False
        self.consumer.close()
        logger.info("分析事件消费者已停止")

if __name__ == '__main__':
    consumer = AnalyticsConsumer()
    try:
        consumer.start_consuming()
    except KeyboardInterrupt:
        pass
python 复制代码
# consumer/analytics_consumer.py
import json
import logging
import time
from datetime import datetime
from typing import Dict, Any
from confluent_kafka import Consumer, KafkaError
from schemas.events import OrderEvent, PaymentEvent, UserEvent, ProductEvent

logger = logging.getLogger(__name__)

class AnalyticsConsumer:
    """分析事件消费者"""
    
    def __init__(self, bootstrap_servers: str = 'localhost:9092', group_id: str = 'analytics-processor'):
        self.bootstrap_servers = bootstrap_servers
        self.group_id = group_id
        self.consumer = self._create_consumer()
        self.running = False
        
        # 订阅所有事件主题
        self.topics = ['order_events', 'payment_events', 'user_events', 'product_events']
    
    def _create_consumer(self) -> Consumer:
        """创建Kafka消费者"""
        config = {
            'bootstrap.servers': self.bootstrap_servers,
            'group.id': self.group_id,
            'auto.offset.reset': 'earliest',
            'enable.auto.commit': False,
            'max.poll.interval.ms': 300000,
        }
        
        consumer = Consumer(config)
        consumer.subscribe(self.topics)
        
        return consumer
    
    def start_consuming(self):
        """开始消费事件"""
        self.running = True
        logger.info("分析事件消费者开始监听...")
        
        try:
            while self.running:
                msg = self.consumer.poll(1.0)
                
                if msg is None:
                    continue
                if msg.error():
                    if msg.error().code() == KafkaError._PARTITION_EOF:
                        continue
                    else:
                        logger.error(f"消费者错误: {msg.error()}")
                        continue
                
                try:
                    self._process_message(msg)
                    self.consumer.commit(asynchronous=False)
                    
                except Exception as e:
                    logger.error(f"分析事件处理失败: {e}")
        
        except KeyboardInterrupt:
            logger.info("收到中断信号,停止消费...")
        except Exception as e:
            logger.error(f"分析消费者异常: {e}")
        finally:
            self.stop_consuming()
    
    def _process_message(self, msg):
        """处理分析事件"""
        try:
            event_data = json.loads(msg.value().decode('utf-8'))
            event_type = event_data.get('event_type')
            topic = msg.topic()
            
            logger.info(f"处理分析事件: {event_type} from {topic}")
            
            if topic == 'order_events':
                self._analyze_order_event(event_data)
            elif topic == 'payment_events':
                self._analyze_payment_event(event_data)
            elif topic == 'user_events':
                self._analyze_user_event(event_data)
            elif topic == 'product_events':
                self._analyze_product_event(event_data)
            
            # 批量更新分析数据(在实际项目中)
            self._batch_update_analytics()
            
        except Exception as e:
            logger.error(f"分析事件处理异常: {e}")
            raise
    
    def _analyze_order_event(self, event_data: Dict[str, Any]):
        """分析订单事件"""
        event = OrderEvent(**event_data)
        
        if event.event_type == 'order_created':
            # 记录订单创建指标
            self._record_order_metrics(event)
            
            # 用户行为分析
            self._analyze_user_behavior(event.user_id, 'order_created', {
                'order_id': event.order_id,
                'amount': event.total_amount
            })
        
        elif event.event_type == 'order_cancelled':
            # 记录订单取消指标
            self._record_cancellation_metrics(event)
    
    def _analyze_payment_event(self, event_data: Dict[str, Any]):
        """分析支付事件"""
        event = PaymentEvent(**event_data)
        
        if event.event_type == 'payment_completed':
            # 记录支付成功指标
            self._record_payment_success_metrics(event)
            
            # 收入统计
            self._record_revenue_metrics(event)
        
        elif event.event_type == 'payment_failed':
            # 记录支付失败指标
            self._record_payment_failure_metrics(event)
    
    def _analyze_user_event(self, event_data: Dict[str, Any]):
        """分析用户事件"""
        event = UserEvent(**event_data)
        
        if event.event_type == 'user_registered':
            # 新用户注册统计
            self._record_user_registration(event)
        
        elif event.event_type == 'user_logged_in':
            # 用户登录统计
            self._record_user_login(event)
    
    def _analyze_product_event(self, event_data: Dict[str, Any]):
        """分析商品事件"""
        event = ProductEvent(**event_data)
        
        if event.event_type == 'product_viewed':
            # 商品浏览统计
            self._record_product_view(event)
    
    def _record_order_metrics(self, event: OrderEvent):
        """记录订单指标"""
        logger.info(f"记录订单指标: 订单 {event.order_id}, 金额 {event.total_amount}")
        # 实际应该写入时序数据库或分析数据库
        time.sleep(0.02)
    
    def _record_cancellation_metrics(self, event: OrderEvent):
        """记录取消指标"""
        logger.info(f"记录取消指标: 订单 {event.order_id}")
        time.sleep(0.02)
    
    def _record_payment_success_metrics(self, event: PaymentEvent):
        """记录支付成功指标"""
        logger.info(f"记录支付成功指标: 支付 {event.payment_id}")
        time.sleep(0.02)
    
    def _record_payment_failure_metrics(self, event: PaymentEvent):
        """记录支付失败指标"""
        logger.info(f"记录支付失败指标: 支付 {event.payment_id}")
        time.sleep(0.02)
    
    def _record_revenue_metrics(self, event: PaymentEvent):
        """记录收入指标"""
        logger.info(f"记录收入指标: 金额 {event.amount}")
        time.sleep(0.01)
    
    def _record_user_registration(self, event: UserEvent):
        """记录用户注册"""
        logger.info(f"记录用户注册: 用户 {event.user_id}")
        time.sleep(0.01)
    
    def _record_user_login(self, event: UserEvent):
        """记录用户登录"""
        logger.info(f"记录用户登录: 用户 {event.user_id}")
        time.sleep(0.01)
    
    def _record_product_view(self, event: ProductEvent):
        """记录商品浏览"""
        logger.info(f"记录商品浏览: 商品 {event.product_id}")
        time.sleep(0.01)
    
    def _analyze_user_behavior(self, user_id: int, action: str, data: Dict[str, Any]):
        """分析用户行为"""
        logger.info(f"分析用户行为: 用户 {user_id}, 动作 {action}")
        time.sleep(0.05)
    
    def _batch_update_analytics(self):
        """批量更新分析数据"""
        # 在实际项目中,这里会批量更新分析数据库
        # 例如:每100条消息或每10秒更新一次
        pass
    
    def stop_consuming(self):
        """停止消费"""
        self.running = False
        self.consumer.close()
        logger.info("分析事件消费者已停止")

if __name__ == '__main__':
    consumer = AnalyticsConsumer()
    try:
        consumer.start_consuming()
    except KeyboardInterrupt:
        pass
python 复制代码
# 使用示例 - API接口
from flask import Flask, request, jsonify
from producer.event_producer import EventProducer
from producer.kafka_producer import KafkaEventProducer
import logging
import uuid

app = Flask(__name__)

# 创建事件生产者
kafka_producer = KafkaEventProducer()
event_producer = EventProducer(kafka_producer)

@app.route('/api/orders', methods=['POST'])
def create_order():
    """创建订单接口"""
    try:
        data = request.get_json()
        
        # 1. 创建订单(同步)
        order_id = create_order_in_db(data)
        order_data = {
            'id': order_id,
            'user_id': data['user_id'],
            'total_amount': data['total_amount'],
            'items': data.get('items', []),
            'metadata': data.get('metadata', {})
        }
        
        # 2. 发送订单创建事件
        event_producer.send_order_created(order_data)
        
        return jsonify({
            'success': True,
            'order_id': order_id,
            'message': '订单创建成功'
        })
        
    except Exception as e:
        logging.error(f"订单创建失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/payments/callback', methods=['POST'])
def payment_callback():
    """支付回调接口"""
    try:
        data = request.get_json()
        
        payment_data = {
            'id': data['payment_id'],
            'order_id': data['order_id'],
            'amount': data['amount'],
            'method': data.get('method', 'alipay'),
            'gateway_response': data.get('gateway_response'),
            'metadata': data.get('metadata', {})
        }
        
        if data['status'] == 'success':
            event_producer.send_payment_completed(payment_data)
        else:
            payment_data.update({
                'error_code': data.get('error_code'),
                'error_message': data.get('error_message')
            })
            event_producer.send_payment_failed(payment_data)
        
        return jsonify({'success': True})
        
    except Exception as e:
        logging.error(f"支付回调处理失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/users/register', methods=['POST'])
def register_user():
    """用户注册接口"""
    try:
        data = request.get_json()
        
        user_id = create_user_in_db(data)
        user_data = {
            'id': user_id,
            'metadata': data.get('metadata', {})
        }
        
        # 发送用户注册事件
        event_producer.send_user_registered(user_data)
        
        return jsonify({
            'success': True,
            'user_id': user_id,
            'message': '用户注册成功'
        })
        
    except Exception as e:
        logging.error(f"用户注册失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/api/products/<int:product_id>/view', methods=['POST'])
def track_product_view(product_id):
    """追踪商品浏览"""
    try:
        data = request.get_json()
        
        product_data = {
            'id': product_id,
            'user_id': data.get('user_id'),
            'category_id': data.get('category_id'),
            'price': data.get('price'),
            'metadata': data.get('metadata', {})
        }
        
        # 发送商品浏览事件
        event_producer.send_product_viewed(product_data)
        
        return jsonify({'success': True})
        
    except Exception as e:
        logging.error(f"商品浏览追踪失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

def create_order_in_db(data):
    """模拟创建订单到数据库"""
    return 12345  # 返回订单ID

def create_user_in_db(data):
    """模拟创建用户到数据库"""
    return 1001  # 返回用户ID

@app.teardown_appcontext
def close_producer(exception=None):
    """关闭生产者"""
    kafka_producer.close()

if __name__ == '__main__':
    app.run(debug=True)

特性 Celery + Redis RabbitMQ Apache Kafka

消息模型 任务队列 消息代理 事件流平台

持久化 可选 支持 强持久化

消息顺序 不保证 队列内保证 分区内保证

吞吐量 中等 中等 非常高

延迟 低 低 低到中等

适用场景 异步任务、定时任务 应用解耦、复杂路由 事件流、数据管道

复杂度 低 中等 高

数据重放 不支持 有限支持 完整支持

生态系统 Python生态 多语言支持 完整流生态

相关推荐
我命由我123452 天前
Java 开发 - 简单消息队列实现、主题消息队列实现
java·开发语言·后端·算法·java-ee·消息队列·intellij-idea
sg_knight3 天前
RabbitMQ 中的预取值(prefetch)详解:如何真正提升消费端性能?
java·spring boot·spring·spring cloud·消息队列·rabbitmq·预取值
whltaoin6 天前
【微服务中间件】RabbitMQ 多平台安装搭建实践指南(Windows_macOS_Ubuntu_Docker 全场景)
微服务·中间件·消息队列·rabbitmq·多平台
AscentStream7 天前
案例实践 | Flipkart 异步总线如何实现不停机从 Kafka 迁移到 Pulsar
消息队列
little_xianzhong12 天前
三个常听到的消息/中间件MQTT RabbitMQ Kafka
java·笔记·中间件·消息队列
陈果然DeepVersion18 天前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(六)
spring boot·kafka·消息队列·向量数据库·java面试·rag·ai智能客服
陈果然DeepVersion18 天前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(二)
spring boot·kafka·消息队列·向量数据库·java面试·rag·ai智能客服
陈果然DeepVersion18 天前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(三)
spring boot·kafka·消息队列·java面试·大厂面试题·rag·ai智能客服
陈果然DeepVersion18 天前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(一)
spring boot·微服务·kafka·消息队列·java面试·rag·ai智能客服