Celery多生产者部署的定时任务去重

Overview

最近在部署webserver,同一个应用(生产者)部署在3个机器上,3个机器都启用了Celery来启动定时任务,执行文件的增删。

celery workflow

application SPF

可以看到在mq和celery worker阶段都可以做到高可用。但是在user application阶段,存在single point failure的情况,如果单点故障,定时任务就发送不到broker了。

而为了消除user application的SPF或者增加整体吞吐量,一般会部署多个application,而这样的情况,每个application都会发送相同的定时任务到broker,导致同一时间就会有多个task。

虽然增删的底层是原子性的,但是多个API同时执行,最后通过conflict来确认是不妥当的。为了解决这个问题,可以采用以下方式,

  1. 分布式定时队列
    • 类似oozie,由一个master来控制metadata
    • 将task不写在user application里面,将其再往上抽象一层
  2. api发送定时任务到broker之前,先过一层分布式锁,获得锁的application才能发送,
    • mysql字段
    • zookeeper
      • 优点: 模型简单,其临时顺序节点天然支持释放锁和node crash
      • 缺点: ZAB的全部同步,写性能较低
    • redis(Redission), etcd
      • 优点: 高性能(10w级)
      • 缺点: 实现复杂,需要考虑加锁与超时的原子性,低效的等锁自旋
  3. mq去重,以相同的task id(时间)发送task到mq,然后mq抓取后进行去重(延迟)

其中分布式锁已经有了一个celery-oncecelery-singleton的实现。

With Unique Task

celery worker with unique task

Reference