Как запланировать сотни тысяч задач?

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

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

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

Каков наилучший способ планирования повторяющихся задач в масштабе?

Для чего это стоит, мы в основном используем Python, хотя у нас нет проблем с использованием компонентов (RabbitMQ?), написанных на других языках.

ОБНОВЛЕНИЕ: Сейчас у нас есть около 350 000 задач, которые запускаются каждые полчаса или около того с некоторыми изменениями. 350 000 заданий * 48 раз в день - 16 800 000 заданий, выполняемых в день.

ОБНОВЛЕНИЕ 2: Нет зависимостей. Задачи не должны выполняться по порядку и не полагаться на предыдущие результаты.

Ответы

Ответ 1

Так как ACID не требуется, и вы в порядке с потенциально запущенными задачами, я бы не сохранил временные метки в базе данных. Для каждой задачи создайте список [timestamp_of_next_run, task_id] и используйте min-heap для хранения всех списков. Python heapq модуль может поддерживать кучу для вас. Вы сможете очень быстро выполнить задачу с самой быстрой отметкой времени. Когда вам нужно запустить задачу, используйте ее task_id для поиска в базе данных того, что должна выполнять задача. Когда задача завершается, обновите метку времени и верните ее в кучу. (Просто будьте осторожны, чтобы не изменить элемент, который в настоящее время находится в куче, поскольку это разрушит свойства кучи).

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

Если у вас недостаточно памяти для одновременного хранения всех задач в памяти, вы можете пойти с гибридной настройкой, где вы сохраняете задачи в течение следующих 24 часов (например) в ОЗУ и все остальное остается в базе данных. В качестве альтернативы вы можете переписать код на C или С++, которые менее голодны.

Ответ 2

Если вам не нужна база данных, вы можете сохранить только следующую метку времени выполнения и идентификатор задачи в памяти. Вы можете сохранить свойства для каждой задачи в файле с именем [task_id].txt. Вам понадобится структура данных для хранения всех задач, отсортированных по временной отметке в памяти, дерево AVL похоже, что это сработает, здесь простой для python: http://bjourne.blogspot.com/2006/11/avl-tree-in-python.html. Надеюсь, Linux (я предполагаю, что то, что вы используете) может обрабатывать миллионы файлов в каталоге, иначе вам может понадобиться хэш на идентификаторе задачи, чтобы получить подпапку).

Вашему мастер-серверу просто нужно будет запустить цикл, выталкивая задачи из дерева AVL, пока в будущем не появится следующая временная метка задачи. Затем вы можете спать несколько секунд и снова начать проверку. Всякий раз, когда запускается задача, вы обновляете следующую временную метку запуска в файле задачи и вставляете ее в дерево AVL.

Когда главный сервер перезагрузится, возникнут накладные расходы, связанные с перезагрузкой всех задач id и следующего запуска timestamp обратно в память, так что это может быть болезненно с миллионами файлов. Возможно, у вас есть только один гигантский файл и укажите каждому заданному 1K-пространству в файле свойства и следующую метку времени выполнения, а затем используйте [task_id] * 1K, чтобы перейти к правильному смещению для свойств задачи.

Если вы хотите использовать базу данных, я уверен, что MySQL может обрабатывать все, что вы на нее набрасываете, учитывая описанные вами условия, предполагая, что у вас есть 4 ГБ + ОЗУ и несколько жестких дисков в RAID 0 + 1 на вашем главном сервере.

Наконец, если вы действительно хотите усложниться, Hadoop тоже может работать: http://hadoop.apache.org/

Ответ 3

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

Кроме того, если у вас нет кластеризованного индекса на отметке времени, вы избежите иметь горячую точку в конце таблицы.

Ответ 4

350 000 заданий * 48 раз в день 16 800 000 заданий, выполняемых в день.

Чтобы запланировать задания, вам не нужна база данных.

Базы данных для вещей, которые обновлены. Единственное обновление, видимое здесь, - это изменение графика для добавления, удаления или перенастройки задания.

Cron делает это полностью масштабируемым образом с помощью одного плоского файла.

Прочитайте весь плоский файл в памяти, начните нерестовые задания. Периодически проверяйте fstat, чтобы увидеть, изменился ли файл. Или, еще лучше, дождитесь сигнала HUP и используйте это, чтобы перечитать файл. Используйте kill -HUP, чтобы сигнализировать планировщику, чтобы перечитать файл.

Непонятно, что вы обновляете базу данных для.

Если база данных используется для определения будущего расписания, основанного на завершении задания, то одна база данных является идеей очень папы.

Если вы используете базу данных для проведения анализа истории заданий, у вас есть простой хранилище данных.

  • Информация о завершении записи (время начала, время окончания, состояние выхода, все это) в простом плоском файле журнала.

  • Обработать плоские файлы журналов для создания таблицы фактов и обновлений размеров.

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

Нельзя напрямую записывать 17 000 000 строк в день в реляционную базу данных. Никто не хочет всех данных. Им нужны сводки: подсчеты и средние значения.

Ответ 5

Почему сотни тысяч, а не сотни миллионов?: Зло:

Мне кажется, вам нужен неконтактный питон, http://www.stackless.com/. созданный гением христианского Тисмера.

Цитирование

Stackless Python - улучшенный версия программирования Python язык. Это позволяет программистам воспользуйтесь преимуществами нитевидных программирование без производительности и проблемы сложности с обычными нитями. microthreads, который Stackless добавляет к Python - дешевый и легкий удобство, которое можно использовать правильно, приведите следующие преимущества: Улучшена структура программы. Больше читаемый код. Увеличенный программист производительность.

Используется для массовых многопользовательских игр.