Flink 기반 실시간 데이터 레이크 구축 사례

이 기사는 CommunityOverCode Asia 2023 데이터 레이크 특별 세션에서 "Flink 기반 실시간 데이터 레이크 구축 실습"에 대한 Volcano Engine 클라우드 네이티브 컴퓨팅 R&D 엔지니어 Wang Zheng과 Min Zhongyuan의 기조 연설을 편집한 것입니다.
 
실시간 데이터 레이크는 현대 데이터 아키텍처의 핵심 구성 요소입니다.데이터 레이크 기술이 발전함에 따라 사용자는 이에 대한 요구 사항이 높아졌습니다. 즉, 여러 데이터 소스에서 데이터를 가져와야 하고, 데이터 레이크와 데이터 소스를 실시간으로 유지해야 합니다. 일관성이 있으며, 변경 사항이 발생하면 시간에 맞춰 동기화할 수 있으며, 고성능 쿼리, 초 단위의 데이터 반환 등도 필요합니다. 그래서 우리는 들어오고 나가는 Lake 및 OLAP 쿼리에 Flink를 사용하기로 결정했습니다. 플링크 일괄 흐름 통합 아키텍처, E 정확히 O 한 번만 보장 및 완전한 커뮤니티 생태계 제공 많은 C연결자가 이전 요구 사항을 충족할 수 있습니다. 플링크 OLAP쿼리에도 적합합니다. 이 기사 .

전체 구조

Flink를 기반으로 실시간 데이터 레이크를 구축하는 전체 아키텍처에서 K8s는 하위 계층의 컨테이너 오케스트레이션 및 관리 플랫폼으로 사용됩니다. 스토리지 계층은 HDFS 또는 S3를 지원합니다. Iceberg는 좋은 파일 구성 구조와 생태로 인해 테이블 ​​형식으로 선택되었습니다. 컴퓨팅 계층은 Flink를 사용하여 레이크에 들어가고 나옵니다. Flink SQL은 레이크에 들어가고 나가는 가장 일반적으로 사용되는 방법입니다. 동시에 Flink Datastream API를 사용하여 일부 고급 기능이 개발됩니다. Lake는 Flink 애플리케이션 모드를 사용하여 K8s에서 실행됩니다. 그런 다음 Session Mode에서 Flink SQL Gateway와 Flink Cluster를 통해 OLAP 쿼리를 수행하고 JDBC 및 REST API 인터페이스의 반환 결과를 제공합니다. 물론 우리는 또한 메타데이터를 관리하기 위해 Catalog를 사용해야 합니다. 이는 Iceberg의 메타데이터를 참조할 뿐만 아니라 다른 타사 데이터 소스의 메타데이터도 포함하고 후속 데이터 유지 관리를 위해 예약된 작업을 사용합니다.

호수 실습에 데이터 입력

데이터가 호수에 들어오면 Flink는 왼쪽의 데이터 소스에서 데이터를 가져와 스트림 또는 일괄 방식으로 Iceberg에 씁니다. Iceberg 자체도 데이터 유지 관리를 위한 여러 작업을 제공하므로 각 테이블에는 데이터 만료, 스냅샷 만료, 고아 파일 정리, 작은 파일 병합 등과 같은 예약 작업이 예정되어 있습니다. 이러한 작업은 실제로 성능을 크게 향상시켰습니다. 큰 도움이 됩니다.
표적 스키마 고정됩니다. 대상 테이블에도 대상 테이블에 대한 테이블이 있습니다 . Flink SQL은 일반적으로 데이터 가져오기에 사용됩니다. 내보내기. , 쓸 수 있습니다. 임시 테이블 , 카탈로그에 메타데이터를 저장하고 카탈로그 테이블을 사용하여 데이터를 가져올 수도 있습니다. 그러나 보다 복잡한 고객 요구 사항을 충족하기 위해 실제로는 전체 데이터베이스 동기화 + 자동 테이블 생성 기능을 실현할 수 있는 Datastream API를 기반으로 CDC 스키마 자동 변경을 개발했습니다.

플링크 SQL

Iceberg 커뮤니티는 기본적인 쓰기 및 읽기 기능을 지원합니다. Flink 1.17에서는 행 수준 업데이트 및 삭제 기능(FLIP-282)을 도입했으며, 이를 기반으로 RowLevelModificationScanContext 인터페이스를 통해 Iceberg의 행 수준 업데이트를 구현하기 위해 일괄 Upate 및 삭제 작업을 추가했습니다. 실제로 Context에는 두 가지 정보(트랜잭션 시작 시 Snapshot ID)와 일괄 업데이트 및 삭제의 트랜잭션성을 보장하기 위한 UPDATE/DELETE의 필터 조건이 기록됩니다.

스키마 진화

스키마 진화는 스트림 작업 프로세스 중에 대상의 스키마를 동적으로 변경하여 데이터의 올바른 쓰기를 보장하는 스트림 처리의 일반적인 문제입니다. Iceberg 자체는 스키마 변경을 잘 지원합니다. Iceberg의 스토리지 아키텍처에서: 카탈로그는 스키마를 저장하지 않고 최신 메타데이터 파일 위치만 저장합니다. 메타데이터 파일은 모든 스키마 ID와 스키마 정보의 매핑뿐만 아니라 최신 스키마 ID(Current-Schema-id)를 저장합니다. 아래의 각 매니페스트는 스키마 ID를 기록합니다. 이는 매니페스트 아래의 Parquet 파일이 해당 스키마를 사용함을 의미합니다.
Iceberg에서 스키마가 변경되면 메타데이터 파일은 새 스키마를 기록하고 Current-Schema-id가 새 스키마를 가리킵니다. 후속 쓰기 작업에서는 새 스키마에 따라 새 Parquet 데이터 파일과 해당 매니페스트 파일이 생성됩니다. 읽을 때에는 최신 Schema-id에 따라 읽혀지며, 하단에 다른 Schema를 가진 Manifest 파일이 있더라도 새로운 Schema 정보를 이용하여 읽혀진다.
현재 Iceberg에서 제공하는 Flinksink는 스키마 변경을 지원하지 않습니다. Iceberg의 기본 Flinksink는 작성해야 하는 각 Parquet 파일에 대해 Streamwrtier를 생성하며 이 Streamwriter의 스키마는 수정됩니다. 그렇지 않으면 Parquet 파일을 작성할 때 오류가 보고됩니다. 위의 예에서 원본 Schema는 id, name, age인데, Schema가 일치하면 쓰기 시 오류가 보고되지 않으므로 Row 1을 쓸 수 있고, Row 2를 쓰면 길이가 일치하지 않으므로 오류가 보고됩니다: 인덱스가 범위를 벗어났습니다. ; 행 3을 작성할 때 데이터 유형 불일치로 인해 오류가 보고됩니다: 클래스 캐스트 예외; 행 4를 작성할 때 유형과 길이가 일치하지만 스키마 의미가 다릅니다. 결국 더티 데이터 조각이 결과 파일에 기록됩니다.
스키마 변경을 위해 해결해야 할 두 가지 주요 문제가 있습니다. 1) 각 행이 어떤 스키마에 해당하는지 어떻게 알 수 있습니까? 2) 한 작업에 여러 스키마 데이터를 작성하는 방법은 무엇입니까?
첫 번째 질문의 경우 각 레코드에 대한 스키마 정보를 포함하도록 Flink CDC 커넥터를 설정할 수 있습니다. 따라서 Row 및 해당 스키마 정보(그림에서 보라색 부분)를 포함하여 레코드를 출력하는 역직렬화 방법을 구현하여 첫 번째 문제를 해결해야 합니다.
두 번째 질문과 관련하여, 여러 스키마의 혼합 작성을 지원하려면 서로 다른 스키마에 대해 서로 다른 Streamwriter를 만들어야 하며 각 Streamwriter는 스키마에 해당합니다. 그러면 Iceberg Sink Connector에 새로운 FlinkSchemaEvolvingSink가 추가됩니다. , 들어오는 데이터가 현재 스키마와 일치하는지 확인합니다. 일치하지 않으면 새 스키마 정보를 Iceberg에 커밋하고 스키마 ID를 반환합니다. 그런 다음 새 Schema를 눌러 데이터를 쓰고 Commit data를 누르면 위 그림의 파란색 선에 대한 설명이 됩니다.Schema가 생성되면 이전 Schema id가 반환됩니다. FlinkSchemaEvolvingSink는 Schema ID를 Key로 하는 Streamwriter Map을 유지하고 있으며, Schema가 전달되면 Schema의 Writer가 포함되어 있는지 여부를 판단하고, 그렇지 않은 경우에는 Writer를 생성하여 다양한 유형의 글쓰기가 가능하도록 합니다. 동일한 작업에 작성되어야 함 스키마 정보.

전체 데이터베이스 동기화 및 자동 테이블 생성

Flink 작업 Jobgraph가 생성되기 전에 카탈로그 모듈이 필요합니다 소스 테이블의 정보를 읽고 Iceberg 측에서 동기화합니다. 에 해당하는 대상 테이블을 생성하거나 변경하는 동시에 Jobgraph에서 해당 테이블의 S잉크 정보 추가.
Flink 작업을 실행하는 동안 각 Binlog 레코드는 역직렬화 파서를 통해 레코드를 생성합니다. 이 레코드에는 Tableid와 Row의 두 부분, 즉 그림의 보라색 부분에 있는 레코드가 포함됩니다. 그런 다음 이 레코드를 분할하고 테이블 ID에 따라 행을 분할한 다음 Keyby Partition 작업 후 다운스트림 테이블에 씁니다.
전체 프로세스는 주로 다음 네 부분으로 구성됩니다.
  1. 디시리얼라이저는 이벤트 이벤트와 데이터를 구문 분석합니다. 전송 과정에서 Class Cast Exception을 방지하기 위해서는 데이터 타입이 소스 Schema와 동일하게 유지되어야 하며, 이를 위해서는 Flink CDC의 테스트 케이스를 활용하여 각 타입을 테스트하고 비교해야 합니다.
  2. Catalog Module은 주로 자동으로 테이블을 생성하고 테이블 내용을 업데이트하는 역할을 담당하며 deserializer와 일관된 유형 변환 방법을 유지해야 합니다.
  3. Table Spilled는 소스 재사용 기능을 실현하고 각 테이블에 대한 Sideoutput 태그를 생성하여 다운스트림으로 출력할 수 있습니다.
  4. Iceberg Sink는 각 파티션에 영향을 미치기 때문입니다. 해당 F anout W riter , 메모리를 많이 차지합니다. 따라서 OOM 수를 줄이기 위해서는 테이블의 Partition 필드에 대해 Keyby 작업을 수행해야 합니다. Iceberg에는 암시적 분할 기능이 있으므로 암시적 분할의 필드를 변환한 후 Keyby 작업을 수행해야 합니다.

데이터 쿼리 실습

플링크를 선택하는 이유

  • 구조적으로 Flink는 JDBC 드라이버, SQL-Gateway 및 세션 모드를 지원합니다. Flink 세션 클러스터는 일반적인 MPP(대량 병렬 처리) 아키텍처이므로 각 쿼리에 새로운 리소스를 적용할 필요가 없습니다. 사용자는 JDBC 드라이버를 통해 쉽게 SELECT 문을 제출하고 몇 초 또는 몇 초 안에 결과를 얻을 수 있습니다.
  • 강력한 일괄 처리 기능. Flink OLAP은 많은 일괄 작업과 최적화를 수행할 수 있습니다. 동시에 OLAP에도 수많은 쿼리가 있는데, Flink는 다른 OLAP 엔진처럼 외부 일괄 처리 엔진을 도입할 필요 없이 Flink의 일괄 처리 기능을 기반으로 이를 지원할 수 있습니다.
  • Flink는 OLAP 사용자의 대화형 요구 사항을 충족하기 위해 QUERY/INSERT/UPDATE와 같은 표준 SQL 구문을 지원합니다.
  • 강력한 커넥터 생태계. Flink는 입력 및 출력을 위한 포괄적인 인터페이스를 정의하고 데이터베이스 및 데이터 레이크 웨어하우스와 같은 많은 내장 커넥터를 구현합니다. 사용자는 이러한 인터페이스를 기반으로 맞춤형 커넥터를 쉽게 구현할 수도 있습니다.

OLAP 아키텍처

Flink OLAP의 전체 아키텍처는 Flink SQL 게이트웨이와 Flink 세션 클러스터의 두 부분으로 나뉩니다. 먼저 사용자는 클라이언트를 이용하여 Rest 인터페이스를 통해 Query를 제출하고, 먼저 Gateway의 SQL 구문 분석 및 최적화 과정을 거쳐 작업의 실행 계획을 생성한 후 Flink Session Cluster의 JobManager에 제출합니다. 해당 TaskManager에 대한 효율적인 소켓 인터페이스를 통해 실행 후 결과가 Clientht로 반환됩니다. JobManager의 Dispatcher는 해당 JobMaster를 생성한 다음 JobMaster는 클러스터의 TaskManager에 따라 특정 예약 규칙에 따라 작업을 배포합니다.

최적화 조치

쿼리 생성 최적화

  • Plan 존재
첫 번째 최적화 지점은 계획 캐싱입니다. OLAP 시나리오에서 Query는 두 가지 대표적인 특징을 가지고 있습니다. 하나는 스트리밍과 달리 비즈니스에서 반복되는 Querie가 많다는 것이고, 두 번째 특징은 쿼리에 시간이 많이 소요된다는 것입니다. 하위 초. 분석을 통해 계획 단계에 수십~수백 밀리초가 소요되어 상대적으로 높은 비율을 차지하는 것으로 나타났습니다. 따라서 Plan 캐싱을 지원하여 Query의 Plan 결과 변환을 캐싱하여 동일한 Query에 대한 Plan이 반복되는 문제를 방지합니다.
또한 메타정보 액세스를 가속화하기 위한 카탈로그 캐시와 TPC-DS 계획에 소요되는 시간을 약 10% 줄여주는 ExecNode의 병렬 변환도 지원됩니다.
  • 산자 하추
두 번째 최적화는 연산자 푸시다운입니다. 스토리지-계산 분리 아키텍처에서 연산자 푸시다운은 매우 중요한 최적화 유형입니다. 핵심 아이디어는 계산을 위해 일부 연산자를 스토리지 계층으로 푸시하여 연산자 수를 크게 줄이는 것입니다. 스캔 데이터 볼륨은 외부 IO를 줄이고 Flink 엔진이 처리해야 하는 데이터의 양을 줄여 Query 성능을 크게 향상시킵니다.
Byte의 내부 관행에는 대부분의 Query가 TopN 데이터를 사용하는 일반적인 업무가 있으므로 TopN의 push-down을 지원합니다.그림에서 알 수 있듯이 Local의 SortLimit 연산자, 즉 Local TopN 연산자는 Scan 노드로 푸시다운되고, TopN 계산은 최종적으로 스토리지 계층에서 수행되므로 스토리지에서 읽어오는 데이터의 양이 크게 줄어듭니다. 최적화 효과는 매우 뚜렷합니다. 스캔 노드가 스토리지에서 읽는 데이터의 양이 99.9% 감소하고, 비즈니스 쿼리 지연 시간이 약 90.4% 감소합니다.
또한 집계 푸시다운, 필터 푸시다운, 제한 푸시다운 등을 포함하여 더 많은 연산자 푸시다운도 지원합니다.

쿼리 실행 최적화

  • ClassLoader 사용
ClassLoader 재사용에서는 먼저 OLAP에서 Classloader의 잦은 생성으로 인해 과도한 CPU 사용이 발생하는 문제를 분석해 보겠습니다. 우리는 JM/TM의 CPU 사용량이 해당 라인에서 높다는 것을 발견했습니다. 플레임 그래프 분석을 통해 JVM의 Dictionary::find 메소드가 CPU의 70% 이상을 점유하고 있으며, JVM 소스 코드를 추가로 분석한 결과 JVM이 클래스를 로드한 후 검색 속도를 높이기 위해 클래스를 로드한 것으로 나타났습니다. Classloader에 대한 클래스 이름은 SystemDictionary.Hash 테이블을 유지 관리합니다(키는 클래스 이름, 값은 Classloader 인스턴스). 클래스로더 수가 매우 많은 경우, 예를 들어 20,000개 이상의 클래스로더가 온라인에 나타나면 해시 테이블에 많은 충돌이 발생하여 검색 프로세스가 매우 느려집니다. 즉 전체 CPU의 대부분을 사용하게 됩니다. 이 단계에서는 JM이 소모됩니다.
포지셔닝을 통해 우리는 이러한 Classloader가 모두 사용자의 Jar 패키지를 동적으로 로드하는 데 사용되는 UserCodeClassloader임을 확인했습니다. 각 Job은 새로운 UserCodeClassloader를 생성합니다. 아래 그림에서 볼 수 있듯이 새 Job의 JobMaster와 Task의 Task는 다음과 같습니다. TM New UserCodeClassloaders의 작업이 생성되어 JM 및 TM에 너무 많은 클래스로더가 생성됩니다. 또한 클래스로더가 너무 많으면 JVM 메타스페이스 공간이 부족해져서 Metaspace Full GC가 자주 발생하게 됩니다.
따라서 크게 두 단계로 나누어진 Classloader 재사용을 최적화했습니다. 첫째, Jar에 의존하는 방식을 최적화했습니다. OLAP 시나리오에서 의존하는 타사 Jar 패키지는 상대적으로 고정되어 있으므로 Classpath에 직접 배치할 수 있습니다. JM 및 TM.에 의해 시작되었으므로 각 작업에 대해 별도의 Jar 패키지를 제출할 필요가 없습니다. 그런 다음 각 작업에 대해 JobMaster 및 Task 초기화 중에 시스템 클래스로더가 직접 재사용됩니다. Classloader 재사용 후 JM에서 Dictionary::find가 차지하는 CPU 사용량은 76%에서 1%로 감소했으며, 동시에 Metaspace Full GC의 빈도도 크게 감소했습니다.
  • CodeGen 생존화
이번 최적화의 전제는 OLAP 하에서 Codegen 소스 코드 컴파일이 너무 많은 TM CPU를 차지한다는 문제를 발견했다는 것입니다. 현재 Codegen 캐싱 프로세스에서 Flink SQL의 많은 연산자는 Codegen을 사용하여 다음과 같은 계산 로직을 생성합니다. Codegen Operator. Code는 Codegen에 의해 생성된 Java 소스 코드인 클래스입니다. Operator가 초기화되면 Java 소스 코드를 컴파일하고 Class에 로드해야 합니다. 반복적인 컴파일을 피하기 위해 현재 클래스 이름을 태스크에서 사용하는 클래스로더에 매핑한 다음 컴파일된 클래스에 매핑하는 캐싱 메커니즘이 있습니다.
그러나 현재 캐싱 메커니즘에는 두 가지 문제가 있습니다. 첫째, 현재 메커니즘은 동일한 작업 내에서 동일한 Task의 서로 다른 동시 재사용만 구현하지만 동일한 Query를 여러 번 실행하기 위해 여전히 반복적인 컴파일이 발생합니다. Codegen이 Java 소스 코드를 생성할 때 이름 지정 충돌을 피하기 위해 코드의 클래스 이름과 변수 이름의 접미사는 프로세스 수준 자동 증가 ID를 사용하므로 동일한 쿼리가 여러 번 실행되고 클래스 이름과 코드의 내용이 변경되므로 캐시를 적중할 수 없습니다. 또 다른 문제는 클래스가 컴파일되고 로드될 때마다 새로운 ByteArrayClassloader가 생성된다는 점입니다. Classloader를 자주 생성하면 심각한 Metaspace 조각화가 발생하고 Metaspace Full GC가 발생하여 서비스 지터가 발생합니다.
작업 간 코드의 반복적인 컴파일을 방지하고 작업 간 클래스 공유를 달성하려면 캐싱 논리를 최적화하고 동일한 소스 코드를 컴파일된 클래스에 매핑해야 합니다. 여기에는 두 가지 어려움이 있습니다.
  1. 첫 번째는 동일한 논리를 사용하는 연산자가 동일한 코드를 생성하는지 확인하는 방법입니다.
  2. 동일한 코드를 고유하게 식별하도록 캐시 키를 설계하는 방법.
첫 번째 어려움은 Codegen 코드를 생성할 때 클래스 이름과 변수 이름의 자동 증가 ID를 전역 세분성에서 로컬 컨텍스트 세분성으로 대체하여 동일한 논리를 가진 연산자가 동일한 코드를 생성할 수 있도록 합니다. 두 번째 난이도에서는 클래스로더의 해시 값 + 클래스 이름 + 코드 길이 + 코드의 md5 값을 캐시 키로 기반으로 4개의 튜플을 캐시 키로 설계하여 동일한 코드를 고유하게 식별했습니다.
Codegen 캐시 최적화의 효과는 매우 뚜렷합니다. TM 측 코드 컴파일의 CPU 사용량이 이전 46%에서 약 0.3%로 최적화되었습니다. 쿼리의 E2E Latency가 약 29.2% 감소합니다. 동시에 Metaspace Full GC 시간은 또한 71.5% 감소합니다.

구체화된 뷰

  1. 먼저, 사용자는 Flink SQL을 통해 플랫폼에 구체화된 뷰를 생성하라는 요청을 보냅니다.
  2. 플랫폼은 Iceberg 구체화된 뷰를 생성하고, 구체화된 뷰를 새로 고치기 위해 Flink 작업을 시작하고, 이 작업이 계속 실행되도록 호스팅하는 역할을 담당합니다.
  3. Flink 새로 고침 작업은 소스 테이블에서 증분 데이터를 계속 스트리밍하고 증분 계산을 수행하여 증분 결과를 얻은 다음 이를 구체화된 뷰로 스트리밍합니다.
  4. 최종 사용자는 구체화된 뷰를 확인하여 원래 전체 계산이 필요했던 결과를 직접 얻을 수 있습니다.
위는 구체화된 뷰를 구현하는 주요 프로세스입니다. 현재 우리의 Iceberg 구체화된 뷰는 일반적인 Iceberg 테이블일 뿐입니다. 앞으로는 데이터의 최신성을 판단할 수 있도록 Iceberg 수준에서 더욱 완전한 메타데이터가 기록될 것입니다. 기존 구체화된 뷰를 기반으로 사용자 쿼리를 자동으로 다시 작성하고 최적화합니다. 정기적인 데이터 유지 관리에는 만료된 데이터 정리, 만료된 스냅샷 정리, 고아 파일 정리, 데이터/메타데이터 작은 파일 병합 등이 포함됩니다.

요약 및 전망

후속 작업은 주로 구체화된 뷰 자동 생성, 구체화된 뷰 쿼리 재작성, 데이터 유지 관리 작업을 위한 매개변수 자동 튜닝(실행 빈도, 병합 파일 크기 등), 핫 및 관련 작업에 중점을 둘 예정입니다. 콜드 데이터 계층화/데이터 캐시 확장.
 
SenseTime 창립자 Tang Xiaoou, 55세의 나이로 사망 2023년에는 PHP 정체 Wi-Fi 7이 완전히 출시됩니다 2024년 초 데뷔, Wi-Fi 6보다 5배 빠름 홍멍 시스템은 곧 독립을 앞두고 있으며 많은 대학에서 '홍멍 수업'을 설치했습니다 Zhihui Jun의 스타트업 회사 재융자, 금액 6억 위안 초과, 사전 평가액 35억 위안 Quark Browser PC 버전 내부 테스트 시작 AI 코드 도우미 인기 많고 프로그래밍 언어 순위는 다 별거 없어요 Mate 60 Pro의 5G 모뎀과 무선 주파수 기술이 훨씬 앞서 있습니다 MariaDB가 SkySQL을 분할하여 설립되었습니다 독립 회사로서 Xiaomi는 Yu Chengdong의 화웨이의 "용골 피벗" 표절 발언에 대응
{{o.이름}}
{{이름}}

추천

출처my.oschina.net/u/5941630/blog/10322189