ETL с потоком данных Spring Cloud

ETL с потоком данных Spring Cloud

1. обзор

Spring Cloud Data Flow - это облачный набор инструментов для создания конвейеров данных в реальном времени и пакетных процессов. Spring Cloud Data Flow готов для использования в различных случаях использования обработки данных, таких как простой импорт / экспорт, обработка ETL, потоковая передача событий и прогнозная аналитика.

В этом руководстве мы изучим пример извлечения, преобразования и загрузки (ETL) в реальном времени с использованием потокового конвейера, который извлекает данные из базы данных JDBC, преобразует их в простые объекты POJO и загружает их в MongoDB.

2. ETL и обработка Event-Stream

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

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

В настоящее время это можно сделать с помощьюstreams in an event-stream architecture with the help of Spring Cloud Data Flow.

3. Spring Cloud Data Flow

С помощью Spring Cloud Data Flow (SCDF) разработчики могут создавать конвейеры данных в двух вариантах:

  • Долгоживущие потоковые приложения в реальном времени, использующие Spring Cloud Stream

  • Краткосрочные пакетные приложения, использующие Spring Cloud Task

В этой статье мы расскажем о первом, долгоживущем потоковом приложении, основанном на Spring Cloud Stream.

3.1. Приложения Spring Cloud Stream

Конвейеры SCDF Stream состоят из шагов,whereeach step is an application built in Spring Boot style using the Spring Cloud Stream micro-framework.. Эти приложения интегрируются промежуточным программным обеспечением обмена сообщениями, таким как Apache Kafka или RabbitMQ.

Эти приложения подразделяются на источники, процессоры и приемники. По сравнению с процессом ETL, мы можем сказать, что источником является «извлечение», процессором является «преобразователь», а приемником является «нагрузка».

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

Список запускающих приложений можно найтиhere.

3.2. Spring Cloud Data Flow Server

The last piece of the architecture is the Spring Cloud Data Flow Server. Сервер SCDF выполняет развертывание приложений и конвейерного потока с использованием спецификации Spring Cloud Deployer. Эта спецификация поддерживает нативную облачную среду SCDF путем развертывания в различных современных средах выполнения, таких как Kubernetes, Apache Mesos, Yarn и Cloud Foundry.

Также мы можем запустить поток как локальное развертывание.

Более подробную информацию об архитектуре SCDF можно найти вhere.

4. Настройка среды

Прежде чем мы начнем, нам нужноchoose the pieces of this complex deployment. Первая часть, которую нужно определить, это сервер SCDF.

Для тестированияwe’ll use SCDF Server Local for local development. Для производственного развертывания мы позже можем выбрать облачную среду выполнения, напримерSCDF Server Kubernetes. Мы можем найти список серверных средhere.

Теперь давайте проверим системные требования для запуска этого сервера.

4.1. Системные Требования

Чтобы запустить SCDF Server, нам нужно определить и настроить две зависимости:

  • промежуточное программное обеспечение для обмена сообщениями и

  • СУРБД.

Для промежуточного программного обеспечения обмена сообщениямиwe’ll work with RabbitMQ, and we choose PostgreSQL as an RDBMS для хранения определений наших конвейерных потоков.

Для запуска RabbitMQ загрузите последнюю версиюhere и запустите экземпляр RabbitMQ, используя конфигурацию по умолчанию, или выполните следующую команду Docker:

docker run --name dataflow-rabbit -p 15672:15672 -p 5672:5672 -d rabbitmq:3-management

В качестве последнего шага установки установите и запустите СУБД PostgreSQL на порту по умолчанию 5432. После этого создайте базу данных, где SCDF может хранить свои определения потоков, используя следующий скрипт:

CREATE DATABASE dataflow;

4.2. Spring Cloud Flow Data Сервер Локальный

Для запуска SCDF Server Local мы можем выбрать запуск сервераusing docker-compose, или запустить его как приложение Java.

Here, we’ll run the SCDF Server Local as a Java application. Для настройки приложения мы должны определить конфигурацию как параметры приложения Java. Нам понадобится Java 8 в системном пути.

Для размещения файлов jar и зависимостей нам нужно создать домашнюю папку для нашего сервера SCDF и загрузить в эту папку локальный дистрибутив сервера SCDF. Вы можете загрузить самый последний дистрибутив SCDF Server Localhere.

Также нам нужно создать папку lib и поместить туда драйвер JDBC. Доступна последняя версия драйвера PostgreSQLhere.

Наконец, давайте запустим локальный сервер SCDF:

$java -Dloader.path=lib -jar spring-cloud-dataflow-server-local-1.6.3.RELEASE.jar \
    --spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/dataflow \
    --spring.datasource.username=postgres_username \
    --spring.datasource.password=postgres_password \
    --spring.datasource.driver-class-name=org.postgresql.Driver \
    --spring.rabbitmq.host=127.0.0.1 \
    --spring.rabbitmq.port=5672 \
    --spring.rabbitmq.username=guest \
    --spring.rabbitmq.password=guest

Мы можем проверить, работает ли он, посмотрев на этот URL:

4.3. Оболочка потока данных Spring Cloud

Оболочка SCDF - этоcommand line tool that makes it easy to compose and deploy our applications and pipelines. Эти команды оболочки выполняются через сервер потока данных Spring CloudREST API.

Загрузите последнюю версию jar-файла в домашнюю папку SCDF, доступнуюhere.. После этого выполните следующую команду (обновите версию при необходимости):

$ java -jar spring-cloud-dataflow-shell-1.6.3.RELEASE.jar
  ____                              ____ _                __
 / ___| _ __  _ __(_)_ __   __ _   / ___| | ___  _   _  __| |
 \___ \| '_ \| '__| | '_ \ / _` | | |   | |/ _ \| | | |/ _` |
  ___) | |_) | |  | | | | | (_| | | |___| | (_) | |_| | (_| |
 |____/| .__/|_|  |_|_| |_|\__, |  \____|_|\___/ \__,_|\__,_|
  ____ |_|    _          __|___/                 __________
 |  _ \  __ _| |_ __ _  |  ___| | _____      __  \ \ \ \ \ \
 | | | |/ _` | __/ _` | | |_  | |/ _ \ \ /\ / /   \ \ \ \ \ \
 | |_| | (_| | || (_| | |  _| | | (_) \ V  V /    / / / / / /
 |____/ \__,_|\__\__,_| |_|   |_|\___/ \_/\_/    /_/_/_/_/_/


Welcome to the Spring Cloud Data Flow shell. For assistance hit TAB or type "help".
dataflow:>

Если вместо «dataflow:>” вы получите«server-unknown:>” в последней строке, значит, вы не запускаете сервер SCDF на локальном хосте. В этом случае выполните следующую команду для подключения к другому хосту:

server-unknown:>dataflow config server http://{host}

Теперь Shell подключена к SCDF-серверу, и мы можем запускать наши команды.

Первое, что нам нужно сделать в Shell, - это импортировать стартеры приложений. Найдите последнюю версиюhere для RabbitMQ + Maven в Spring Boot 2.0.x и выполните следующую команду (снова обновите версию, здесь «Darwin-SR1», если необходимо):

$ dataflow:>app import --uri http://bit.ly/Darwin-SR1-stream-applications-rabbit-maven

Для проверки установленных приложений выполните следующую команду Shell:

$ dataflow:> app list

В результате мы должны увидеть таблицу, содержащую все установленные приложения.

Кроме того, SCDF предлагает графический интерфейс с именемFlo, к которому мы можем получить доступ по этому адресу:http://localhost:9393/dashboard. Однако его использование не рассматривается в данной статье.

5. Составление ETL-конвейера

Теперь давайте создадим наш потоковый конвейер. Для этого мы воспользуемся стартером приложения JDBC Source для извлечения информации из нашей реляционной базы данных.

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

5.1. Извлечение - подготовка реляционной базы данных для извлечения

Давайте создадим базу данных с именемcrm и таблицу с именемcustomer:

CREATE DATABASE crm;
CREATE TABLE customer (
    id bigint NOT NULL,
    imported boolean DEFAULT false,
    customer_name character varying(50),
    PRIMARY KEY(id)
)

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

Теперь давайте вставим некоторые данные:

INSERT INTO customer(id, customer_name, imported) VALUES (1, 'John Doe', false);

5.2. Transform - Отображение полей JDBC в структуру полей MongoDB

На этапе преобразования мы сделаем простой перевод поляcustomer_name из исходной таблицы в новое полеname. Здесь можно выполнить и другие преобразования, но давайте оставим пример кратким.

To do this, we’ll create a new project with the name customer-transform. Самый простой способ сделать это - использовать сайтSpring Initializr для создания проекта. После перехода на веб-сайт выберите группу и название артефакта. Мы будем использоватьcom.customer иcustomer-transform, соответственно.

Как только это будет сделано, нажмите кнопку «Создать проект», чтобы загрузить проект. Затем разархивируйте проект и импортируйте его в свою любимую среду IDE и добавьте следующую зависимость кpom.xml:


    org.springframework.cloud
    spring-cloud-stream-binder-rabbit

Теперь мы готовы начать кодирование преобразования имени поля. Для этого мы создадим классCustomer, который будет действовать как адаптер. Этот класс получитcustomer_name через методsetName() и выведет его значение через методgetName.

Саннотации@JsonProperty выполнят преобразование при десериализации из JSON в Java:

public class Customer {

    private Long id;

    private String name;

    @JsonProperty("customer_name")
    public void setName(String name) {
        this.name = name;
    }

    @JsonProperty("name")
    public String getName() {
        return name;
    }

    // Getters and Setters
}

Процессор должен получать данные от входа, выполнять преобразование и связывать результат с выходным каналом. Для этого создадим класс:

import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.integration.annotation.Transformer;

@EnableBinding(Processor.class)
public class CustomerProcessorConfiguration {

    @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
    public Customer convertToPojo(Customer payload) {

        return payload;
    }
}

В приведенном выше коде мы можем наблюдать, что преобразование происходит автоматически. На вход поступают данные в формате JSON, и Джексон десериализует их в объектCustomer с помощью методовset.

Напротив, для вывода данные сериализуются в JSON с использованием методовget.

5.3. Загрузка - Мойка в MongoDB

Аналогично шагу преобразованияwe’ll create another maven project, now with the name customer-mongodb-sink. Снова откройтеSpring Initializr, для группы выберитеcom.customer, а для артефакта выберитеcustomer-mongodb-sink. Затем введитеMongoDB * «* в поле поиска зависимостей и загрузите проект.

Затем разархивируйте и импортируйте его в свою любимую IDE.

Затем добавьте ту же дополнительную зависимость, что и в проектеcustomer-transform.

Теперь мы создадим еще один классCustomer для получения входных данных на этом этапе:

import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection="customer")
public class Customer {

    private Long id;
    private String name;

    // Getters and Setters
}

Для сниженияCustomer мы создадим класс Listener, который сохранит сущность клиента с помощьюCustomerRepository:

@EnableBinding(Sink.class)
public class CustomerListener {

    @Autowired
    private CustomerRepository repository;

    @StreamListener(Sink.INPUT)
    public void save(Customer customer) {
        repository.save(customer);
    }
}

ИCustomerRepository, в этом случае,MongoRepository из Spring Data:

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CustomerRepository extends MongoRepository {

}

5.4. Определение потока

Теперьboth custom applications are ready to be registered on SCDF Server.. Для этого скомпилируйте оба проекта с помощью команды Mavenmvn install.

Затем мы регистрируем их, используя оболочку потока данных Spring Cloud:

app register --name customer-transform --type processor --uri maven://com.customer:customer-transform:0.0.1-SNAPSHOT
app register --name customer-mongodb-sink --type sink --uri maven://com.customer:customer-mongodb-sink:jar:0.0.1-SNAPSHOT

Наконец, давайте проверим, хранятся ли приложения в SCDF, запустите команду списка приложений в оболочке:

app list

В результате мы должны увидеть оба приложения в итоговой таблице.

5.4.1. Домен-ориентированный язык потокового конвейера - DSL

DSL определяет конфигурацию и поток данных между приложениями. SCLF DSL прост. В первом слове мы определяем имя приложения, за которым следуют конфигурации.

Кроме того, синтаксис - вдохновленный UnixPipeline syntax, который использует вертикальные полосы, также известные как «каналы», для соединения нескольких приложений:

http --port=8181 | log

Это создает приложение HTTP, обслуживаемое в порту 8181, которое отправляет любую полученную полезную нагрузку тела в журнал.

Теперь давайте посмотрим, как создать определение потока DSL для источника JDBC.

5.4.2. Определение исходного потока JDBC

Ключевые конфигурации для источника JDBC:query иupdate. query will select unread records while update will change a flag to prevent the current records from being reread.

Кроме того, мы определим источник JDBC для опроса с фиксированной задержкой в ​​30 секунд и опроса не более 1000 строк. Наконец, мы определим конфигурации подключения, такие как драйвер, имя пользователя, пароль и URL подключения:

jdbc 
    --query='SELECT id, customer_name FROM public.customer WHERE imported = false'
    --update='UPDATE public.customer SET imported = true WHERE id in (:id)'
    --max-rows-per-poll=1000
    --fixed-delay=30 --time-unit=SECONDS
    --driver-class-name=org.postgresql.Driver
    --url=jdbc:postgresql://localhost:5432/crm
    --username=postgres
    --password=postgres

Дополнительные свойства конфигурации источника JDBC можно найти вhere.

5.4.3. Определение входящего потока клиента MongoDB

Поскольку мы не определяли конфигурации подключения вapplication.properties изcustomer-mongodb-sink, мы будем настраивать через параметры DSL.

Наше приложение полностью основано наMongoDataAutoConfiguration.. Вы можете проверить другие возможные конфигурацииhere. По сути, мы определимspring.data.mongodb.uri:

customer-mongodb-sink --spring.data.mongodb.uri=mongodb://localhost/main

5.4.4. Создать и развернуть поток

Во-первых, чтобы создать окончательное определение потока, вернитесь в командную консоль и выполните следующую команду (без разрывов строк они просто вставлены для удобства чтения):

stream create --name jdbc-to-mongodb
  --definition "jdbc
  --query='SELECT id, customer_name FROM public.customer WHERE imported=false'
  --fixed-delay=30
  --max-rows-per-poll=1000
  --update='UPDATE customer SET imported=true WHERE id in (:id)'
  --time-unit=SECONDS
  --password=postgres
  --driver-class-name=org.postgresql.Driver
  --username=postgres
  --url=jdbc:postgresql://localhost:5432/crm | customer-transform | customer-mongodb-sink
  --spring.data.mongodb.uri=mongodb://localhost/main"

Этот DSL потока определяет поток с именем jdbc-to-mongodb. Далееwe’ll deploy the stream by its name:

stream deploy --name jdbc-to-mongodb

Наконец, мы должны увидеть расположение всех доступных журналов в выводе журнала:

Logs will be in {PATH_TO_LOG}/spring-cloud-deployer/jdbc-to-mongodb/jdbc-to-mongodb.customer-mongodb-sink

Logs will be in {PATH_TO_LOG}/spring-cloud-deployer/jdbc-to-mongodb/jdbc-to-mongodb.customer-transform

Logs will be in {PATH_TO_LOG}/spring-cloud-deployer/jdbc-to-mongodb/jdbc-to-mongodb.jdbc

6. Заключение

В этой статье мы рассмотрели полный пример конвейера данных ETL с использованием Spring Cloud Data Flow.

Наиболее примечательно, что мы увидели конфигурации начального уровня приложения, создали потоковый конвейер ETL с использованием Spring Cloud Data Flow Shell и реализовали пользовательские приложения для нашего чтения, преобразования и записи данных.

Как всегда, пример кода можно найтиin the GitHub project.