任务队列的应用场景
在 Web2.0 后的时代,社交网站、搜索引擎的的迅猛发展对 Web 服务的后台管理系统提出了更高的需求。
考虑几个常见的使用场景:
- 社交网站的用户在其主页发布了一组新的照片,这条新鲜事需要适时地推送至该用户的所有好友。该网站的活跃用户有千万级别,在同一时刻会有非常多的“新鲜事推送”任务需要处理,并且每个用户的好友数会达到 1000+的级别。出于用户体验的考虑,用户发布照片的这个操作需要在较短时间内得到反馈。
- 在文献搜索系统的主页,用户可以查到当前一小时内最热门的十大文献,并且能够直接访问该文献。该文献管理系统所管理的文献数量非常多,达到 PB 的级别。处于用户体验的考虑,用户获得十大热门文献这个动作需要在较短时间内获得反馈。
考虑对于高并发大用户量的 Web 服务系统,对于场景一和场景二中的需求,如果在请求处理周期内完成这些任务,然后再返回结果,这种传统的做法会导致用户等待的时间过长。同时 Web 服务管理后台对任务处理能力也缺乏扩展性。
在这些场景下,任务队列是有效的解决方案。
在一个任务队列系统中,“将新鲜事推送至用户A的所有好友”或者“查询当前最热门的十大文献”这种查询或者计算工作可以被当成一个“任务”。
在任务队列系统中,一般有任务生产者、任务处理中间方以及任务处理者三方。
- 任务生产者负责创建任务,比如“将新鲜事推送至用户A的所有好友”这一任务的发起方就可以称作任务生产者。
- 任务处理中间方负责接收任务生产者的任务处理请求,对任务进行调度,最后将任务分发给任务处理者来进行处理。
- 任务处理者就是执行任务的一方,它负责接收任务处理中间方发来的任务处理请求,完成这些任务,并且返回任务处理的结果。
在生产方、消费者和任务处理中间方之间一般使用消息传递的方式来进行通信。
在任务队列系统框架中,任务处理者可以跨越不同的服务节点,可以动态地增加节点来增加系统的任务处理能力,非常适合高并发、需要横向扩展的 Web 服务后台。
什么是Celery?
Celery是基于Python语言的开源分布式任务调度模块。
它有着简明的 API,并且有丰富的扩展性,适合用于构建分布式的Web服务。
Celery的结构图如下:
在上图中,一共可以分为五个部分:
- application(任务生产者)
- celery beat(定时任务处触发)
- broker(任务队列)
- workers(任务处理者)
- result store(运行结果存储)
下面,我们依次来了解这五个部分的作用:
任务生产者 (task producer)
任务生产者 (task producer) 负责产生计算任务,交给任务队列去处理。
在 Celery 里,一段独立的 Python 代码、一段嵌入在 Django Web 服务里的一段请求处理逻辑,只要是调用了 Celery 提供的 API,产生任务并交给任务队列处理的,我们都可以称之为任务生产者。
任务调度器 (celery beat)
Celery beat 是一个任务调度器,它以独立进程的形式存在。
Celery beat 进程会读取配置文件的内容,周期性地将执行任务的请求发送给任务队列。
Celery beat 是 Celery系统自带的任务生产者。
系统管理员可以选择关闭或者开启 Celery beat。
同时在一个 Celery 系统中,只能存在一个Celery beat调度器。
任务代理 (broker)
任务代理方负责接受任务生产者发送过来的任务处理消息,存进队列之后再进行调度,分发给任务消费方 (celery worker)。
因为任务处理是基于 message(消息) 的,所以我们一般选择 RabbitMQ、Redis 等消息队列或者数据库作为 Celery 的 message broker。
任务消费方 (celery worker)
Celery worker 就是执行任务的一方,它负责接收任务处理中间方发来的任务处理请求,完成这些任务,并且返回任务处理的结果。
Celery worker 对应的就是操作系统中的一个进程。
Celery 支持分布式部署和横向扩展,我们可以在多个节点增加 Celery worker 的数量来增加系统的高可用性。
在分布式系统中,我们也可以在不同节点上分配执行不同任务的 Celery worker 来达到模块化的目的。
结果保存
Celery 支持任务处理完后将状态信息和结果的保存,以供查询。
Celery 内置支持 rpc, Django ORM,Redis,RabbitMQ 等方式来保存任务处理后的状态信息。