Оптимизация

Введение

Конфигурация по умолчанию допускает множество компромиссов. Она не является оптимальной для какого-либо отдельного случая, но работает достаточно хорошо для большинства ситуаций.

Существуют оптимизации, которые могут быть применены в зависимости от конкретных случаев использования.

Оптимизация может применяться к различным свойствам рабочей среды, будь то время, необходимое для выполнения задач, объем используемой памяти или скорость реакции в моменты высокой нагрузки.

Обеспечение деятельности

В книге Programming Pearls Джон Бентли излагает концепцию вычислений по принципу «back-of-the-envelope», задавая вопрос;

» Сколько воды вытекает из реки Миссисипи за день? «

Смысл этого упражнения [*] заключается в том, чтобы показать, что существует предел того, сколько данных система может обрабатывать своевременно. Расчеты «назад по конверту» могут быть использованы как средство для планирования этого заранее.

В Celery; если на выполнение задачи требуется 10 минут, и каждую минуту поступает 10 новых задач, очередь никогда не будет пустой. Вот почему очень важно следить за длиной очереди!

Способ сделать это - using Munin. Вы должны настроить оповещения, которые будут уведомлять вас, как только какая-либо очередь достигнет неприемлемого размера. Таким образом, вы сможете принять соответствующие меры, например, добавить новые рабочие узлы или отозвать ненужные задания.

Общие настройки

Пулы соединений брокера

Пул соединений брокера включен по умолчанию начиная с версии 2.5.

Вы можете настроить параметр broker_pool_limit для минимизации конкуренции, а значение должно быть основано на количестве активных потоков/зеленых потоков, использующих соединения брокера.

Использование переходных очередей

Очереди, созданные Celery, по умолчанию являются постоянными. Это означает, что брокер будет записывать сообщения на диск, чтобы гарантировать, что задания будут выполнены, даже если брокер будет перезапущен.

Но в некоторых случаях нет ничего страшного в том, что сообщение будет потеряно, поэтому не все задачи требуют долговечности. Вы можете создать переходную очередь для этих задач, чтобы улучшить производительность:

from kombu import Exchange, Queue

task_queues = (
    Queue('celery', routing_key='celery'),
    Queue('transient', Exchange('transient', delivery_mode=1),
          routing_key='transient', durable=False),
)

или с помощью task_routes:

task_routes = {
    'proj.tasks.add': {'queue': 'celery', 'delivery_mode': 'transient'}
}

Параметр delivery_mode изменяет способ доставки сообщений в эту очередь. Значение один означает, что сообщение не будет записано на диск, а значение два (по умолчанию) означает, что сообщение может быть записано на диск.

Чтобы направить задачу в вашу новую переходную очередь, вы можете указать аргумент queue (или использовать настройку task_routes):

task.apply_async(args, queue='transient')

Для получения дополнительной информации см. раздел routing guide.

Настройки работника

Пределы предварительной выборки

Prefetch - это термин, унаследованный от AMQP, который часто неправильно понимается пользователями.

Предел предварительной выборки - это ограничение на количество заданий (сообщений), которые рабочий может зарезервировать для себя. Если он равен нулю, рабочий будет продолжать потреблять сообщения, не обращая внимания на то, что могут существовать другие доступные рабочие узлы, которые могут обработать их быстрее [], или что сообщения могут даже не поместиться в памяти.

Количество prefetch по умолчанию для рабочих - это значение worker_prefetch_multiplier, умноженное на количество слотов параллелизма [] (процессов/потоков/зеленых потоков).

Если у вас много задач с большой продолжительностью, вы хотите, чтобы значение множителя было равно один: это означает, что одновременно будет резервироваться только одна задача на рабочий процесс.

Однако – если у вас много коротких задач, и для вас важна пропускная способность/задержка в пути, это число должно быть большим. Рабочий может обрабатывать больше задач в секунду, если сообщения уже были предварительно сброшены и доступны в памяти. Возможно, вам придется поэкспериментировать, чтобы найти оптимальное значение, которое подойдет именно вам. Значения типа 50 или 150 могут иметь смысл в таких обстоятельствах. Скажем, 64 или 128.

Если у вас есть комбинация долго- и краткосрочных задач, лучшим вариантом будет использование двух рабочих узлов, настроенных отдельно, и маршрутизация задач в зависимости от времени выполнения (см. Задачи маршрутизации).

Резервируйте по одной задаче за раз

Сообщение о задании удаляется из очереди только после того, как задание выполнено acknowledged, поэтому если рабочий упал до подтверждения задания, оно может быть повторно передано другому рабочему (или тому же самому после восстановления).

При использовании по умолчанию раннего подтверждения, установка множителя предварительной выборки 1 означает, что рабочий будет резервировать не более одной дополнительной задачи для каждого рабочего процесса: или, другими словами, если рабочий запущен с -c 10, он может резервировать не более 20 задач (10 подтвержденных выполняющихся задач и 10 непризнанных зарезервированных задач) в любое время.

Часто пользователи спрашивают, можно ли отключить «предварительную выборку заданий», но на самом деле они имеют в виду, чтобы рабочий резервировал только столько заданий, сколько рабочих процессов (10 непринятых заданий для -c 10).

Это возможно, но не без включения опции late acknowledgment. Использование этой опции вместо поведения по умолчанию означает, что задача, которая уже начала выполняться, будет повторно запущена в случае сбоя питания или внезапного завершения рабочего экземпляра, поэтому это также означает, что задача должна быть idempotent.

Вы можете включить это поведение с помощью следующих параметров конфигурации:

task_acks_late = True
worker_prefetch_multiplier = 1

Сноски

Вернуться на верх