Pull to refresh

Comments 24

Интересно, а какие альтернативы celery на питоне есть сейчас? А то большая часть проектов умеет только в redis, что явно не prouduction-ready решение.
rq — только redis
tasktiger — только redis
Huey — только redis
WorQ — только redis
dramatiq — вроде неплохо, но не хватает ряда полезных фич, например, событий.
django-carrot — странная штука, просто обертка над rabbitmq

Ну гуглить я тоже умею, интересно все-таки немного отзывов.
Тада ждем, я пайтон больше для автоматизации использую, с очередями и шинами почти не работал.
apscheduler — вот такое еще есть. Не только redis, правда rabbitmq нет.

Что значит "явно не prouduction-ready решение" применительно к редису для очередей?

Подскажите, что вы будете делать, когда у вас очередь перестанет влазить в память? Это ждет практически любой проект, который использует большое количество фоновых задач.

Ну и редис не скалируется по человечески.

К самому редису претензий нет, но использовать его для очереди задач очень странно, на мой взгляд.
Понятно. Используем редис. Пока в память влазят миллионы задач, ну а больше нам и не надо, ибо задачи должны быстро обрабатываться, а не копиться, и ненулевое количество задач в очереди вообще нужно для сглаживания пиков нагрузки.
И сколько он у вас памяти ест? Мне вот 450 мб не хватало для 5-10 тысяч задач.
Точно не могу сказать. Он на машине с 32 гигами, выделенными под редис, но в нём не только очереди, но и другие NoSQL данные (в других БД редиса). Ну допустим на максимум 32гб можно ориентироваться. Обычно он жрёт чуть меньше 10Гб.
И какой у вас поток задач в секунду? Ну, у нас пока не доходит до десятка в секунду. У вас под сотню или где-то так же?

Просто на мой взгляд, если где-то меньше десятка, то такой поток вытягивает и кролик на 1 ГБ и со слабым диском.
Этот вопрос я так понимаю имеет отношение к скорости редиса. Точных цифр бенчмарков на прод не помню, но сразу могу сказать что он медленнее RabbitMQ, и собственно его скорость зависит от той собственно системы очередей, что используется, у нас своя система, а она сильно влияет на бенчмарки.
Из цифр могу сказать что эпизодически ставятся сотни тысяч задач в очередь и этого никто не замечает, если по ошибке поставить 10млн, то да, память кончится. На этот случай есть мониторинг.
Это довольно странно, так как Redis должен быть быстрее RabbitMQ, в силу того, что кролик далеко не всегда хранит свои очереди в памяти. Если редис еще и медленее кролика смысла использовать его никакого нет, на мой взгляд.

Просто меня довольно давно удивляет, что все берут для очередей редис, учитывая, что есть rabbitmq, который и более надежный, и более гибкий, и еще позволяет делать довольно просто отказоустойчивый сетап. Мне казалось, что единственное преимущество редиса — это скорость. Или вы взяли его по другой причине?
Так, по скорости, счас посмотрел у нас явно бывает больше 350 в секунду.

Редис будет быстрее рэббита если написать на нём свою очередь, состоящую из пары команд PUSH/BLPOP, в которой ничего больше нет.

Если сделать так чтобы задачи не терялись в случае любых ситуаций (воркер взял задачу и упал), а так же чтобы не было race condition при различных кейзах, а так же возврат результата работы, + статистика, мониторинг, то будет медленнее.

Проблем с надёжностью редиса не вижу. Гибкость как раз больше у редиса (если самому писать под него систему), т.к. это фактически бэкэнд для системы очередей, а не готовая система очередей.

Сложно сравнивать голый рэббит и некую систему очередей X, которая использует Redis.
По самому редису нет никаких нареканий к надёжности, и гибкости. А скорость обычно пострадает при написании системы очередей под него.
UFO just landed and posted this here

Нет кластера — нет проблем?) split brain можно словить в любом кластере, в master-slave немного сложнее, но тоже вполне можно попробовать.
Или у rabbitmq какая-то серьезная проблема именно со split brain? Вам не подошел autoheal или он не работает в вашем случае?

redis для очередей вполне production-ready решение, проверено уже на многих проектах.
При 50000 задач ежесекундно (при условии что воркеры успевают их разгребать) redis в нашем проекте потреляет 80 Мб памяти.

Если очередь перестает помещаться в память, то скорее всего происходит что-то не то: либо задачи накапливаются – что не очень хорошо, либо вы передаете в сообщениях мегабайты данных, чего тоже делать не стоит.
При 50000 задач ежесекундно (при условии что воркеры успевают их разгребать) redis в нашем проекте потреляет 80 Мб памяти.

Хм… это самописное решение или таки celery?


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

А как насчет таких случаев:


  1. В сообщениях приходится передавать большие объемы информации. Например, sentry цеплять в сообщение всю инфу по событию, которое приняло по api. Или вы предложили сначала записать это все добро в базу сырым и потом удалить оттуда?
  2. Задачи выполняются очень долго и все время, пока выполняются висят в очереди (кстати, а у вас так или вы как-то по другому удостоверяетесь в том, что задача не пропала?). К сожалению, те же задачи по интеграции с внешними сервисами могут работать внушительно долго.
  3. Задачи идут волнами. Например, есть задача "импорт с внешнего источника" и она создает большое количество задач волнами, что как бы приводит к их накоплению.

Ну и да, возвращаясь к редису — вы его как-то кластеризируете или он у вас просто так стоит как единая точка отказа?

Промазал, ответил вам ниже.
Хм… это самописное решение или таки celery?


celery, мы в таски передаем только id-шники, сообщение в таком случае и не должно занять больше 2Кб.

В сообщениях приходится передавать большие объемы информации


Все еще не совсем понятен юзекейс, зачем вы передаете в задачу всю информацию по событию? Событие в sentry все равно посылается асинхронно без задач, а в других случаях разве не нужно сохранять это событие в промежуточный сторадж (база, кэш)? Чтобы потом прочитать его в задаче по ключу? Мы у себя редко передает в параметры задач что-то больше 2Кб. Вся информация, которая нужна в задаче «достается» из каких-либо стораджей.

Задачи выполняются очень долго и все время, пока выполняются висят в очереди (кстати, а у вас так или вы как-то по другому удостоверяетесь в том, что задача не пропала?)


Мы ставим максимальный софт таймаут для некоторых задач на 5 минут, если задача работает больше – значит это ненормально и что-то пошло не так, если внешний сервис лежит, то в задачах у нах предусмотрен exponential backoff и подходящая retry policy. А что значит «не пропала»? Вы имеете ввиду гарантируем ли мы как-то что все задачи действительно выполнены? Нет не гарантируем, да и сам redis такого не гарантирует, но мы знаем об этой особенности, для нашего проекта она пока не критична.

Задачи идут волнами. Например, есть задача «импорт с внешнего источника» и она создает большое количество задач волнами, что как бы приводит к их накоплению.


Буду об этом рассказывать в своем докладе. Мы тоже несколько раз получали task flooding, поэтому поигрались с настройками и написали свой чанкификатор задач, который запускает их определенными порциями и таким образом обеспечивает равномерное накопление задач в очередях и не перегружает внутренние (например базу) и внешние сервисы.

Ну и да, возвращаясь к редису — вы его как-то кластеризируете или он у вас просто так стоит как единая точка отказа?


Пока мы кластеризуем его хуже чем нам хотелось бы, AWS обеспечивает автоматический фейловер в случае если с мастер нодой что-то случилось, но в те несколько секунд пока происходит фейловер – постановка задач фейлится, может быть какие-то окажутся потеряны. Эту проблему мы у себя пока не решили, но можно посмотреть в сторону github.com/dealertrack/celery-redis-sentinel – там есть retry в случае connection error'a.

У вас довольно интересная схема, хотя мне и кажется, что она немного читерская, потому что, исходя из того, что я понял, всю инфу по таске вы храните во внешнем источнике, получается цепочка redis -> storage -> task execution, вместо rabbitmq -> task execution. Мне сложно понять выгоду такой схемы, но выглядит интересно)


А так большое спасибо за такой развернутый ответ, довольно познавательно :)


Касательно кластеризации, немного отвратительный опыт с redis sentinel из-за того, что там нельзя разделить bind/advertise адреса. Из-за этого sentinel совсем у нас не работал.

Самая что ни на есть оптимальная схема)
Зачем тянуть в таск то что можно найти уже в воркере?
Понятно что это не панацея и от всех случаев не спасет, но сама идея весьма продуктивна и работает в продакшене как часы.
А выгода быть может тогда когда данные для успешного выполнения таска могли поменяться.
Если мы передадим в таск сразу готовый набор данных то он окажется устаревшим (Страшно подумать, но например отложенная оплата с баланса в системе или другой кошмар на выбор). И ситуация когда мы в таск передаем только тип операции, id юзера ну и id странзакции..(или id таска в БД) Воркер сам все подтянет, проверит возможность и выполнит или задеклайнит таск…
Зачем тянуть в таск то что можно найти уже в воркере?

Тут скорее "зачем класть в бд то, что можно туда не класть?". Просто в теории положить в брокер json (а иногда и msgpack) должно быть как минимум дешевле, чем acid полностью записать инфу в бд.

Кстати, по поводу кластеризации редиса, есть неплохое решение resec.
Sign up to leave a comment.