05_Hudi는 Flink 통합, 스트리밍 쿼리, Flink SQL Writer, Flink SQL은 Kafka 통합, Flink SQL은 Hudi에 쓰기, Kafka 데이터 사용 등을 수행합니다.

이 글은 "Dark Horse Programmer" 후디 강좌에서 발췌한 것입니다.

5. Chapter 5 Hudi Flink 통합
5.1 Flink 설치 1.12
5.2 빠른 시작
5.2.1 Flink 통합 개요
5.2.2 환경 준비
5.2.3 테이블 생성
5.2.4 데이터 삽입
5.2.5 데이터 쿼리
5.2.6 데이터 업데이트
5.3 스트리밍 쿼리
5.3 .1 테이블 생성
5.3.2 데이터 쿼리
5.3.3 데이터 삽입
5.4 Flink SQL 작성기
5.4.1 Flink SQL은 Kafka 통합
5.4.2 Flink SQL은 Hudi에 쓰기
5.4.2.1 Maven 모듈 생성
5.4.2.2 Kafka 데이터 사용
5.4.2.3 데이터 저장 To Hudi
5.4.2.4 Hudi 테이블 데이터 로드
5.4.3 Flink SQL 클라이언트 Hudi에 쓰기
5.4.3.1 통합 환경
5.4.3.2 SQL 실행
5.5 Hudi CDC
5.5.1 CDC 데이터를 레이크로
5.5.2 Flink CDC Hudi
5.5.2.1 비즈니스 요구 사항
5.5 .2.2 MySQL 테이블 생성
5.5.2.3 CDC 테이블 생성
5.5.2.4 뷰 생성
5.5.2.5 Hudi 테이블 생성
5.5.2.6 Hudi 테이블에 데이터 쓰기
5.5.2.7 Hive 테이블 쿼리
5.5.3 Hudi 클라이언트 Hudi 테이블 작동

5. 5장 Hudi 통합 Flink

Hudi 버전 0.7.0부터 Flink 쓰기가 지원되고, Hudi 버전 0.8.0에서는 API 인터페이스가 리팩토링되어 Flink와 Hudi의 통합이 더욱 개선되었으며, Hudi 버전 0.9.0에서는 Flink CDC 데이터 쓰기가 지원됩니다. Flink 버전이 필요한 버전은 1.12+ 버전입니다.

  • 더 나은 성능, 더 나은 확장성을 재설계하고 Flink 상태 인덱스를 기반으로 파이프라인을 작성합니다.
  • Flink를 지원하여 MOR 테이블을 작성합니다.
  • Flink는 COW 및 MOR 테이블을 일괄적으로 읽습니다.
  • 스트리밍 읽기 MOR 테이블;
  • Hudi를 소스 및 싱크의 Flink SQL 커넥터로 지원합니다.
  • Flink CDC 데이터 작성 지원,
    공식 문서: http://hudi.apache.org/docs/flink-quick-start-guide.html

5.1 플링크 1.12 설치

Flink 1.12 버전을 사용하고, Flink Standalone 클러스터 모드를 배포하고, 서비스를 시작합니다. 단계는 다음과 같습니다.
1단계, 설치 패키지 다운로드

https://archive.apache.org/dist/flink/flink-1.12.2/

2단계. 소프트웨어 패키지
flink-1.12.2-bin-scala_2.12.tgz를 node1의 지정된 디렉터리에 업로드합니다.

step3, 압축을 푼다

tar -zxvf flink-1.12.2-bin-scala_2.12.tgz 
chown -R root:root /export/server/flink-1.12.2/

4단계, 소프트 링크 생성
ln -s flink-1.12.2 flink

5단계. hadoop 종속 jar 패키지 추가
cd /export/server/flink/lib
rz를 사용하여 jar 패키지 업로드: flink-shaded-hadoop-2-uber-2.7.5-10.0.jar

6단계, HDFS 클러스터 시작

hadoop-daemon.sh start namenode
hadoop-daemon.sh start datanode

7단계, Flink 로컬 클러스터 시작

/export/server/flink/bin/start-cluster.sh

jps를 사용하여 다음 두 프로세스를 확인하세요.
여기에 이미지 설명을 삽입하세요

플링크 중지

/export/server/flink/bin/stop-cluster.sh

8단계, Flink의 웹 UI에 액세스

URL: http://node1.itcast.cn:8081/#/개요
여기에 이미지 설명을 삽입하세요

step9.공식 예제 실행
텍스트 파일 데이터를 읽고 단어 빈도 통계 WordCount를 수행한 후 결과를 콘솔에 인쇄합니다.

/export/server/flink/bin/flink run /export/server/flink/examples/batch/WordCount.jar

여기에 이미지 설명을 삽입하세요

5.2 빠른 시작

Flink를 기반으로 Hudi 테이블 데이터를 운용하고 쿼리 분석을 수행하며, 소프트웨어 버전 설명은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

5.2.1 Flink 통합 개요

Flink가 Hudi를 통합하면 기본적으로 Flink 애플리케이션 CLASSPATH 아래에 배치될 수 있는 jar 패키지인 hudi-flink-bundle_2.12-0.9.0.jar 을 통합합니다 . Flink SQLConnector가 Hudi를 소스 및 싱크로 지원하는 경우 jar 패키지를 CLASSPATH 경로에 넣는 두 가지 방법이 있습니다.

  • 방법 1: Flink SQL 클라이언트 명령줄을 실행할 때 [ -j xx.jar ] 매개변수를 통해 jar 패키지를 지정합니다.
    여기에 이미지 설명을 삽입하세요

  • 방법 2: jar 패키지를 Flink 소프트웨어 설치 패키지 [$FLINK_HOME/lib]의 lib 디렉터리에 직접 넣습니다.
    여기에 이미지 설명을 삽입하세요

다음으로 Flink SQL Client를 사용하여 Hudi와 통합하기 위한 SQL 명령줄을 제공합니다. Flink Standalone 클러스터를 시작하고 구성 파일 [ $FLINK_HOME/conf/flink-conf.yaml ]을 수정해야 하며 , TaskManager가 할당한 슬롯 수는 4입니다.
여기에 이미지 설명을 삽입하세요

5.2.2 환경 준비

먼저 각 프레임워크 서비스를 시작한 다음 DDL 문을 작성하여 테이블을 만들고, 마지막으로 DML 문을 작성하여 데이터를 삽입하고 쿼리하고 분석합니다. 아래 단계에 따라 환경을 시작하십시오. 이는 세 단계로 구성됩니다.

  • 첫 번째 단계, HDFS 클러스터 시작
[root@node1 ~]# hadoop-daemon.sh start namenode 
[root@node1 ~]# hadoop-daemon.sh start datanode
  • 2단계: Flink 클러스터 시작
    Flink는 HDFS 파일 시스템에 연결해야 하므로 먼저 HADOOP_CLASSPATH 변수를 설정한 후 독립 실행형 클러스터 서비스를 시작합니다.
[root@node1 ~]# export HADOOP_CLASSPATH=`$HADOOP_HOME/bin/hadoop classpath`

[root@node1 ~]# /export/server/flink/bin/start-cluster.sh
  • 3단계: Flink SQL Cli 명령줄 시작
[root@node1 ~]# /export/server/flink/bin/sql-client.sh embedded shell

hudi-flink 통합 패키지를 로드하기 위해 지정된 파라미터 [-j xx.jar]를 사용하며, 명령어는 다음과 같습니다.

[root@node1 ~]# /export/server/flink/bin/sql-client.sh embedded -j /root/hudi-flink-bundle_2.11-0.9.0.jar shell

SQL Cli에서 분석 결과 표시 모드를 다음과 같이 설정합니다: setexecution.result-mode=tableau;.
여기에 이미지 설명을 삽입하세요

SQL
클라이언트 문서: https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/dev/table/sqlclient/

5.2.3 테이블 생성

테이블 생성: t1, Hudi 테이블에 데이터 저장, 기본 HDFS 스토리지, 테이블 유형: MOR, 명령문은 다음과 같습니다.

CREATE TABLE t1(
  uuid VARCHAR(20), 
  name VARCHAR(10),
  age INT,
  ts TIMESTAMP(3),
  `partition` VARCHAR(20)
)
PARTITIONED BY (`partition`)
WITH (
  'connector' = 'hudi',
  'path' = 'hdfs://node1.itcast.cn:8020/hudi-warehouse/hudi-t1',
  'write.tasks' = '1',
  'compaction.tasks' = '1', 
  'table.type' = 'MERGE_ON_READ'
);

Flink SQL CLI 명령줄에서 DDL 문을 실행하면 스크린샷은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

테이블과 구조를 보면 명령은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

다음으로, Hudi 테이블에 데이터를 삽입하는 INSERT 문을 작성합니다.

5.2.4 데이터 삽입

위에서 생성된 테이블 t1에 데이터를 삽입합니다. 여기서 t1 테이블은 파티션 테이블, 필드 이름: partition, 데이터 삽입 시 필드 값: [part1, part2, part3 및 part4 ], 명령문은 다음과 같습니다.

INSERT INTO t1 VALUES
('id1','Danny',23,TIMESTAMP '1970-01-01 00:00:01','par1');

INSERT INTO t1 VALUES
('id2','Stephen',33,TIMESTAMP '1970-01-01 00:00:02','par1'),
('id3','Julian',53,TIMESTAMP '1970-01-01 00:00:03','par2'),
('id4','Fabian',31,TIMESTAMP '1970-01-01 00:00:04','par2'),
('id5','Sophia',18,TIMESTAMP '1970-01-01 00:00:05','par3'),
('id6','Emma',20,TIMESTAMP '1970-01-01 00:00:06','par3'),
('id7','Bob',44,TIMESTAMP '1970-01-01 00:00:07','par4'),
('id8','Han',56,TIMESTAMP '1970-01-01 00:00:08','par4');

Flink SQL CLI의 실행 스크린샷은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요
로그 정보에는 SQL 문이 실행을 위해 Flink Standalone 클러스터에 제출되고 업데이트 문이 성공적으로 실행되었음을 보여줍니다.
여기에 이미지 설명을 삽입하세요

HDFS에서 데이터 저장소 디렉터리를 쿼리합니다.
여기에 이미지 설명을 삽입하세요

5.2.5 쿼리 데이터

Flink SQL CLI를 통해 Hudi 테이블에 데이터를 삽입한 후 데이터를 쿼리하는 SQL 문을 작성합니다.

select * from t1;

데이터 삽입과 마찬가지로 SQL을 독립 실행형 클러스터에 제출하여 작업 쿼리 데이터를 생성합니다.
여기에 이미지 설명을 삽입하세요

다음과 같이 WHERE 절에 파티션 경로를 추가하여 파티션을 잘라냅니다.

select * from t1 where `partition` = 'par1' ;

여기에 이미지 설명을 삽입하세요

5.2.6 데이터 업데이트

id1의 데이터 연령을 23에서 24로 변경하고 다음과 같이 SQL 문을 실행합니다.

insert into t1 values ('id1','Danny',27,TIMESTAMP '1970-01-01 00:00:01','par1');

테이블의 데이터를 다시 쿼리하면 결과는 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

Flink Standalone 모니터링 페이지 8081을 삽입하면 3개의 Job이 실행되는 것을 확인할 수 있습니다.
여기에 이미지 설명을 삽입하세요

5.3 스트리밍 쿼리

Flink는 Hudi 테이블 데이터를 삽입할 때 스트리밍 방식으로 데이터 로드와 증분 쿼리 분석을 지원합니다.

5.3.1 테이블 생성

먼저 테이블 생성: t2, 관련 속성 설정, 스트리밍 방식으로 쿼리 및 읽기, 이전 테이블: t1에 매핑, 명령문은 다음과 같습니다.

CREATE TABLE t2(
  uuid VARCHAR(20), 
  name VARCHAR(10),
  age INT,
  ts TIMESTAMP(3),
  `partition` VARCHAR(20)
)
PARTITIONED BY (`partition`)
WITH (
  'connector' = 'hudi',
  'path' = 'hdfs://node1.itcast.cn:8020/hudi-warehouse/hudi-t1',
  'table.type' = 'MERGE_ON_READ',
  'read.tasks' = '1', 
  'read.streaming.enabled' = 'true',
  'read.streaming.start-commit' = '20210316134557',
  'read.streaming.check-interval' = '4' 
);

핵심 매개변수 옵션에 대한 설명:

  • read.streaming.enabled가 true로 설정되어 스트리밍을 통해 테이블 ​​데이터를 읽었음을 나타냅니다.
  • read.streaming.check-interval은 소스가 새 커밋을 모니터링하는 간격을 4초로 지정합니다.
  • table.type 테이블 유형을 MERGE_ON_READ로 설정합니다.
    여기에 이미지 설명을 삽입하세요

다음으로 데이터를 삽입하는 SQL을 작성하고 스트리밍 모드에서 테이블을 삽입합니다: t2 데이터.

5.3.2 데이터 쿼리

테이블 생성: t2 이후 현재 테이블에 있는 데이터는 이전 배치 모드에서 작성한 데이터입니다.

select * from t2 ;

표시 테이블에 모든 데이터를 삽입하고 커서가 4초마다 계속 깜박인 다음 커밋 타임스탬프에 따라 증분적으로 쿼리합니다.

5.3.3 데이터 삽입

터미널을 다시 열어 Flink SQL CLI를 시작하고 테이블 t1을 다시 생성한 후 배치 모드에서 데이터 1개를 삽입합니다.

CREATE TABLE t1(
  uuid VARCHAR(20), 
  name VARCHAR(10),
  age INT,
  ts TIMESTAMP(3),
  `partition` VARCHAR(20)
)
PARTITIONED BY (`partition`)
WITH (
  'connector' = 'hudi',
  'path' = 'hdfs://node1.itcast.cn:8020/hudi-warehouse/hudi-t1',
  'write.tasks' = '1',
  'compaction.tasks' = '1', 
  'table.type' = 'MERGE_ON_READ'
);

insert into t1 values ('id9','test',27,TIMESTAMP '1970-01-01 00:00:01','par5');

몇 초 후에 흐름 테이블에서 새로운 데이터(이전에 삽입된 데이터)를 읽을 수 있습니다.
여기에 이미지 설명을 삽입하세요

몇 가지 간단한 시연을 통해 HUDI Flink의 통합이 비교적 완료되었으며 읽기 및 쓰기 데이터가 포함된 것으로 나타났습니다.

5.4 Flink SQL 작성기

Flink SQL 커넥터 커넥터는 Hudi 테이블에서 데이터 읽기 및 쓰기를 지원하기 위해 hudi-flink 모듈에 제공됩니다.
여기에 이미지 설명을 삽입하세요
문서: https://hudi.apache.org/docs/writing_data#flink-sql-writer

5.4.1 Kafka와 통합된 Flink SQL

먼저 Kafka를 통합하고 Kafka Topic 데이터를 실시간으로 사용하도록 Flink SQL을 구성합니다.구체적인 단계는 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

  • 첫 번째 단계는 Zookeeper 및 Kafka 서비스 구성 요소를 시작하기 위한 주제를 생성하는 것입니다
    . 이 사례에서는 FlinkSQL과 Kafka를 통합하여 실시간으로 데이터를 로드하는 방법을 보여줍니다. KafkaTool 도구를 사용하여 Kafka 서비스를 연결 및 시작하고 flink-topic 주제를 생성합니다 .
    여기에 이미지 설명을 삽입하세요

명령줄을 사용하여 주제를 생성할 수 있으며 구체적인 명령은 다음과 같습니다.

-- 创建topic:flink-topic
kafka-topics.sh --create --bootstrap-server node1.itcast.cn:9092 --replication-factor 1 --partitions 1 --topic flink-topic

Flink Standalone 클러스터 서비스를 시작하고, flink-sql 명령줄을 실행하고, Kafka에 매핑된 테이블을 만듭니다.

  • 두 번째 단계는 HDFS 클러스터를 시작하는 것입니다.
    [root@node1 ~]# hadoop-daemon.sh start namenode
    [root@node1 ~]# hadoop-daemon.sh start datanode

  • 3단계: Flink 클러스터 시작
    Flink는 HDFS 파일 시스템에 연결해야 하므로 먼저 HADOOP_CLASSPATH 변수를 설정한 후 독립 실행형 클러스터 서비스를 시작합니다.

[root@node1 ~]# export HADOOP_CLASSPATH=`$HADOOP_HOME/bin/hadoop classpath`
[root@node1 ~]# /export/server/flink/bin/start-cluster.sh
  • 네 번째 단계는 Flink SQL Cli 명령줄을 시작하는 것입니다.
    지정된 매개변수 [-j xx.jar]를 사용하여 hudi-flink 통합 패키지를 로드합니다. 명령은 다음과 같습니다.
[root@node1 ~]# cd /export/server/flink
[root@node1 ~]# bin/sql-client.sh embedded -j /root/flink-sql-connector-kafka_2.11-1.12.0.jar shell

SQL Cli의 분석 결과 표시 모드를 tableau로 설정합니다.
여기에 이미지 설명을 삽입하세요

  • 다섯 번째 단계는 테이블을 생성하여 Kafka Topic에 매핑하는 것입니다.
    Kafka Topic의 데이터는 CSV 파일 형식이며 user_id, item_id, 동작의 세 가지 필드로 구성됩니다. Kafka에서 데이터를 소비할 때 최신 오프셋부터 시작을 설정합니다. .테이블 생성문은 다음과 같습니다.
CREATE TABLE tbl_kafka (
  `user_id` BIGINT,
  `item_id` BIGINT,
  `behavior` STRING
) WITH (
  'connector' = 'kafka',
  'topic' = 'flink-topic',
  'properties.bootstrap.servers' = 'node1.itcast.cn:9092',
  'properties.group.id' = 'test-group-10001',
  'scan.startup.mode' = 'latest-offset',
  'format' = 'csv'
);

명령을 실행한 후 테이블을 보면 스크린샷은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

  • 6단계: 실시간으로 Topic에 데이터를 전송하고 FlinkSQL에서 쿼리합니다
    . 먼저 FlinkSQL 페이지에서 SELECT 쿼리 문을 실행합니다. 스크린샷은 다음과 같습니다.
    여기에 이미지 설명을 삽입하세요

둘째, Kafka Console Producer를 통해 Topic에 데이터를 전송합니다. 명령과 데이터는 다음과 같습니다.

-- 生产者发送数据
kafka-console-producer.sh --broker-list node1.itcast.cn:9092 --topic flink-topic
/*
1001,90001,click
1001,90001,browser
1001,90001,click
1002,90002,click
1002,90003,click
1003,90001,order
1004,90001,order
*/

데이터를 삽입하고 FlinkSQL 인터페이스를 관찰하면 아래 스크린샷과 같이 데이터가 실시간으로 쿼리되고 처리되는 것을 확인할 수 있습니다. 지금까지
여기에 이미지 설명을 삽입하세요
FlinkSQL은 Kafka를 통합하고 테이블을 사용하여 주제 데이터를 연결한 다음 Flink SQL을 작성했습니다. Kafka 데이터를 Hudi 테이블에 실시간으로 동기화하는 프로그램입니다.

5.4.2 Hudi에 Flink SQL 작성

위에서 언급한 구조적 스트리밍 스트림 프로그램을 Flink SQL 프로그램으로 변경: Kafka의 Topic 데이터를 실시간으로 소비하고 분석 및 변환하여 Hudi 테이블에 저장합니다 . 개략적인 다이어그램은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

5.4.2.1 Maven 모듈 생성

여기에 이미지 설명을 삽입하세요

Maven 모듈 모듈을 생성하고 종속성을 추가합니다(여기서 Flink: 1.12.2 및 Hudi: 0.9.0 버전).

<repositories>
    <repository>
        <id>nexus-aliyun</id>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </repository>
    <repository>
        <id>central_maven</id>
        <name>central maven</name>
        <url>https://repo1.maven.org/maven2</url>
    </repository>
    <repository>
        <id>cloudera</id>
        <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
    </repository>
    <repository>
        <id>apache.snapshots</id>
        <name>Apache Development Snapshot Repository</name>
        <url>https://repository.apache.org/content/repositories/snapshots/</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <java.version>1.8</java.version>
    <scala.binary.version>2.12</scala.binary.version>
    <flink.version>1.12.2</flink.version>
    <hadoop.version>2.7.3</hadoop.version>
    <mysql.version>8.0.16</mysql.version>
</properties>

<dependencies>
    <!-- Flink Client -->
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-clients_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-java</artifactId>
        <version>${flink.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-runtime-web_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>

    <!-- Flink Table API & SQL -->
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-table-common</artifactId>
        <version>${flink.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-table-api-java-bridge_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-connector-kafka_${scala.binary.version}</artifactId>
        <version>${flink.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-json</artifactId>
        <version>${flink.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.hudi</groupId>
        <artifactId>hudi-flink-bundle_${scala.binary.version}</artifactId>
        <version>0.9.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-shaded-hadoop-2-uber</artifactId>
        <version>2.7.5-10.0</version>
    </dependency>

    <!-- MySQL/FastJson/lombok -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.68</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>

    <!-- slf4j及log4j -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.7</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
        <scope>runtime</scope>
    </dependency>

</dependencies>

<build>
    <sourceDirectory>src/main/java</sourceDirectory>
    <testSourceDirectory>src/test/java</testSourceDirectory>
    <plugins>
        <!-- 编译插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <!--<encoding>${project.build.sourceEncoding}</encoding>-->
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.18.1</version>
            <configuration>
                <useFile>false</useFile>
                <disableXmlReport>true</disableXmlReport>
                <includes>
                    <include>**/*Test.*</include>
                    <include>**/*Suite.*</include>
                </includes>
            </configuration>
        </plugin>
        <!-- 打jar包插件(会包含所有依赖) -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<!-- <mainClass>com.itcast.flink.batch.FlinkBatchWordCount</mainClass> -->
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

5.4.2.2 Kafka 데이터 사용

클래스 생성: Flink Table API를 기반으로 하는 FlinkSQLKafakDemo는 Kafka의 데이터를 사용하고 필드 값을 추출합니다(후디 테이블의 후속 저장을 위해).

package cn.itcast.hudi;

import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.TableEnvironment;

import static org.apache.flink.table.api.Expressions.$;

/**
 * 基于Flink SQL Connector实现:实时消费Topic中数据,转换处理后,实时存储Hudi表中
 */
public class FlinkSQLKafakDemo {
    
    

   public static void main(String[] args) {
    
    

      // 1-获取表执行环境
      EnvironmentSettings settings = EnvironmentSettings
         .newInstance()
         .inStreamingMode()
         .build();
      TableEnvironment tableEnv = TableEnvironment.create(settings) ;

      // 2-创建输入表, TODO: 从Kafka消费数据
      tableEnv.executeSql(
         "CREATE TABLE order_kafka_source (\n" +
            "  orderId STRING,\n" +
            "  userId STRING,\n" +
            "  orderTime STRING,\n" +
            "  ip STRING,\n" +
            "  orderMoney DOUBLE,\n" +
            "  orderStatus INT\n" +
            ") WITH (\n" +
            "  'connector' = 'kafka',\n" +
            "  'topic' = 'order-topic',\n" +
            "  'properties.bootstrap.servers' = 'node1.itcast.cn:9092',\n" +
            "  'properties.group.id' = 'gid-1001',\n" +
            "  'scan.startup.mode' = 'latest-offset',\n" +
            "  'format' = 'json',\n" +
            "  'json.fail-on-missing-field' = 'false',\n" +
            "  'json.ignore-parse-errors' = 'true'\n" +
            ")"
      );

      // 3-数据转换:提取订单时间中订单日期,作为Hudi表分区字段值
      Table etlTable = tableEnv
         .from("order_kafka_source")
         .addColumns(
            $("orderTime").substring(0, 10).as("partition_day")
         )
         .addColumns(
            $("orderId").substring(0, 17).as("ts")
         );
      tableEnv.createTemporaryView("view_order", etlTable);

      // 4-查询数据
      tableEnv.executeSql("SELECT * FROM view_order").print();
   }

}

스트리밍 애플리케이션과 시뮬레이션된 데이터 프로그램을 실행하여 콘솔을 확인하세요.
여기에 이미지 설명을 삽입하세요

5.4.2.3 Hudi에 데이터 저장

테이블 생성 DDL 문을 작성하고 이를 Hudi 테이블에 매핑하고 관련 속성(기본 키 필드, 테이블 유형 등)을 지정합니다.

CREATE TABLE order_hudi_sink (
  orderId STRING PRIMARY KEY NOT ENFORCED,
  userId STRING,
  orderTime STRING,
  ip STRING,
  orderMoney DOUBLE,
  orderStatus INT,
  ts STRING,
  partition_day STRING
)
PARTITIONED BY (partition_day)
WITH (
    'connector' = 'hudi',
    'path' = 'file:///D:/flink_hudi_order',
    'table.type' = 'MERGE_ON_READ',
    'write.operation' = 'upsert',
    'hoodie.datasource.write.recordkey.field'= 'orderId',
    'write.precombine.field' = 'ts',
    'write.tasks'= '1'
);

Hudi 테이블 데이터를 로컬 파일 시스템의 LocalFS 디렉터리에 저장하고, 또한 Hudi 테이블에 데이터를 쓸 때 INSERT INTO를 사용하여 데이터를 삽입합니다.구체적인 DDL 문은 다음과 같습니다.

-- 子查询插入INSERT ... SELECT ...
INSERT INTO order_hudi_sink
SELECT
    orderId, userId, orderTime, ip, orderMoney, orderStatus,
    substring(orderId, 0, 17) AS ts, substring(orderTime, 0, 10) AS partition_day
FROM order_kafka_source ;

클래스 생성: FlinkSQLHudiDemo , 코드 작성: Kafka의 데이터를 사용하고 변환한 후 Hudi 테이블에 저장합니다.

package cn.itcast.hudi;

import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;

import static org.apache.flink.table.api.Expressions.$;

/**
 * 基于Flink SQL Connector实现:实时消费Topic中数据,转换处理后,实时存储Hudi表中
 */
public class FlinkSQLHudiDemo {
    
    

   public static void main(String[] args) {
    
    

      System.setProperty("HADOOP_USER_NAME","root");

      // 1-获取表执行环境
      StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
      env.setParallelism(1);
      env.enableCheckpointing(5000);
      EnvironmentSettings settings = EnvironmentSettings
         .newInstance()
         .inStreamingMode()
         .build();
      StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings) ;

      // 2-创建输入表, TODO: 从Kafka消费数据
      tableEnv.executeSql(
         "CREATE TABLE order_kafka_source (\n" +
            "  orderId STRING,\n" +
            "  userId STRING,\n" +
            "  orderTime STRING,\n" +
            "  ip STRING,\n" +
            "  orderMoney DOUBLE,\n" +
            "  orderStatus INT\n" +
            ") WITH (\n" +
            "  'connector' = 'kafka',\n" +
            "  'topic' = 'order-topic',\n" +
            "  'properties.bootstrap.servers' = 'node1.itcast.cn:9092',\n" +
            "  'properties.group.id' = 'gid-1001',\n" +
            "  'scan.startup.mode' = 'latest-offset',\n" +
            "  'format' = 'json',\n" +
            "  'json.fail-on-missing-field' = 'false',\n" +
            "  'json.ignore-parse-errors' = 'true'\n" +
            ")"
      );

      // 3-数据转换:提取订单时间中订单日期,作为Hudi表分区字段值
      Table etlTable = tableEnv
         .from("order_kafka_source")
         .addColumns(
            $("orderId").substring(0, 17).as("ts")
         )
         .addColumns(
            $("orderTime").substring(0, 10).as("partition_day")
         );
      tableEnv.createTemporaryView("view_order", etlTable);

      // 4-定义输出表,TODO:数据保存到Hudi表中
      tableEnv.executeSql(
         "CREATE TABLE order_hudi_sink (\n" +
            "  orderId STRING PRIMARY KEY NOT ENFORCED,\n" +
            "  userId STRING,\n" +
            "  orderTime STRING,\n" +
            "  ip STRING,\n" +
            "  orderMoney DOUBLE,\n" +
            "  orderStatus INT,\n" +
            "  ts STRING,\n" +
            "  partition_day STRING\n" +
            ")\n" +
            "PARTITIONED BY (partition_day) \n" +
            "WITH (\n" +
            "  'connector' = 'hudi',\n" +
            "  'path' = 'file:///D:/flink_hudi_order',\n" +
            "  'table.type' = 'MERGE_ON_READ',\n" +
            "  'write.operation' = 'upsert',\n" +
            "  'hoodie.datasource.write.recordkey.field' = 'orderId'," +
            "  'write.precombine.field' = 'ts'" +
            "  'write.tasks'= '1'" +
            ")"
      );

      // 5-通过子查询方式,将数据写入输出表
      tableEnv.executeSql(
         "INSERT INTO order_hudi_sink\n" +
            "SELECT\n" +
            "  orderId, userId, orderTime, ip, orderMoney, orderStatus, ts, partition_day\n" +
            "FROM view_order"
      );

   }

}

위에서 작성한 스트림 프로그램을 실행하여 로컬 파일 시스템의 디렉터리를 확인하고 Hudi 테이블의 데이터 구조 정보를 저장합니다.
여기에 이미지 설명을 삽입하세요

5.4.2.4 Hudi 테이블 데이터 로드

클래스 생성: FlinkSQLReadDemo , Hudi 테이블에 데이터를 로드하고 스트리밍 모드에서 읽어 동일한 테이블을 생성한 후 Hudi 테이블의 데이터 저장 디렉터리에 매핑합니다. 테이블 생성을 위한 DDL 문은 다음과 같습니다.

CREATE TABLE order_hudi(
  orderId STRING PRIMARY KEY NOT ENFORCED,
  userId STRING,
  orderTime STRING,
  ip STRING,
  orderMoney DOUBLE,
  orderStatus INT,
  ts STRING,
  partition_day STRING
)
PARTITIONED BY (partition_day)
WITH (
    'connector' = 'hudi',
    'path' = 'file:///D:/flink_hudi_order',
    'table.type' = 'MERGE_ON_READ',
    'read.streaming.enabled' = 'true',
    'read.streaming.check-interval' = '4'
);

전체 Flink SQL 스트리밍 프로그램 코드는 다음과 같습니다.

package cn.itcast.hudi;

import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;

/**
 * 基于Flink SQL Connector实现:从Hudi表中加载数据,编写SQL查询
 */
public class FlinkSQLReadDemo {
    
    

   public static void main(String[] args) {
    
    
      System.setProperty("HADOOP_USER_NAME","root");

      // 1-获取表执行环境
      EnvironmentSettings settings = EnvironmentSettings
         .newInstance()
         .inStreamingMode()
         .build();
      TableEnvironment tableEnv = TableEnvironment.create(settings) ;

      // 2-创建输入表, TODO: 加载Hudi表查询数据
      tableEnv.executeSql(
         "CREATE TABLE order_hudi(\n" +
            "  orderId STRING PRIMARY KEY NOT ENFORCED,\n" +
            "  userId STRING,\n" +
            "  orderTime STRING,\n" +
            "  ip STRING,\n" +
            "  orderMoney DOUBLE,\n" +
            "  orderStatus INT,\n" +
            "  ts STRING,\n" +
            "  partition_day STRING\n" +
            ")\n" +
            "PARTITIONED BY (partition_day)\n" +
            "WITH (\n" +
            "  'connector' = 'hudi',\n" +
            "  'path' = 'file:///D:/flink_hudi_order',\n" +
            "  'table.type' = 'MERGE_ON_READ',\n" +
            "  'read.streaming.enabled' = 'true',\n" +
            "  'read.streaming.check-interval' = '4'\n" +
            ")"
      );

      // 3-通过子查询方式,将数据写入输出表
      tableEnv.executeSql(
         "SELECT \n" +
            "  orderId, userId, orderTime, ip, orderMoney, orderStatus, ts ,partition_day \n" +
            "FROM order_hudi"
      ).print();

   }

}

스트리밍 프로그램을 실행하고 Hudi 테이블 데이터를 로드하면 결과는 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

5.4.3 Flink SQL 클라이언트가 Hudi에 쓰기

Flink Standalone 클러스터를 시작하고, SQL 클라이언트 명령줄 클라이언트를 실행하고, DDL 및 DML 문을 실행하고, 데이터를 조작합니다.

5.4.3.1 통합 환경

Flink 클러스터 구성

  • $FLINK_HOME/conf/flink-conf.yaml 파일 수정
jobmanager.rpc.address: node1.itcast.cn
jobmanager.memory.process.size: 1024m
taskmanager.memory.process.size: 2048m
taskmanager.numberOfTaskSlots: 4

classloader.check-leaked-classloader: false
classloader.resolve-order: parent-first

execution.checkpointing.interval: 3000
state.backend: rocksdb
state.checkpoints.dir: hdfs://node1.itcast.cn:8020/flink/flink-checkpoints
state.savepoints.dir: hdfs://node1.itcast.cn:8020/flink/flink-savepoints
state.backend.incremental: true
  • Hudi 및 Flink의 통합 jar 패키지와 기타 관련 jar 패키지를 **$FLINK_HOME/lib** 디렉터리에 넣습니다.
    여기에 이미지 설명을 삽입하세요

독립형 클러스터 시작

export HADOOP_CLASSPATH=`/export/server/hadoop/bin/hadoop classpath`
/export/server/flink/bin/start-cluster.sh
  • SQL 클라이언트를 시작합니다. Hudi 통합 jar 패키지를 다시 지정하는 것이 가장 좋습니다.
/export/server/flink/bin/sql-client.sh embedded -j /export/server/flink/lib/hudi-flink-bundle_2.12-0.9.0.jar shell
  • 속성 설정
set execution.result-mode=tableau;
set execution.checkpointing.interval=3sec;

여기에 이미지 설명을 삽입하세요

5.4.3.2 SQL 실행

먼저 입력 테이블을 생성합니다. Kafka에서 데이터를 사용한 다음 SQL을 작성하여 필드 값을 추출한 다음 출력 테이블을 생성합니다. Hudi 테이블에 데이터를 저장하고 마지막으로 SQL을 작성하여 Hudi 테이블의 데이터를 쿼리합니다.

-1步、创建输入表,关联Kafka Topic
-- 输入表:Kafka Source
CREATE TABLE order_kafka_source (
  orderId STRING,
  userId STRING,
  orderTime STRING,
  ip STRING,
  orderMoney DOUBLE,
  orderStatus INT
) WITH (
  'connector' = 'kafka',
  'topic' = 'order-topic',
  'properties.bootstrap.servers' = 'node1.itcast.cn:9092',
  'properties.group.id' = 'gid-1001',
  'scan.startup.mode' = 'latest-offset',
  'format' = 'json',
  'json.fail-on-missing-field' = 'false',
  'json.ignore-parse-errors' = 'true'
);

SELECT orderId, userId, orderTime, ip, orderMoney, orderStatus FROM order_kafka_source ;
  • 2단계, Kafka 메시지 데이터 처리 및 획득, 필드 값 추출
SELECT 
  orderId, userId, orderTime, ip, orderMoney, orderStatus, 
  substring(orderId, 0, 17) AS ts, substring(orderTime, 0, 10) AS partition_day 
FROM order_kafka_source ;
  • 3단계. 출력 테이블 생성, Hudi 테이블에 데이터 저장 및 관련 속성 설정
-- 输出表:Hudi Sink
CREATE TABLE order_hudi_sink (
  orderId STRING PRIMARY KEY NOT ENFORCED,
  userId STRING,
  orderTime STRING,
  ip STRING,
  orderMoney DOUBLE,
  orderStatus INT,
  ts STRING,
  partition_day STRING
)
PARTITIONED BY (partition_day) 
WITH (
  'connector' = 'hudi',
  'path' = 'hdfs://node1.itcast.cn:8020/hudi-warehouse/order_hudi_sink',
  'table.type' = 'MERGE_ON_READ',
  'write.operation' = 'upsert',
  'hoodie.datasource.write.recordkey.field'= 'orderId',
  'write.precombine.field' = 'ts',
  'write.tasks'= '1',
  'compaction.tasks' = '1', 
  'compaction.async.enabled' = 'true', 
  'compaction.trigger.strategy' = 'num_commits', 
  'compaction.delta_commits' = '1'
);
  • 4단계, INSERT INTO 문을 사용하여 Hudi 테이블에 데이터를 저장합니다.
-- 子查询插入INSERT ... SELECT ...
INSERT INTO order_hudi_sink 
SELECT
  orderId, userId, orderTime, ip, orderMoney, orderStatus,
  substring(orderId, 0, 17) AS ts, substring(orderTime, 0, 10) AS partition_day 
FROM order_kafka_source ;

이 시점에서 아래와 같이 FlinkStandalone 클러스터에서 실행할 Flink 작업을 제출합니다.
여기에 이미지 설명을 삽입하세요

시뮬레이션된 거래 주문 데이터 프로그램이 실행되는 동안 데이터는 Kafka로 전송되고 최종적으로 변환되어 Hudi 테이블에 저장됩니다.스크린샷은 다음과 같습니다.
여기에 이미지 설명을 삽입하세요

  • 5단계. Hudi 테이블의 거래 주문 데이터를 쿼리하는 SELECT 문 작성
-- 查询Hudi表数据
SELECT * FROM order_hudi_sink ;

여기에 이미지 설명을 삽입하세요

5.5 후디 CDC

CDC의 전체 이름은 변경 데이터 캡처, 즉 변경 데이터 캡처입니다. 주로 데이터베이스 변경을 지향합니다. 데이터베이스 분야에서 매우 일반적인 기술입니다. 주로 데이터베이스의 일부 변경 사항을 캡처하는 데 사용됩니다 . 변경된 데이터는 다운스트림으로 전송될 수 있습니다 .
여기에 이미지 설명을 삽입하세요

CDC의 경우 업계에는 크게 두 가지 유형이 있습니다. 하나는 쿼리 기반이고 , 클라이언트는 SQL을 통해 소스 데이터베이스 테이블의 변경 데이터를 쿼리한 후 외부로 보냅니다. 두 번째는 업계에서 널리 사용되는 방식인 로그(log)를 기반으로 하는 것으로, 일반적으로 binlog 방식을 통해 변경된 기록을 binlog에 기록하고, binlog를 파싱한 후 메시지 시스템에 기록한다. , 또는 Flink CDC를 기반으로 직접 처리됩니다 .
여기에 이미지 설명을 삽입하세요

  • 쿼리 기반 : 이 CDC 기술은 방해가 되며 데이터 소스에서 SQL 문을 실행해야 합니다 . 이 기술을 사용하여 CDC를 구현하면 데이터 원본의 성능에 영향을 미칠 수 있습니다. 많은 수의 레코드가 포함된 전체 테이블을 스캔해야 하는 경우가 많습니다.
  • 로그 기반 : 이 CDC 기술은 비침해적이며 데이터 소스에서 SQL 문을 실행할 필요가 없습니다. 소스 데이터베이스의 로그 파일을 읽어 소스 데이터베이스 테이블의 데이터 생성, 수정 또는 삭제를 식별합니다.

5.5.1 CDC 데이터를 호수로

레이크에 입력되는 CDC 데이터를 기반으로 아키텍처는 매우 간단합니다. DB 변경 데이터, 이벤트 스트림, 다양한 외부 데이터 소스 등 다양한 업스트림 데이터 소스를 변경 스트림을 통해 테이블에 기록한 후 외부 쿼리를 수행할 수 있습니다. 분석.
여기에 이미지 설명을 삽입하세요

레이크에 대한 일반적인 CDC 링크: 위 링크는 대부분의 회사에서 채택한 링크입니다. 이전 CDC 데이터는 먼저 CDC 도구를 통해 Kafka 또는 Pulsar로 가져온 다음 Flink 또는 Spark 스트리밍 소비를 통해 Hudi에 기록됩니다. 두 번째 아키텍처는 Flink CDC를 통해 MySQL 업스트림 데이터 소스에 직접 연결하고 다운스트림 Hudi 테이블에 직접 쓰는 것 입니다 .
여기에 이미지 설명을 삽입하세요

5.5.2 플링크 CDC 후디

Flink CDC 기술을 기반으로 ETL 변환 처리 후 MySQL 데이터베이스 테이블 데이터를 실시간으로 수집하고 최종적으로 Hudi 테이블을 저장합니다.
여기에 이미지 설명을 삽입하세요

5.5.2.1 비즈니스 요구사항

MySQL 데이터베이스는 테이블을 생성하고 실시간으로 데이터를 추가하며 Flink CDC를 통해 Hudi 테이블에 데이터를 쓰고 Hudi와 Hive를 통합하여 자동으로 테이블을 생성하고 Hive에 파티션 정보를 추가하며 마지막으로 Hive 터미널 Beeline이 데이터를 쿼리하고 분석합니다.
여기에 이미지 설명을 삽입하세요

Hudi 테이블과 Hive 테이블은 자동으로 연관 및 통합되며, 컴파일 시 Hudi 소스 코드 재컴파일, Hive 버전 지정, Hive 종속 jar 패키지 포함이 필요하며 구체적인 단계는 다음과 같습니다.

  • flink 및 Hive 컴파일 종속성 버전 구성을 통합하도록 Hudi 수정
    이유 : 컴파일 시 기본적으로 통합된 Hudi의 현재 버전은 Flink lib 패키지 아래의 flink-SQL-connector-hive 패키지와 충돌합니다. 따라서 컴파일 프로세스 중에는 하이브 컴파일 버전만 수정됩니다.
    파일 : hudi-0.9.0/packaging/hudi-flink-bundle/pom.xml
    여기에 이미지 설명을 삽입하세요

  • Hudi 소스 코드 컴파일

mvn clean install -DskipTests -Drat.skip=true -Dscala-2.12 -Dspark3 -Pflink-bundle-shade-hive2 

컴파일이 완료되면 매우 중요한 2개의 jar 패키지가 있습니다.

  1. hudi-0.9.0/packaging/hudi-flink-bundle/target에 있는 hudi-flink-bundle_2.12-0.9.0.jar, flink는 데이터를 쓰고 읽는 데 사용되며 이를 **$FLINK_HOME/에 복사합니다. lib** 디렉토리에 이전에 같은 이름의 jar 패키지가 있었다면 삭제한 후 복사하세요.
  2. hudi-0.9.0/packaging/hudi-hadoop-mr-bundle/target에 있는 hudi-hadoop-mr-bundle-0.9.0.jar, Hive를 사용하여 hudi 데이터를 읽고 $HIVE_HOME에 복사해야 합니다. /lib 디렉토리 중간.
  • Flink CDC MySQL에 해당하는 jar 패키지를 $FLINK_HOME/lib 디렉터리에 넣습니다.
flink-sql-connector-mysql-cdc-1.3.0.jar

지금까지 $FLINK_HOME/lib 디렉토리에는 다음과 같은 필수 jar 패키지가 있으며 모두 필수입니다. 버전 번호에 주의하세요.

5.5.2.2 MySQL 테이블 생성

먼저 MySQL 데이터베이스 binlog 로그를 활성화한 다음 MySQL 데이터베이스 서비스를 다시 시작하고 마지막으로 테이블을 생성합니다.

  • 첫 번째 단계는 MySQL binlog 로그를 여는 것입니다.
[root@node1 ~]# vim /etc/my.cnf [mysqld]下面添加内容:
server-id=2
log-bin=mysql-bin
binlog_format=row
expire_logs_days=15
binlog_row_image=full

여기에 이미지 설명을 삽입하세요

  • 두 번째 단계, MySQL 서버 다시 시작
service mysqld restart

MySQL 클라이언트 명령줄에 로그인하여 적용 여부를 확인하세요.
여기에 이미지 설명을 삽입하세요

  • 세 번째 단계는 MySQL 데이터베이스에 테이블을 생성하는 것입니다.
-- MySQL 数据库创建表
create database test ;
create table test.tbl_users(
   id bigint auto_increment primary key,
   name varchar(20) null,
   birthday timestamp default CURRENT_TIMESTAMP not null,
   ts timestamp default CURRENT_TIMESTAMP not null
);

여기에 이미지 설명을 삽입하세요

5.5.2.3 CDC 테이블 생성

먼저 HDFS 서비스, Hive MetaStore 및 HiveServer2 서비스, Flink Standalone 클러스터를 시작한 다음 SQL 클라이언트를 실행하고 마지막으로 MySQL CDC 방법을 사용하여 MySQL 테이블과 연결된 테이블을 생성합니다.

  • HDFS 서비스를 시작하고 NameNode와 DataNode를 각각 시작하십시오.
-- 启动HDFS服务
hadoop-daemon.sh start namenode 
hadoop-daemon.sh start datanode
  • Hive 서비스 시작: 메타데이터 MetaStore 및 HiveServer2
-- Hive服务
/export/server/hive/bin/start-metastore.sh 
/export/server/hive/bin/start-hiveserver2.sh
  • Flink 독립 실행형 클러스터 시작
-- 启动Flink Standalone集群
export HADOOP_CLASSPATH=`/export/server/hadoop/bin/hadoop classpath`
/export/server/flink/bin/start-cluster.sh
  • SQL 클라이언트 클라이언트 시작
/export/server/flink/bin/sql-client.sh embedded -j /export/server/flink/lib/hudi-flink-bundle_2.12-0.9.0.jar shell

속성 설정:

set execution.result-mode=tableau;
set execution.checkpointing.interval=3sec;
  • 입력 테이블 생성, MySQL 테이블 연결, MySQL CDC 연결 사용
-- Flink SQL Client创建表
CREATE TABLE users_source_mysql (
  id BIGINT PRIMARY KEY NOT ENFORCED,
  name STRING,
  birthday TIMESTAMP(3),
  ts TIMESTAMP(3)
) WITH (
'connector' = 'mysql-cdc',
'hostname' = 'node1.itcast.cn',
'port' = '3306',
'username' = 'root',
'password' = '123456',
'server-time-zone' = 'Asia/Shanghai',
'debezium.snapshot.mode' = 'initial',
'database-name' = 'test',
'table-name' = 'tbl_users'
);

id가 기본 키이고 ts가 데이터 병합 필드인 테이블 구조를 쿼리합니다.
여기에 이미지 설명을 삽입하세요

  • CDC 테이블 데이터 쿼리
-- 查询数据
select * from users_source_mysql;

여기에 이미지 설명을 삽입하세요

  • MySQL 클라이언트 클라이언트 열기, DML 문 실행 및 데이터 삽입
insert into test.tbl_users (name) values ('zhangsan')
insert into test.tbl_users (name) values ('lisi');
insert into test.tbl_users (name) values ('wangwu');
insert into test.tbl_users (name) values ('laoda');
insert into test.tbl_users (name) values ('laoer');

5.5.2.4 뷰 생성

하이브 파티션 테이블의 후속 동기화를 용이하게 하기 위해 임시 뷰를 만들고 파티션 열 부분을 추가합니다.

-- 创建一个临时视图,增加分区列 方便后续同步hive分区表
create view view_users_cdc 
AS 
SELECT *, DATE_FORMAT(birthday, 'yyyyMMdd') as part FROM users_source_mysql;

보기 보기에서 데이터 보기

select * from view_users_cdc;

여기에 이미지 설명을 삽입하세요

5.5.2.5 Hudi 테이블 생성

CDC Hudi Sink 테이블을 생성하고 하이브 파티션 테이블, 특정 DDL 문을 자동으로 동기화합니다.

CREATE TABLE users_sink_hudi_hive(
id bigint ,
name string,
birthday TIMESTAMP(3),
ts TIMESTAMP(3),
part VARCHAR(20),
primary key(id) not enforced
)
PARTITIONED BY (part)
with(
'connector'='hudi',
'path'= 'hdfs://node1.itcast.cn:8020/users_sink_hudi_hive', 
'table.type'= 'MERGE_ON_READ',
'hoodie.datasource.write.recordkey.field'= 'id', 
'write.precombine.field'= 'ts',
'write.tasks'= '1',
'write.rate.limit'= '2000', 
'compaction.tasks'= '1', 
'compaction.async.enabled'= 'true',
'compaction.trigger.strategy'= 'num_commits',
'compaction.delta_commits'= '1',
'changelog.enabled'= 'true',
'read.streaming.enabled'= 'true',
'read.streaming.check-interval'= '3',
'hive_sync.enable'= 'true',
'hive_sync.mode'= 'hms',
'hive_sync.metastore.uris'= 'thrift://node1.itcast.cn:9083',
'hive_sync.jdbc_url'= 'jdbc:hive2://node1.itcast.cn:10000',
'hive_sync.table'= 'users_sink_hudi_hive',
'hive_sync.db'= 'default',
'hive_sync.username'= 'root',
'hive_sync.password'= '123456',
'hive_sync.support_timestamp'= 'true'
);

Hudi 테이블 유형은 다음과 같습니다. MOR, 읽기 시 병합(읽기 시 병합), 스냅샷 쿼리 + 증분 쿼리 + 읽기 최적화 쿼리(거의 실시간). 데이터를 저장하려면 컬럼형 스토리지(parquet) + 행 파일(arvo)을 사용하세요. 업데이트는 델타 파일에 기록된 후 동기식 또는 비동기식으로 압축되어 새 버전의 열 형식 파일을 생성합니다.
여기에 이미지 설명을 삽입하세요

5.5.2.6 Hudi 테이블에 데이터 쓰기

INSERT 문을 작성하고, 뷰에서 데이터를 쿼리한 후 Hudi 테이블에 씁니다.문은 다음과 같습니다.

insert into users_sink_hudi_hive select id, name, birthday, ts, part from view_users_cdc;

Flink 웹 UI DAG 다이어그램:
여기에 이미지 설명을 삽입하세요

HDFS의 Hudi 파일 디렉터리 상황:
여기에 이미지 설명을 삽입하세요

Hudi 테이블 데이터를 쿼리하기 위한 SELECT 문은 다음과 같습니다.

select * from users_sink_hudi_hive; 

여기에 이미지 설명을 삽입하세요

5.5.2.7 Hive 테이블 쿼리

hudi-hadoop-mr-bundle-0.9.0.jar 패키지를 가져와 **$HIVE_HOME/lib** 아래에 배치해야 합니다.
여기에 이미지 설명을 삽입하세요

Hive에서 Beeline 클라이언트를 시작하고 HiveServer2 서비스에 연결합니다.

/export/server/hive/bin/beeline -u jdbc:hive2://node1.itcast.cn:10000 -n root -p 123456

여기에 이미지 설명을 삽입하세요

hudi MOR 모드의 두 테이블이 자동으로 생성되었습니다.

  • users_sink_hudi_hive_ro , ro 테이블의 전체 이름은 읽기 최적화 테이블이며, MOR 테이블과 동기화된 xxx_ro 테이블의 경우 압축된 Parquet만 노출됩니다. 쿼리 방법은 COW 테이블과 유사합니다. hiveInputFormat을 설정한 후 일반 Hive 테이블처럼 쿼리할 수 있습니다.
  • users_sink_hudi_hive_rt
    , rt는 주로 증분 쿼리의 rt 테이블에 대한 증분 뷰를 의미합니다. ro 테이블은 쪽모이 세공 파일 데이터만 쿼리할 수 있고, rt 테이블 쪽모이 세공 파일 데이터와 로그 파일 데이터는 확인할 수 있습니다. 자동으로 생성된 테이블 users_sink_hudi_hive_ro 구조를 봅니다 .
CREATE EXTERNAL TABLE `users_sink_hudi_hive_ro`(
  `_hoodie_commit_time` string COMMENT '', 
  `_hoodie_commit_seqno` string COMMENT '', 
  `_hoodie_record_key` string COMMENT '', 
  `_hoodie_partition_path` string COMMENT '', 
  `_hoodie_file_name` string COMMENT '', 
  `_hoodie_operation` string COMMENT '', 
  `id` bigint COMMENT '', 
  `name` string COMMENT '', 
  `birthday` bigint COMMENT '', 
  `ts` bigint COMMENT '')
PARTITIONED BY ( 
  `part` string COMMENT '')
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
WITH SERDEPROPERTIES ( 
  'hoodie.query.as.ro.table'='true', 
  'path'='hdfs://node1.itcast.cn:8020/users_sink_hudi_hive') 
STORED AS INPUTFORMAT 
  'org.apache.hudi.hadoop.HoodieParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
  'hdfs://node1.itcast.cn:8020/users_sink_hudi_hive'
TBLPROPERTIES (
  'last_commit_time_sync'='20211125095818', 
  'spark.sql.sources.provider'='hudi', 
  'spark.sql.sources.schema.numPartCols'='1', 
  'spark.sql.sources.schema.numParts'='1', 
'spark.sql.sources.schema.part.0'='{\"type\":\"struct\",\"fields\":[{\"name\":\"_hoodie_commit_time\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"_hoodie_commit_seqno\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"_hoodie_record_key\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"_hoodie_partition_path\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"_hoodie_file_name\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"_hoodie_operation\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"id\",\"type\":\"long\",\"nullable\":false,\"metadata\":{}},{\"name\":\"name\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"birthday\",\"type\":\"timestamp\",\"nullable\":true,\"metadata\":{}},{\"name\":\"ts\",\"type\":\"timestamp\",\"nullable\":true,\"metadata\":{}},{\"name\":\"part\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}}]}', 
  'spark.sql.sources.schema.partCol.0'='partition', 
  'transient_lastDdlTime'='1637743860')

자동으로 생성된 테이블의 파티션 정보를 확인합니다.

show partitions users_sink_hudi_hive_ro;
show partitions users_sink_hudi_hive_rt;

여기에 이미지 설명을 삽입하세요

Hive 파티션 테이블 데이터 쿼리

set hive.exec.mode.local.auto=true;
set hive.input.format = org.apache.hudi.hadoop.hive.HoodieCombineHiveInputFormat;
set hive.mapred.mode=nonstrict ;

select id, name, birthday, ts, `part` from users_sink_hudi_hive_ro;

데이터를 필터링하고 쿼리하려면 파티션 필드를 지정하세요.

select name, ts from users_sink_hudi_hive_ro where part ='20211125';
select name, ts from users_sink_hudi_hive_rt where part ='20211125';

여기에 이미지 설명을 삽입하세요

5.5.3 Hudi Client는 Hudi 테이블을 운영한다

Hudi 클라이언트 명령줄을 입력합니다: hudi-0.9.0/hudi-cli/hudi-cli.sh
여기에 이미지 설명을 삽입하세요

Hudi 테이블에 접속하여 테이블 정보 보기

connect --path hdfs://node1.itcast.cn:8020/users_sink_hudi_hive

여기에 이미지 설명을 삽입하세요

Hudi 커밋 정보 보기

commits show --sortBy "CommitTime"

여기에 이미지 설명을 삽입하세요

Hudi 압축 계획을 확인하세요

compactions show all

여기에 이미지 설명을 삽입하세요

추천

출처blog.csdn.net/toto1297488504/article/details/132256320