Паттерн Periodic Job (Периодическое задание) расширяет паттерн Batch Job (Пакетное задание), добавляя измерение времени и позволяя выполнять единицу работы по временным событиям.
В мире распределенных систем и микросервисов наблюдается явное стремление к организации взаимодействий и обмену событиями между приложениями в режиме реального времени с использованием HTTP и упрощенных механизмов обмена сообщениями. Однако, независимо от последних тенденций в разработке программного обеспечения, планирование заданий имеет долгую историю и продолжает оставаться актуальным. Паттерн Periodic Job (Периодическое задание) обычно используется для автоматизации обслуживания системы и решения административных задач. Он также применяется в бизнес-приложениях, требующих периодического выполнения определенных задач. Типичными примерами могут служить интеграция между системами посредством передачи файлов, интеграция приложений посредством периодического опроса баз данных, отправка электронных писем с новостями, а также архивация и удаление старых файлов.
Традиционно для периодического выполнения заданий с целью обслуживания системы используется специализированное программное обеспечение — планировщик Cron. Однако специализированное программное обеспечение может оказаться избыточным для простых случаев использования, к тому же задания Cron, выполняемые на единственном сервере, трудно поддерживать, так как они представляют собой единую точку отказа. Вот почему очень часто разработчики стремятся реализовать решения, которые способны осуществлять планирование и выполнять необходимую бизнес-логику. Например, в мире Java выполнение заданий с привязкой ко времени можно организовать с использованием библиотек, таких как Quartz и Spring Batch, или пользовательских реализаций на основе класса ScheduledThreadPoolExecutor. Но, как и в случае с Cron, основная сложность этого подхода состоит в том, чтобы сделать механизм планирования устойчивым и высокодоступным, а это влечет значительное потребление ресурсов. Кроме того, при таком подходе планировщик заданий является частью приложения, и чтобы обеспечить высокую доступность планировщика, нужно обеспечить высокую доступность всего приложения. Обычно ради этого приходится запускать несколько экземпляров приложения, но так, чтобы активно занимался планированием только один экземпляр, а это требует реализации алгоритма выбора лидера и решения других проблем, характерных для распределенных систем.
В конце концов, простая служба, которая должна скопировать несколько файлов один раз в день, может потребовать нескольких узлов, распределенного механизма выбора лидера и многого другого. Реализация контроллера CronJob в Kubernetes решает все эти проблемы и позволяет планировать ресурсы Job с помощью хорошо известного формата описания заданий, используемого планировщиком Cron. Это дает возможность разработчикам сосредоточиться только на реализации выполняемой работы, а не на аспектах планирования с привязкой ко времени.
В главе 7 «Пакетное задание» мы познакомились с возможностями и вариантами использования поддержки заданий Job в Kubernetes. Все, о чем рассказывалось там, относится и к этой главе, потому что примитив CronJob основан на Job. Экземпляр CronJob напоминает строку в файле crontab в Unix (таблица заданий планировщика cron) и управляет аспектами выполнения задания, связанными со временем. Он позволяет периодически выполнять задание в определенные моменты времени. Образец определения такого периодического задания приводится в листинге 8.1.
Листинг 8.1. Ресурс CronJob
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: random-generator
spec:
# Через каждые три минуты
schedule: "*/3 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
command: [ "java", "-cp", "/", "RandomRunner",
"/numbers.txt", "10000" ]
restartPolicy: OnFailure
Инструкция для Cron, требующая запускать задание каждые три минуты.
Паттерн задания, имеет ту же структуру, что и описание обычного задания Job.
Кроме описания задания Job, в определении CronJob имеются дополнительные параметры для определения привязки ко времени:
Строка в формате crontab, определяющая планирование задания Job с привязкой ко времени (например, "0 * * * *" требует запускать задание в начале каждого часа).
Крайний срок (в секундах) запуска задания, если было пропущено запланированное время. Некоторые задания допустимо выполнять только в течение определенного отрезка времени и бессмысленно запускать позднее. Например, если задание не было запущено в нужное время из-за недостатка вычислительных ресурсов или отсутствия других условий, иногда лучше пропустить выполнение, потому что данные, которые должно обработать это задание, уже устарели.
Определяет порядок управления одновременным выполнением заданий, созданных одним и тем же CronJob. Значение по умолчанию Allow (разрешить) позволяет запускать новые экземпляры заданий, даже если предыдущие задания еще не завершились. Если такое поведение нежелательно, можно указать в этом параметре значение Forbid (запретить), чтобы пропустить запуск нового экземпляра задания, или значение Replace (заменить), чтобы остановить прежний экземпляр задания и запустить новый.
Этот параметр приостанавливает запуск новых экземпляров задания, но не влияет на уже запущенные.
Эти поля определяют, сколько заданий, выполнившихся успешно и завершившихся с ошибкой, следует сохранить для исследования.
CronJob — это узкоспециализированный примитив и применяется, только когда единица работы имеет временное измерение. Даже при том, что CronJob не является примитивом общего назначения, он служит отличным примером того, как механизмы Kubernetes основываются друг на друге и поддерживают сценарии использования, не связанные с облачными вычислениями.
Как видите, CronJob — это довольно простой примитив, добавляющий кластерное Cron-подобное поведение к существующему механизму заданий Job. Но когда в сочетании с другими примитивами, такими как Pod, средствами изоляции ресурсов контейнера и другими особенностями Kubernetes, например, описанными в главе 6 «Автоматическое размещение» или в главе 4 «Проверка работоспособности», он превращается в очень мощную систему планирования заданий. Это позволяет разработчикам сосредоточиться исключительно на предметной области и заняться реализацией контейнерного приложения, отвечающей только за выполнение бизнес-логики. Планирование осуществляется за рамками приложения и является частью платформы со всеми ее дополнительными преимуществами, такими как высокая доступность, отказоустойчивость, емкость и размещение подов на основе политик. Конечно, по аналогии с реализацией зданий Job, при реализации контейнера для выполнения под управлением CronJob следует учитывать все тупиковые ситуации: повторные запуски, пропуск запусков, параллельные запуски или принудительная остановка.
• Пример периодически выполняемого задания (http://bit.ly/2HGXAnh).
• Описание механизма CronJob (https://kubernetes.io/docs/concepts/jobs/cron-jobs/).
• Описание планировщика cron в Unix (https://ru.wikipedia.org/wiki/Cron).