Перейти к содержимому
Последнее обновление

Планировщик заданий (Job Scheduler)

Обзор​

Встроенный в Apache Doris Job Scheduler — это система управления заданиями, которая выполняет их по заранее заданному расписанию. Она автоматически запускает операции SQL в указанные моменты времени или через фиксированные интервалы без использования внешних инструментов планирования. Начиная с версии 2.1, Job Scheduler обеспечивает точность планирования до секунды.

Типичные сценарии использования:

  • Периодическая загрузка данных и обработка ETL с меньшим объёмом ручной работы
  • Периодическая синхронизация данных между несколькими источниками совместно с Multi-Catalog
  • Периодическое удаление устаревших или некорректных данных для освобождения места в хранилище
  • Периодическое обновление асинхронных материализованных представлений

Основные возможности:

ВозможностьОписание
Точность до секундыИспользует алгоритм TimingWheel для запуска событий с точностью до секунды
Гибкое планированиеПоддерживает однократное и периодическое выполнение; для периодических заданий можно указать время начала и окончания
Высокопроизводительная очередьИспользует Disruptor для построения высокопроизводительной модели с производителями и потребителями, предотвращая перегрузку при выполнении
История выполненияХранит записи о последних выполнениях задач Task (количество записей настраивается), которые можно просмотреть с помощью команд
Высокая доступностьИспользует собственный механизм высокой доступности Doris и поддерживает автоматическое восстановление после сбоев

Связанная документация: CREATE JOB


Синтаксис​

Полный оператор создания задания Job состоит из следующих трёх частей:

CREATE JOB job_name
ON SCHEDULE schedule
[COMMENT 'string']
DO execute_sql;

schedule: {
AT timestamp
| EVERY interval
[STARTS timestamp]
[ENDS timestamp]
}

interval:
quantity { WEEK | DAY | HOUR | MINUTE }

Элементы синтаксиса:

КонструкцияОписание
CREATE JOB job_nameЗадаёт имя задания Job, которое однозначно идентифицирует его в базе данных
ON SCHEDULE AT timestampОднократное выполнение: задание выполняется один раз в указанный момент времени. Для немедленного выполнения используйте CURRENT_TIMESTAMP
ON SCHEDULE EVERY intervalПериодическое выполнение: задание повторяется через указанный интервал
STARTS timestamp(Необязательно) Время начала периодического выполнения. Для немедленного запуска используйте CURRENT_TIMESTAMP
ENDS timestamp(Необязательно) Время окончания периодического выполнения
DO execute_sqlОператор SQL, выполняемый при срабатывании расписания (в настоящее время поддерживаются только операторы INSERT)

Поддерживаемые единицы интервала: WEEK, DAY, HOUR, MINUTE


Примеры​

Однократное задание​

Выполнить задание один раз в 2025-01-01 00:00:00, чтобы загрузить данные из db2.tbl2 в db1.tbl1:

CREATE JOB my_job
ON SCHEDULE AT '2025-01-01 00:00:00'
DO INSERT INTO db1.tbl1 SELECT * FROM db2.tbl2;

Периодическое задание (без времени окончания)​

Начиная с 2025-01-01 00:00:00, выполнять инкрементальную загрузку один раз в день:

CREATE JOB my_job
ON SCHEDULE EVERY 1 DAY
STARTS '2025-01-01 00:00:00'
DO INSERT INTO db1.tbl1
SELECT * FROM db2.tbl2
WHERE create_time >= days_add(now(), -1);

Периодическое задание (со временем окончания)​

Выполнять ежедневную загрузку начиная с 2025-01-01 и автоматически прекратить её в 2026-01-01 00:10:00:

CREATE JOB my_job
ON SCHEDULE EVERY 1 DAY
STARTS '2025-01-01 00:00:00'
ENDS '2026-01-01 00:10:00'
DO INSERT INTO db1.tbl1
SELECT * FROM db2.tbl2
WHERE create_time >= days_add(now(), -1);

Асинхронное выполнение​

Задания Job создаются в Doris синхронно, а само выполнение происходит асинхронно. Поэтому Job подходят для асинхронных задач, таких как длительные операции INSERT INTO SELECT.

Задайте время начала с помощью CURRENT_TIMESTAMP, и задание Job запустится асинхронно сразу после создания:

CREATE JOB my_job
ON SCHEDULE AT CURRENT_TIMESTAMP
DO INSERT INTO db1.tbl1 SELECT * FROM db2.tbl2;

Автоматическая синхронизация данных с помощью Catalog и Job Scheduler​

Рассмотрим сценарий электронной коммерции, в котором нужно периодически извлекать бизнес-данные из MySQL и синхронизировать их с Doris для аналитики, используемой в целевом маркетинге. Job Scheduler совместно с Multi-Catalog позволяет эффективно выполнять периодическую синхронизацию данных между источниками.

Шаг 1: Подготовьте исходные данные в MySQL

Предположим, что в MySQL существует следующая таблица активности пользователей:

CREATE TABLE IF NOT EXISTS user.activity (
`user_id` INT NOT NULL,
`date` DATE NOT NULL,
`city` VARCHAR(20),
`age` SMALLINT,
`sex` TINYINT,
`last_visit_date` DATETIME DEFAULT '1970-01-01 00:00:00',
`cost` BIGINT DEFAULT '0',
`max_dwell_time` INT DEFAULT '0',
`min_dwell_time` INT DEFAULT '99999'
);

INSERT INTO user.activity VALUES
(10000, '2017-10-01', 'Beijing', 20, 0, '2017-10-01 06:00:00', 20, 10, 10),
(10000, '2017-10-01', 'Beijing', 20, 0, '2017-10-01 07:00:00', 15, 2, 2),
(10001, '2017-10-01', 'Beijing', 30, 1, '2017-10-01 17:05:00', 2, 22, 22),
(10002, '2017-10-02', 'Shanghai', 20, 1, '2017-10-02 12:59:00', 200, 5, 5),
(10003, '2017-10-02', 'Guangzhou', 32, 0, '2017-10-02 11:20:00', 30, 11, 11),
(10004, '2017-10-01', 'Shenzhen', 35, 0, '2017-10-01 10:00:00', 100, 3, 3),
(10004, '2017-10-03', 'Shenzhen', 35, 0, '2017-10-03 10:20:00', 11, 6, 6);
user_iddatecityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-01Beijing2002017-10-01 06:00:00201010
100002017-10-01Beijing2002017-10-01 07:00:001522
100012017-10-01Beijing3012017-10-01 17:05:0022222
100022017-10-02Shanghai2012017-10-02 12:59:0020055
100032017-10-02Guangzhou3202017-10-02 11:20:00301111
100042017-10-01Shenzhen3502017-10-01 10:00:0010033
100042017-10-03Shenzhen3502017-10-03 10:20:001166

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

Шаг 2: Создайте целевую таблицу в Doris

CREATE TABLE IF NOT EXISTS user_activity (
`user_id` LARGEINT NOT NULL COMMENT "User id",
`date` DATE NOT NULL COMMENT "Data ingestion date",
`city` VARCHAR(20) COMMENT "User city",
`age` SMALLINT COMMENT "User age",
`sex` TINYINT COMMENT "User gender",
`last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "Last visit time",
`cost` BIGINT SUM DEFAULT "0" COMMENT "Total spending",
`max_dwell_time` INT MAX DEFAULT "0" COMMENT "Maximum dwell time",
`min_dwell_time` INT MIN DEFAULT "99999" COMMENT "Minimum dwell time"
)
AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

Шаг 3: Создайте Catalog для MySQL

CREATE CATALOG activity PROPERTIES (
"type" = "jdbc",
"user" = "root",
"password" = "123456",
"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/user?useSSL=false",
"driver_url" = "mysql-connector-java-5.1.49.jar",
"driver_class" = "com.mysql.jdbc.Driver"
);

Шаг 4: Создайте задания Job для синхронизации данных по расписанию

Полная загрузка может вызывать колебания нагрузки на систему, поэтому её обычно планируют на часы низкой нагрузки, например на раннее утро.

  • Однократное выполнение (полная загрузка, запускаемая один раз в 3:00 утра):

    CREATE JOB one_time_load_job
    ON SCHEDULE AT '2024-08-10 03:00:00'
    DO INSERT INTO user_activity
    SELECT * FROM activity.user.activity;
  • Периодическое выполнение (ежедневная инкрементальная синхронизация последних данных):

    CREATE JOB schedule_load
    ON SCHEDULE EVERY 1 DAY
    DO INSERT INTO user_activity
    SELECT * FROM activity.user.activity
    WHERE last_visit_date >= days_add(now(), -1);

Архитектура и реализация​

Высокая точность планирования сопряжена с большим потреблением ресурсов. Традиционные решения Java на основе потоков с планированием не обеспечивают достаточной точности и расходуют слишком много памяти. Для решения этой проблемы Job Scheduler сочетает алгоритм TimingWheel и Disruptor, обеспечивая высокую производительность при низком потреблении ресурсов.

Основные механизмы:

  1. Запуск событий с помощью колеса таймеров: алгоритм колеса таймеров реализован с использованием HashedWheelTimer из Netty. Job Manager заранее загружает будущие события в колесо таймеров для планирования каждые десять минут (по умолчанию).
  2. Диспетчеризация через Disruptor: колесо таймеров только инициирует события и не выполняет задачи напрямую. Задачи, для которых наступило время выполнения, сначала поступают в поток Dispatch, который передаёт их в соответствующий пул потоков выполнения. Задачи, требующие немедленного выполнения, направляются непосредственно в пул потоков выполнения.
  3. Управление жизненным циклом событий: определения событий однократных задач автоматически удаляются после завершения планирования. Для периодических задач колесо таймеров регулярно получает план выполнения на следующий цикл. Это позволяет избежать скопления большого количества задач в одной корзине и повышает эффективность обработки.
  4. Транзакционная согласованность: для транзакционных задач Job Scheduler использует тесную связь с транзакциями и механизм обратных вызовов, чтобы результаты выполнения задач соответствовали ожиданиям, а целостность данных сохранялась.

Планы развития​

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

В будущих версиях планируется добавить следующие возможности:

  • Визуализация распределения задач: пользовательский интерфейс для просмотра распределения выполнений задач по различным временным окнам.
  • Оркестрация рабочих процессов DAG: поддержка оркестрации рабочих процессов JOB (DAG JOB), позволяющая управлять зависимостями задач хранилища данных внутри Doris. В сочетании с Catalog это повысит эффективность обработки и анализа данных.
  • Поддержка дополнительных операций: выполнение по расписанию таких операций, как UPDATE и DELETE.