Pull to refresh

Comments 9

Мастер периодически рассылает heartbeat сообщения всем воркерам. Если воркер не ответил на сообщение определенное количество раз, то он считается недоступным, и все выполняемые на нем задачи планируются на другие доступные воркеры. Аналогично задачи, которые вернули код ошибки или аварийно завершились, планируются на другие доступные воркеры.


Представьте себе ситуацию, когда вы на время (например, в течение нескольких минут) исчерпали все доступные ресурсы по CPU или по сети в кластере, и ваши воркеры начали таймаутиться. После этого, если я правильно понял алгоритм, все задания будут запускаться во втором, третьем и т.д. экземплярах на всё ещё живых нодах, пока их тоже не вырубит?

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

Если пытаться решать эту проблему, тогда нужно динамически менять таймаут в сторону увеличения. Для этого нужна обратная связь от запущенного процесса. Как понять процесс завис в infinite loop или уперся в железо? А если увеличить таймаут, то возникает вопрос: нужно ли уменьшать таймаут после того, когда ресурсы освободятся? Не совсем ясно как решать проблему с каскадным отключением автоматически в общем случае.
В нашей системе (которую мы, в отдаленной перспективе, планировали тоже заопенсорсить) мы не перезапускаем процесс, пока не вышло максимальное время его исполнения. Ну и также, если хост живой, мы периодически сверяем список запущенных процессов на сервере и список запущенных задач в планировщике. У нас есть отдельный механизм, который гарантирует, что задание будет убито спустя указанный промежуток времени, и основывается он на системном вызове alarm() и на запрете перехвата сигналов процессом. Наши приложения представляют из себя PHP, поэтому это работает. Для других языков, я думаю, можно придумать что-нибудь похожее.

На самом деле, проблема очень сложная для решения, потому что фактически невозможно отличить недоступность хоста и недоступность, к примеру, сети до хоста. То есть, практически невозможно убедиться, что 2 экземпляра программы не запущено одновременно. Для нас это было критично, поэтому мы используем описанное выше решение.
У нас есть отдельный механизм, который гарантирует, что задание будет убито спустя указанный промежуток времени, и основывается он на системном вызове alarm() и на запрете перехвата сигналов процессом.

А когда вы убиваете процесс, что вы делаете с дочерними процессами, которые мог породить убиваемый процесс? Или в unix'е они самоубьются? Боролся с этим на windows и никакой приличной стратегии не нашёл, кроме как не порождать дочерних процессов из процесса под шедулером :)
Все верно — у нас запрещен fork(). То есть, если нужно запустить еще процессов, то разработчики должны использовать API по добавлению новых заданий, которые, при правильных настройках, могут попасть и на тот же хост.
А есть ли информация по производительности описанного планировщика?
Сколько job'ов он может одновременно обрабатывать/отслеживать?
На воркере каждый запуск задачи порождает процесс. Пара fork+exec занимает порядка 10 мс. Т.е. приблизительно 100 запусков hello-world задачи с одного ядра. Такие ограничения для воркера.

Есть синтетический нагрузочный тест ptest_load, который проверяет отдельно алгоритм планирования мастера. Этот тест симулирует планирование 100k задач на 10k воркеров. Это однопоточный тест и на моем железе планировалось где-то 4.5k задач в секунду.
Sign up to leave a comment.

Articles

Change theme settings