【问题标题】:Multiple Docker containers and Celery多个 Docker 容器和 Celery
【发布时间】:2017-08-24 13:33:10
【问题描述】:

我们现在的项目结构如下:

  1. 处理来自客户端的传入请求的 Web 服务器。
  2. 向用户提供一些建议的分析模块。

我们决定让这些模块完全独立,并将它们移动到不同的 docker 容器中。当来自用户的查询到达网络服务器时,它会向分析模块发送另一个查询以获取建议。

为了使建议保持一致,我们需要定期进行一些后台计算,例如,当新用户在我们的系统中注册时。此外,一些后台任务纯粹与 Web 服务器逻辑相关联。为此,我们决定使用分布式任务队列,例如 Celery。

任务创建和执行的可能场景如下:

  1. 任务在网络服务器上排队,在网络服务器上执行(例如,处理上传的图像)
  2. 在网络服务器上排队的任务,在分析模块中执行(例如,为新用户计算推荐)
  3. 在分析模块中排队并在那里执行的任务(例如,定期更新)

到目前为止,我在这里看到了使用 Celery 的 3 种相当奇怪的可能性:

我。芹菜放在单独的容器里,什么都做

  1. 将 Celery 移到单独的 docker 容器中。
  2. 提供来自网络服务器和分析的所有必要包以执行任务。
  3. 与其他容器共享任务代码(或在网络服务器和分析中声明虚拟任务)

这样,我们放松了隔离,因为功能由 Celery 容器和其他容器共享。

二。芹菜放在单独的容器里,做的少得多

I 相同,但任务现在只是对网络服务器和分析模块的请求,它们在那里异步处理,结果在任务内部轮询,直到它准备好。

通过这种方式,我们从拥有代理中受益,但所有繁重的计算都从 Celery 工作人员转移。

三。在每个容器中分开芹菜

  1. 在网络服务器和分析模块中运行 Celery。
  2. 向网络服务器添加(分析任务的)虚拟任务声明。
  3. 添加 2 个任务队列,一个用于 Web 服务器,一个用于分析。

这样,在网络服务器上安排的任务可以在分析模块中执行。但是,仍然需要跨容器共享任务代码或使用虚拟任务,此外,还需要在每个容器中运行 celery worker。

最好的方法是什么,或者应该完全改变逻辑,例如,将所有东西移到一个容器中?

【问题讨论】:

    标签: docker celery


    【解决方案1】:

    首先,让我们澄清一下 celery 库(通过 pip installsetup.py 获得)和 celery worker 之间的区别 - 这是从代理和处理它们。当然,您可能希望拥有多个 workers/进程(例如,用于将不同的任务分配给不同的 worker)。

    假设您有两个任务:calculate_recommendations_taskperiodic_update_task,并且您想在单独的工作人员(即 recommendation_workerperiodic_worker)上运行它们。 另一个进程将是 celery beat,它只是每 x 小时将 periodic_update_task 排入代理。

    此外,假设您有一个使用bottle 实现的简单网络服务器。

    我假设您也想将 celery 代理和后端与 docker 一起使用,我将选择 celery 的推荐用法 - RabbitMQ 作为代理,Redis 作为后端。

    所以现在我们有 6 个容器,我会将它们写在 docker-compose.yml 中:

    version: '2'
    services:
      rabbit:
        image: rabbitmq:3-management
        ports:
          - "15672:15672"
          - "5672:5672"
        environment:
          - RABBITMQ_DEFAULT_VHOST=vhost
          - RABBITMQ_DEFAULT_USER=guest
          - RABBITMQ_DEFAULT_PASS=guest
      redis:
        image: library/redis
        command: redis-server /usr/local/etc/redis/redis.conf
        expose:
          - "6379"
        ports:
          - "6379:6379"
      recommendation_worker:
        image: recommendation_image
        command: celery worker -A recommendation.celeryapp:app -l info -Q recommendation_worker -c 1 -n recommendation_worker@%h -Ofair
      periodic_worker:
        image: recommendation_image
        command: celery worker -A recommendation.celeryapp:app -l info -Q periodic_worker -c 1 -n periodic_worker@%h -Ofair
      beat:
        image: recommendation_image
        command: <not sure>
      web:
        image: web_image
        command: python web_server.py
    

    构建recommendation_imageweb_image 的dockerfile 都应该安装celery 。只有 recommendation_image 应该有任务代码,因为工作人员将处理这些任务:

    推荐Dockerfile:

    FROM python:2.7-wheezy
    RUN pip install celery
    COPY tasks_src_code..
    

    WebDockerfile:

    FROM python:2.7-wheezy
    RUN pip install celery
    RUN pip install bottle 
    COPY web_src_code..
    

    其他图像(rabbitmq:3-managementlibrary/redis 可从 docker hub 获得,它们会在您运行 docker-compose up 时自动拉取)。

    现在是这样的:在您的网络服务器中,您可以通过字符串名称触发 celery 任务并通过任务 ID 提取结果(不共享代码)web_server.py

    import bottle
    from celery import Celery
    rabbit_path = 'amqp://guest:guest@rabbit:5672/vhost'
    celeryapp = Celery('recommendation', broker=rabbit_path)
    celeryapp.config_from_object('config.celeryconfig')
    
    @app.route('/trigger_task', method='POST')
    def trigger_task():
        r = celeryapp.send_task('calculate_recommendations_task', args=(1, 2, 3))
        return r.id
    
    @app.route('/trigger_task_res', method='GET')
    def trigger_task_res():
        task_id = request.query['task_id']
        result = celery.result.AsyncResult(task_id, app=celeryapp)
        if result.ready():
            return result.get()
        return result.state
    

    最后一个文件config.celeryconfig.py

    CELERY_ROUTES = {
        'calculate_recommendations_task': {
            'exchange': 'recommendation_worker',
            'exchange_type': 'direct',
            'routing_key': 'recommendation_worker'
        }
    }
    CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'msgpack', 'yaml']
    

    【讨论】:

    • 感谢您的详细解答!
    • 您可以通过接受答案和点赞来感谢我 ;-)
    • 所以,基本上,我需要使用 celery worker 容器的代码重用图像。如果我需要使用来自不同模块的 celery 任务,我想,我应该为每个 celery 容器使用不同的图像。
    • 是的,没错。你说你想要服务器和工作人员之间的分离.. 当然你也可以将它们分开
    • 很好的答案 - 能够毫无问题地使用它来启动 POC。
    猜你喜欢
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多