Celery高可用架构设计:Broker、Worker与Result Backend协同实践

发布时间:2026/7/6 10:42:12

Celery高可用架构设计:Broker、Worker与Result Backend协同实践 1. 项目概述为什么 Celery 的高可用与水平扩展不是“加几台机器”那么简单在 Python 后端工程实践中Celery这个名字几乎等同于“异步任务调度”的代名词。但真正把 Celery 用进生产环境、扛住日均百万级任务吞吐、支撑订单履约、邮件推送、数据清洗、AI 模型预热等关键链路的团队很快会发现启动一个celery worker进程只是起点让整个任务系统在节点宕机、网络抖动、流量突增、队列积压时依然稳定交付才是真正的分水岭。我带过的三个中型 SaaS 项目里有两次线上事故的根因都指向同一个盲区——把 Celery 当成“开箱即用”的黑盒却忽略了它底层依赖的Broker消息中间件、Result Backend结果存储和Worker 进程模型三者之间严丝合缝的协同逻辑。所谓“High Availability and Horizontal Scaling”绝不是简单地celery -A proj worker --concurrency8多起几个进程更不是在 Kubernetes 里把 replicas 调到 20 就万事大吉。它是一套需要你亲手校准的分布式系统Broker 决定任务能不能发出去、Worker 决定任务能不能被消费、Result Backend 决定结果能不能被查到——三者中任意一环单点故障或配置失当整个链条就断了。这篇文章不讲 Celery 基础语法也不堆砌官方文档。我会以一个真实电商后台的“订单超时自动关单”任务为锚点从零开始拆解如何设计一个可横向伸缩、节点宕机不丢任务、结果可追溯、监控可落地的 Celery 生产级架构。你会看到 RabbitMQ 镜像队列的最小安全副本数怎么算、Redis 结果后端的过期策略为什么不能拍脑袋设 1 小时、K8s 中 Worker 的优雅退出为何必须配合preStop钩子、以及为什么acks_lateTrue在某些场景下反而比acks_earlyTrue更危险。这些细节往往就是线上告警和深夜救火之间的全部距离。2. 整体架构设计与核心组件选型逻辑2.1 为什么必须是“Broker Worker Result Backend”铁三角Celery 不是一个独立运行的进程而是一个分布式任务协调框架。它的核心职责是“分发”和“调度”而非“执行”或“存储”。这决定了它天然依赖三个外部组件构成闭环Broker消息代理任务的“邮局”。Producer你的 Django/Flask 应用把任务序列化后投递到这里Worker 从这里拉取任务。它不保证任务执行成功只保证“至少一次投递”at-least-once delivery。常见选型RabbitMQ、Redis、Apache Kafka。Worker工作进程任务的“快递员”。它连接 Broker持续拉取任务并执行。一个 Worker 可以有多个并发子进程--concurrency也可以部署多个 Worker 实例水平扩展。它负责执行业务逻辑、处理异常、上报状态。Result Backend结果后端任务的“回执系统”。Worker 执行完任务后把返回值、异常信息、执行耗时等元数据写入这里。调用方比如 Web 请求线程可以通过task_id查询执行结果。它不参与任务分发纯属“事后查询”。提示很多新手误以为CELERY_RESULT_BACKEND rpc://是最佳选择因为它看起来“不用额外存数据库”。但 RPC 方式本质是让 Worker 自己当结果服务器一旦该 Worker 宕机所有未被查询的结果就永久丢失——这直接破坏了高可用性。生产环境必须使用持久化后端如 Redis 或数据库。2.2 Broker 选型RabbitMQ 为何是高可用首选Redis 的坑在哪我们对比两个最常用 BrokerRabbitMQ和Redis。维度RabbitMQRedis消息可靠性原生支持消息持久化durable queues persistent messages、镜像队列mirrored queues、ACK 机制。单节点宕机镜像队列自动切换无消息丢失风险。持久化需开启appendonly yes但 AOF 重写期间可能丢数据无原生队列镜像主从切换时若从库未同步完成部分消息丢失。消息顺序性严格 FIFO同一队列内消息按入队顺序被消费。对“订单创建→支付→发货”类强序任务至关重要。单实例下 FIFO但集群模式Redis Cluster中不同 slot 的 key 分散在不同节点无法保证跨队列全局顺序。水平扩展能力集群节点间通过 Erlang 分布式协议通信新增节点即可分担连接压力镜像队列可跨节点复制扩展性好。Redis Cluster 支持分片但 Celery 的redis://URL 无法指定多个节点地址需借助客户端分片如redis-py-cluster增加复杂度。运维成熟度有成熟的管理界面RabbitMQ Management Plugin、丰富的监控指标队列长度、未确认消息数、消费者数量、完善的告警体系。监控依赖INFO命令关键指标如 pending tasks需自行解析缺乏开箱即用的队列级视图。结论对于要求高可靠、强顺序、易监控的生产任务系统RabbitMQ 是无可争议的首选。我们项目最终采用3 节点 RabbitMQ 集群 镜像队列ha-modeall。这里有个关键计算镜像队列的副本数不是越多越好。假设集群有 N 个节点设置ha-modeall会让每个队列在所有节点上都有副本。但当节点数 3 时网络分区Network Partition概率上升Erlang 集群的脑裂Split-Brain问题会导致部分节点拒绝服务。因此3 节点是 RabbitMQ 高可用集群的黄金配置——既能容忍单节点故障又规避了多节点带来的协调开销。我们实测过3 节点集群在单节点宕机后新任务入队延迟从平均 2ms 升至 5ms完全在业务可接受范围内而 5 节点集群在模拟网络抖动时出现过 12 秒的队列不可用窗口。2.3 Result Backend 选型Redis vs 数据库性能与一致性的权衡Result Backend 的核心诉求是低延迟读写、高并发支持、数据不丢失、TTL 管理灵活。Redis 和关系型数据库如 PostgreSQL是两大主流。Redis 方案CELERY_RESULT_BACKEND redis://:passwordredis:6379/1✅ 优势毫秒级读写完美匹配任务结果“短时高频查询”场景如前端轮询任务进度支持原生 TTL可为不同任务类型设置差异化过期时间。❌ 劣势内存存储成本高主从异步复制主库宕机且未同步到从库时结果丢失无事务无法保证“任务执行成功 结果写入”原子性。PostgreSQL 方案CELERY_RESULT_BACKEND dbpostgresql://user:passdb:5432/celery_results✅ 优势数据强持久化WAL 日志保障不丢支持 ACID可与业务数据库共用连接池降低运维复杂度便于做历史结果归档、审计分析。❌ 劣势写入延迟高平均 15ms在每秒数千任务的场景下Result Backend 可能成为瓶颈TTL 需自行实现如定时 Job 清理date_created now() - INTERVAL 7 days。我们的折中方案Redis 作为主 Result BackendPostgreSQL 作为冷备归档库。具体实现Celery 配置CELERY_RESULT_BACKEND redis://...所有结果写入 Redis编写一个独立的result_archiver服务监听 Redis 的__keyevent1__:expired通道需开启notify-keyspace-events Ex捕获过期的任务结果 key将过期 key 对应的完整结果 JSON 解析后写入 PostgreSQL 的celery_task_results_archive表并打上archived_at时间戳业务方查询时优先查 Redis若 Redis 中不存在已过期则查 PostgreSQL 归档表。这个方案兼顾了实时性与持久性上线后 Redis 内存占用稳定在 12GB支撑 5000 并发任务PostgreSQL 归档表日增记录 80 万条查询响应时间 100ms。2.4 Worker 部署模型进程级并发 vs 容器级水平扩展Celery Worker 的扩展有两个维度纵向Vertical单个 Worker 进程内增加并发子进程数--concurrencyN横向Horizontal部署多个 Worker 实例不同机器或容器。很多人认为“横向扩展更优”于是把--concurrency设为 1然后疯狂扩 Pod 数量。这是个巨大误区。原因在于CPU 密集型任务如图像压缩、PDF 生成单 Worker 进程内多线程/多进程能充分利用单机 CPU 核心减少进程间通信开销。此时--concurrency88 核机器比 8 个--concurrency1的 Worker 更高效。I/O 密集型任务如 HTTP 调用、数据库查询单进程内多协程如gevent比多进程更省内存、上下文切换更快。此时--poolgevent --concurrency1000是合理选择。混合型任务绝大多数业务场景必须根据任务 profile 动态调整。我们用cProfile对“订单关单”任务采样发现30% 时间在 DB 查询I/O50% 在 Redis 写入I/O20% 在 Python 计算CPU。因此我们采用--poolprefork --concurrency4prefork 是默认进程池既避免 gevent 的猴子补丁monkey patch对第三方库的兼容性风险又让单机 4 核资源得到充分压榨。最终部署架构是Kubernetes StatefulSet 管理 Worker每个 Pod 运行 1 个 Worker 进程--concurrency4HPAHorizontal Pod Autoscaler根据rabbitmq_queue_messages_ready{queuecelery}指标自动扩缩 Pod 数量。当待处理消息数 1000触发扩容 200触发缩容。实测在流量高峰秒杀活动时Pod 数从 5 快速扩到 22消息积压在 30 秒内清零。3. 核心细节解析与实操要点3.1 RabbitMQ 镜像队列的深度配置与验证仅仅在 RabbitMQ 管理界面勾选“Mirroring”远远不够。生产环境必须通过命令行或策略Policy精确控制镜像行为。我们使用的策略如下# 创建名为 ha-all 的策略应用于所有以 celery 开头的队列 rabbitmqctl set_policy ha-all ^celery\. {ha-mode:all,ha-sync-mode:automatic}^celery\.正则匹配队列名确保只有 Celery 使用的队列如celery,celeryworker1被镜像ha-mode:all在所有在线节点上创建镜像副本ha-sync-mode:automatic新节点加入集群时自动同步已有队列数据无需手动rabbitmqctl sync_queue。关键验证步骤必须在上线前执行强制关闭一个 RabbitMQ 节点docker stop rabbitmq-node2如果是 K8s则kubectl delete pod rabbitmq-1观察管理界面剩余两个节点的Queues页面中对应队列的State应显示runningSynchronised mirrors数量应为 2原为 3发送测试任务在应用中调用some_task.delay()检查 RabbitMQ 管理界面Publish message按钮是否正常响应Messages ready数量是否增加重启宕机节点docker start rabbitmq-node2验证自动同步等待 2-3 分钟在管理界面查看该队列的Synchronised mirrors是否恢复为 3且Unsynchronised mirrors为 0。注意如果Unsynchronised mirrors长时间不为 0说明网络或磁盘 I/O 存在瓶颈。我们曾遇到过因 NFS 存储性能不足导致镜像同步卡在 99% 的情况。解决方案是改用本地 SSD 存储并在rabbitmq.conf中增加disk_free_limit.relative 1.0禁用磁盘空间检查由 K8s 的resources.limits.ephemeral-storage统一管控。3.2 Celery 配置文件的“防呆”设计一个健壮的celeryconfig.py不仅要定义参数更要内置防御性逻辑。以下是我们的核心配置节选及原理说明# celeryconfig.py import os from celery import Celery # 1. Broker 连接字符串从环境变量读取强制要求 BROKER_URL os.environ.get(CELERY_BROKER_URL) if not BROKER_URL: raise RuntimeError(CELERY_BROKER_URL must be set in environment) # 2. Result Backend同样强制环境变量且校验格式 RESULT_BACKEND os.environ.get(CELERY_RESULT_BACKEND) if not RESULT_BACKEND or not RESULT_BACKEND.startswith((redis://, db)): raise RuntimeError(CELERY_RESULT_BACKEND must be redis:// or db...) # 3. 关键可靠性参数这才是高可用的灵魂 CELERY_TASK_ACKS_LATE True # 任务执行完成后才 ACK防止 Worker 宕机导致任务丢失 CELERY_WORKER_PREFETCH_MULTIPLIER 1 # 每个 Worker 进程最多预取 1 个任务避免单个慢任务阻塞整个进程 CELERY_TASK_REJECT_ON_WORKER_LOST True # Worker 异常退出时将未完成任务重新入队 CELERY_TASK_SERIALIZER json # 强制使用 JSON避免 pickle 的安全风险与兼容性问题 CELERY_RESULT_SERIALIZER json CELERY_ACCEPT_CONTENT [json] # 4. 任务超时与重试防止死循环和长任务拖垮系统 CELERY_TASK_TIME_LIMIT 300 # 任务硬性超时 5 分钟超时则强制终止进程 CELERY_TASK_SOFT_TIME_LIMIT 240 # 软超时 4 分钟触发异常但不终止进程可做清理 CELERY_TASK_DEFAULT_RETRY_DELAY 60 # 默认重试延迟 60 秒 CELERY_TASK_MAX_RETRIES 3 # 最多重试 3 次避免无限重试雪崩 # 5. 队列路由为不同任务类型分配专属队列隔离风险 CELERY_TASK_ROUTES { proj.tasks.order_close: {queue: order_queue, routing_key: order.close}, proj.tasks.send_email: {queue: email_queue, routing_key: email.send}, proj.tasks.data_clean: {queue: data_queue, routing_key: data.clean}, }逐条解释其必要性CELERY_TASK_ACKS_LATE True这是高可用的基石。默认acks_earlyTrue是在任务刚被 Worker 拉取时就向 Broker 发送 ACK如果 Worker 在执行中崩溃任务就永远消失了。设为True后只有task.run()函数成功返回或抛出可重试异常时才发送 ACK。我们曾在线上因忘记此配置导致一次 RabbitMQ 节点升级期间数百个“关单”任务静默丢失引发大量客诉。CELERY_WORKER_PREFETCH_MULTIPLIER 1Prefetch 是 Worker 为提升吞吐一次性从 Broker 拉取多个任务缓存在内存中。但若一个任务执行 10 分钟而 prefetch 设置为 10那么该 Worker 进程的其他 9 个核就空转了。设为 1 后Worker 总是“按需拉取”保证负载绝对均衡。代价是 Broker 连接数略增但远小于负载不均带来的损失。CELERY_TASK_TIME_LIMIT必须设置Python 的time.sleep(10000)或数据库死锁会让任务无限挂起吃光 Worker 进程资源。硬超时是最后的安全阀。3.3 任务函数的编写规范不只是app.task一个看似简单的app.task装饰器背后藏着大量影响可用性的细节。以下是我们团队强制遵守的《Celery 任务函数编写规范》✅ 必须做的显式声明bindTrue让任务函数能访问自身上下文用于重试、日志、获取task_id。app.task(bindTrue, max_retries3, default_retry_delay60) def order_close(self, order_id): try: # 业务逻辑 close_order(order_id) except DatabaseError as exc: # 捕获特定异常触发重试 raise self.retry(excexc) except Exception as exc: # 未知异常记录详细日志后放弃 logger.exception(fUnexpected error closing order {order_id}) raise所有外部调用必须带超时HTTP 请求用requests.get(url, timeout(3, 10))DB 查询用session.execute(text(...), execution_options{timeout: 5})。没有超时的调用是分布式系统的定时炸弹。幂等性设计任务必须能被安全重试多次。例如“关单”任务先查订单状态是否已是“已关闭”若是则直接返回避免重复操作。❌ 绝对禁止的在任务中创建全局连接对象如conn redis.Redis(...)写在函数外。Worker 进程是长生命周期的全局连接会因网络闪断而失效。正确做法是每次执行时新建连接或使用连接池如redis.ConnectionPool。在任务中修改全局状态如global COUNTER; COUNTER 1。多进程环境下每个子进程有独立内存空间修改无效且难以调试。返回大型对象如return queryset.all()返回整个 QuerySet。Result Backend 会尝试序列化所有数据极易 OOM。应只返回关键 ID 或摘要信息如return {order_id: order_id, status: closed}。3.4 Kubernetes 中 Worker 的优雅启停与健康检查在容器化环境中K8s 的livenessProbe和readinessProbe是保障高可用的关键。但 Celery Worker 的特殊性让标准配置失效Liveness Probe存活探针如果用http://localhost:5000/health检查Worker 本身不提供 HTTP 服务会直接失败导致 K8s 不断重启 Pod。Readiness Probe就绪探针如果只检查进程是否存在Worker 进程虽在但可能因 Broker 连接中断而无法消费任务此时不应将流量导向它。我们的解决方案自建/healthz端点 celery inspect命令集成。首先在 Worker 启动时启动一个轻量 HTTP 服务用flask或aiohttp# health_server.py from flask import Flask, jsonify import subprocess import json app Flask(__name__) app.route(/healthz) def healthz(): # 1. 检查自身进程 if not is_worker_running(): return jsonify({status: unhealthy, reason: worker process not found}), 500 # 2. 检查 Broker 连接调用 celery inspect try: result subprocess.run( [celery, -A, proj, inspect, ping, --timeout2], capture_outputTrue, textTrue, timeout3 ) if result.returncode ! 0: return jsonify({status: unhealthy, reason: broker ping failed}), 500 # 解析 ping 结果确保至少有一个活跃 worker ping_data json.loads(result.stdout) if not ping_data or len(ping_data) 0: return jsonify({status: unhealthy, reason: no active workers}), 500 except Exception as e: return jsonify({status: unhealthy, reason: finspect error: {str(e)}}), 500 return jsonify({status: ok}), 200 def is_worker_running(): # 检查当前进程是否是 celery worker import psutil current psutil.Process() return celery in current.cmdline()[0] and worker in current.cmdline() if __name__ __main__: app.run(host0.0.0.0:8000)然后在 K8s Deployment 中配置# deployment.yaml livenessProbe: httpGet: path: /healthz port: 8000 initialDelaySeconds: 60 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /healthz port: 8000 initialDelaySeconds: 30 periodSeconds: 15 timeoutSeconds: 3 # successThreshold: 1 # 默认就是1表示一次成功即就绪 # 关键优雅终止 lifecycle: preStop: exec: command: [/bin/sh, -c, celery -A proj control cancel_consumer celery --timeout10 sleep 5]preStop中的命令含义celery -A proj control cancel_consumer celery向所有 Worker 发送指令停止消费celery队列的新消息sleep 5留出 5 秒缓冲让 Worker 处理完已拉取但未执行的任务K8s 在preStop执行完毕后再发送SIGTERM终止进程。我们实测过在preStop加入此逻辑后Worker Pod 缩容时任务丢失率为 0而未加时平均每次缩容丢失 2-3 个任务。4. 实操过程与核心环节实现4.1 从零搭建高可用 RabbitMQ 集群Docker Compose 版虽然生产用 K8s但本地开发和 CI/CD 测试用 Docker Compose 更便捷。以下是经过我们生产验证的docker-compose.yml# docker-compose-rabbitmq.yml version: 3.8 services: rabbitmq1: image: rabbitmq:3.11-management hostname: rabbitmq1 container_name: rabbitmq1 ports: - 5672:5672 # AMQP - 15672:15672 # Management UI environment: RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: admin RABBITMQ_ERLANG_COOKIE: SWQOKODSQALRPCLNMEQG RABBITMQ_NODE_PORT: 5672 RABBITMQ_NODE_IP_ADDRESS: 0.0.0.0 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: -kernel inet_dist_listen_min 9100 inet_dist_listen_max 9100 volumes: - ./rabbitmq1:/var/lib/rabbitmq networks: - celery-net rabbitmq2: image: rabbitmq:3.11-management hostname: rabbitmq2 container_name: rabbitmq2 ports: - 5673:5672 - 15673:15672 environment: RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: admin RABBITMQ_ERLANG_COOKIE: SWQOKODSQALRPCLNMEQG RABBITMQ_NODE_PORT: 5672 RABBITMQ_NODE_IP_ADDRESS: 0.0.0.0 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: -kernel inet_dist_listen_min 9100 inet_dist_listen_max 9100 RABBITMQ_CLUSTER_PARTITION_HANDLING: autoheal RABBITMQ_CLUSTER_QUEUES: true RABBITMQ_CLUSTER_NODES: rabbitmq1 rabbitmq2 rabbitmq3 volumes: - ./rabbitmq2:/var/lib/rabbitmq depends_on: - rabbitmq1 networks: - celery-net rabbitmq3: image: rabbitmq:3.11-management hostname: rabbitmq3 container_name: rabbitmq3 ports: - 5674:5672 - 15674:15672 environment: RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: admin RABBITMQ_ERLANG_COOKIE: SWQOKODSQALRPCLNMEQG RABBITMQ_NODE_PORT: 5672 RABBITMQ_NODE_IP_ADDRESS: 0.0.0.0 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: -kernel inet_dist_listen_min 9100 inet_dist_listen_max 9100 RABBITMQ_CLUSTER_PARTITION_HANDLING: autoheal RABBITMQ_CLUSTER_QUEUES: true RABBITMQ_CLUSTER_NODES: rabbitmq1 rabbitmq2 rabbitmq3 volumes: - ./rabbitmq3:/var/lib/rabbitmq depends_on: - rabbitmq1 - rabbitmq2 networks: - celery-net networks: celery-net: driver: bridge启动与初始化步骤docker-compose -f docker-compose-rabbitmq.yml up -d启动三个容器等待 30 秒确保所有节点启动完成加入集群关键Docker Compose 不会自动组集群# 进入 rabbitmq2 容器 docker exec -it rabbitmq2 bash # 停止应用保留 Erlang 节点 rabbitmqctl stop_app # 将 rabbitmq2 加入 rabbitmq1 的集群 rabbitmqctl join_cluster rabbitrabbitmq1 # 启动应用 rabbitmqctl start_app exit # 同样操作将 rabbitmq3 加入集群 docker exec -it rabbitmq3 bash rabbitmqctl stop_app rabbitmqctl join_cluster rabbitrabbitmq1 rabbitmqctl start_app exit设置镜像策略docker exec rabbitmq1 rabbitmqctl set_policy ha-all ^celery\. {ha-mode:all,ha-sync-mode:automatic}验证集群状态docker exec rabbitmq1 rabbitmqctl cluster_status # 输出中应包含 {nodes,[{disc,[rabbitrabbitmq1,rabbitrabbitmq2,rabbitrabbitmq3]]}注意RABBITMQ_ERLANG_COOKIE必须三节点完全一致否则集群无法建立。RABBITMQ_CLUSTER_NODES指定了集群种子节点但实际加入需手动join_cluster。4.2 Celery Worker 的 Dockerfile 与构建优化一个高效的 Worker 镜像直接影响启动速度、内存占用和安全性。我们的Dockerfile如下# Dockerfile.worker FROM python:3.10-slim # 1. 创建非 root 用户安全基线 RUN groupadd -g 1001 -r celery \ useradd -r -u 1001 -g celery celery # 2. 安装系统依赖如 gcc 用于编译 psycopg2 RUN apt-get update apt-get install -y --no-install-recommends \ gcc \ libpq-dev \ rm -rf /var/lib/apt/lists/* # 3. 创建工作目录并切换用户 WORKDIR /app USER celery # 4. 复制 requirements.txt 并安装 Python 依赖利用 Docker 层缓存 COPY --chowncelery:celery requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 5. 复制应用代码注意权限 COPY --chowncelery:celery . . # 6. 健康检查端点复用前面写的 health_server.py EXPOSE 8000 CMD [sh, -c, python health_server.py celery -A proj worker --loglevelinfo --concurrency4]关键优化点多阶段构建未展示但强烈推荐在构建阶段用python:3.10安装所有依赖运行阶段用python:3.10-slim镜像体积可从 1.2GB 降至 320MB--no-cache-dir避免 pip 在容器内缓存节省空间--chowncelery:celery复制文件时直接设置属主避免后续chown命令USER celery以非 root 用户运行满足 CIS Docker Benchmark 安全要求。构建命令docker build -f Dockerfile.worker -t myapp/celery-worker:1.0 .4.3 K8s Deployment 与 HPA 的完整 YAML这是生产环境直接可用的部署模板已去除敏感信息# k8s/celery-worker-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: celery-worker labels: app: celery-worker spec: replicas: 5 selector: matchLabels: app: celery-worker template: metadata: labels: app: celery-worker spec: serviceAccountName: celery-worker-sa # 绑定 RBAC 权限 containers: - name: worker image: myapp/celery-worker:1.0 imagePullPolicy: IfNotPresent env: - name: CELERY_BROKER_URL value: amqp://admin:adminrabbitmq:5672 - name: CELERY_RESULT_BACKEND value: redis://:passwordredis:6379/1 resources: requests: memory: 512Mi cpu: 250m limits: memory: 1Gi cpu: 500m livenessProbe: httpGet: path: /healthz port: 8000 initialDelaySeconds: 60 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /healthz port: 8000 initialDelaySeconds: 30 periodSeconds: 15 timeoutSeconds: 3 lifecycle: preStop: exec: command: [/bin/sh, -c, celery -A proj control cancel_consumer celery --timeout10 sleep 5] ports: - containerPort: 8000 name: health restartPolicy: Always --- # k8s/celery-worker-hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: celery-worker-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: celery-worker minReplicas: 3 maxReplicas: 30 metrics: - type: External external: metric: name: rabbitmq_queue_messages_ready selector: matchLabels: queue: celery target: type: AverageValue averageValue: 100HPA 配置说明rabbitmq_queue_messages_ready是 Prometheus 通过rabbitmq-exporter抓取的指标averageValue: 100表示当所有celery队列的平均待处理消息数超过 100 时触发扩容minReplicas: 3保证基础运力避免冷启动延迟maxReplicas: 30是根据 RabbitMQ 集群最大连接数默认 65536和单 Worker 平均连接数约 2000计算得出的理论上限防止压垮 Broker。4.4 全链路监控与告警配置没有监控的高可用系统是空中楼阁。我们基于 Prometheus Grafana 构建了 Celery 全链路监控核心监控指标Broker 层rabbitmq_queue_messages_ready{queuecelery}待处理消息、rabbitmq_queue_messages_unacknowledged{queuecelery}正在处理的消息、rabbitmq_node_fd_used

相关新闻