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

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

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

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

Что лучший способ состоит в том, чтобы запланировать повторяющиеся задачи в масштабе?

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

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

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

16
задан wehriam 17 March 2010 в 02:36
поделиться

5 ответов

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

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

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

5
ответ дан 30 November 2019 в 23:14
поделиться

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

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

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

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

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

3
ответ дан 30 November 2019 в 23:14
поделиться

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

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

Цитирую

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

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

0
ответ дан 30 November 2019 в 23:14
поделиться

350 000 задач * 48 раз в день - это 16 800 000 задач, выполняемых в день.

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

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

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

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

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

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

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

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

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

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

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

1
ответ дан 30 November 2019 в 23:14
поделиться

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

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

1
ответ дан 30 November 2019 в 23:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: