Как запланировать сотни тысяч задач? - PullRequest
15 голосов
/ 17 марта 2010

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

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

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

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

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

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

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

Ответы [ 5 ]

5 голосов
/ 17 марта 2010

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

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

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

3 голосов
/ 17 марта 2010

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

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

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

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

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

1 голос
/ 17 марта 2010

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

Для планирования заданий вам не нужна база данных.

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

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

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

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

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

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

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

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

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

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

1 голос
/ 17 марта 2010

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

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

0 голосов
/ 17 марта 2010

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

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

Цитирование

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...