Как стать автором
Обновить

Комментарии 6

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

Тоже об этом сразу подумалось. А если публиковать в rabbit, то и партиционированием не нужно будет управлять

Тут есть 2 проблемы:

  • рассинхронизирования баз данных (основная vs. kafka) если kafka лежит

  • медленные воркеры все также блокируют все очередь (или одну partition)

Подход с transactional sandbox или BD+CDC вполне стандартный подход в данном случае.

Альтернативой может быть какой-то pub/sub, но тут надо дробить входящие сообщения. Скорее всего несколько уровней очередей - первая принять большой документ, вторая раздробить его, и дальше уже workers которые будут скачивать изображения и обновлять базу. Да и это довольно рискованная смена архитектуры по сравнение с тем, что было до обновления.

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

Что такое BD+CDC?

При старте каждый воркер будет идти в базу и в рамках своего лимита получать список id свободных задач. После этого он будет пытаться назначить эти задачи на себя — по сути, просто делать update-запрос, пытаясь проставить им свой worker_id.

видно, что скорость падает из-за лишней нагрузкой на БД из-за повторения запросов.

А какая у вас БД?

В postgresql можно использовать блокировку на строки + обновление в одном запросе. Тогда не будет перезапросов.

UPDATE
    task_table
SET 
    version = version + 1,
    available_after = now() at time zone 'utc' + @lockInterval,
    worker_id = @workerId
WHERE
    id IN (
        SELECT id
        FROM task_table
        WHERE 
            (available_after is null OR available_after < now() at time zone 'utc')
            AND completed_at is null
        ORDER BY id
        LIMIT 1000
        FOR UPDATE SKIP LOCKED
    )
RETURNING *, now() at time zone 'utc' - created_at AS Lifetime

Подзапрос ищет первые 1000 не заблокированных строк, обновление берёт строки в обработку без гонок.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий