Контекст
У меня есть инфраструктура, в которой сервер создает долго выполняющиеся задания, где каждое задание состоит из логических кусков примерно одинакового размера, но каждое задание имеет совершенно различное количество кусков. У меня есть масштабируемое количество рабочих, которые могут выполнять работу по частям (загрузка процессора) и возвращать результат на сервер. Один рабочий одновременно работает только с одним чанком.
В настоящее время для планирования чанков я использую очередь SQS, поэтому при создании задания я сбрасываю все чанки в очередь SQS, и рабочие берут чанки. Он работает как FIFO.
Итак, чтобы подвести итог, что делает, что:
A job - это много ресурсоемких вычислений. Он состоит из нескольких независимых блоков, которые имеют примерно одинаковый размер.
A chunk - это вычисление с интенсивным использованием процессора, с которым могут работать работники. Независимо от других блоков и может быть вычислен сам без дополнительного контекста.
Сервер создает задания. Когда задание создано, сервер помещает все чанки задания в очередь (и, по существу, забывает о заданиях).
worker может работать с чанками. Неважно, какая работа является основной частью, рабочий может взять на себя любую. Рабочий, когда ему не с чем работать (он только что создан или уже завершил предыдущий чанк) ищет следующий чанк в очереди.
Проблема
Когда все задания запланированы чанки добавляются в очередь, и когда запланировано следующее задание, оно не будет запущено до тех пор, пока не будет выполнено первое задание. Таким образом, в сценарии, где задание A (первое) занимает 4 часа, а задание B (второе) занимает 5 минут, задание B не запустится в первые несколько часов и будет только завершается примерно через 4 часа 5 минут, поэтому, если запланировано большое задание, оно эффективно заблокирует все остальные вычисления. Очередь будет выглядеть следующим образом:
A1 A2 A3 A4 A5 A6 A7 A8 A9 A9 ... A100 B1 B2
Я хотел бы не блокировать поступающие новые вычисления, а обработать их в другой порядок, например:
A1 B1 A2 B2 A3 A4 A5 A6 A7 A8 A9 A10 ... A100
Если третья работа поступает после того, как A1 и B1 были получены, она должна не блокируется:
A2 B2 C1 A3 C2 A4 C3 A5 C4 A6 A7 A8 A9 A10 ... A100
При заказе таких кусков я могу гарантировать следующее:
- Для каждой работы первое задание выбирается относительно быстро.
- Для каждой работы наблюдается постоянный ощутимый прогресс (некоторые новые куски всегда завершаются)
- Короткие работы (не много фрагменты) заканчиваются относительно быстро.
Решения
Я знаю, что не могу переупорядочить очередь SQS сама по себе, поэтому мне, возможно, придется сделать что-то вроде:
- Изменение технологий. Может быть, какая-то очередь поддерживает это "из коробки" в AWS
- Когда планируется запланировать новое задание, сервер просто берет все порции из очереди, перемешивает в новых порциях, возвращает все в queue.
- Каким-то образом достичь желаемого поведения с помощью приоритетной очереди (возможно, RabbitMQ).
Есть ли какое-то простое и безопасное решение для этого? как мне это сделать?