본문 바로가기
BigData/Flink

[Flink] 좋은 스트리밍 시스템과 Apache Flink 기본 개념 정리 및 내부 구조

by 스파이디웹 2025. 6. 15.
728x90

이번 포스트에는 스트림 데이터와 좋은 스트리밍 시스템은 어떤 것인지, Flink에 대한 기본 개념과 내부구조, 왜 좋은지 장단점에 대해서 정리해보겠습니다.


1. 스트림 데이터와 좋은 스트리밍 시스템

우선 flink가 스트리밍 시스템에 있어서 왜 좋은지를 파악하려면 스트림 데이터는 어떻게 쓰이고, 좋은 스트리밍 시스템은 어떤 기준을 갖고 있는지를 파악해 봐야 합니다.

1) 스트림 데이터란

  • 계속해서 끊임없이 생성되고 흐르는 데이터를 의미
  • 한 번에 한 건씩(또는 작은 단위로) 발생하며, 실시간으로 처리되는 것이 일반적

스트림 데이터의 예시

  • 쇼핑몰 고객의 구매 요청
  • 항공사 예약 발생
  • 보험금 청구
  • 은행 트랜잭션 발생
  • 클릭 이벤트
  • 서버 로그
  • 현재 IoT 장비의 위치
  • 기타 등등

스트림 데이터를 활용하는 예시

  • 은행에서 이상 거래를 탐지
  • 쇼핑몰에서 구매자의 수요에 맞춰 동적 가격 계산
  • 온라인 사용자의 행동 패턴 분석
  • 실시간 추천 시스템
  • 기타 등등

2) 좋은 스트림 시스템의 조건

  1. 실시간 처리를 위한 유연한 확장성과 부하 대응력
    • 부하에 유동적으로 대응할 수 있어야 하며, 데이터 유입이 급증해도 성능이 저하되지 않아야 함
    • 급증한 데이터에 대해 스트림 프로세싱을 수행하지 못한다면, 데이터는 계속 지연되기 때문에 실시간 처리가 아니게 됨
  2. 정확한 시간 제어
    1. 이벤트 시간을 기준으로 처리 할 수 있어야 함
    2. WaterMark + event 시간 기준으로 out-of-order를 처리 할 수 있어야 함
  3. 시스템은 내결함성을 가져야 함
  4. 정확히 한 번 수행(Exactly once) 보장
    • 중복 없이, 빠짐 없이 정확한 상태와 결과를 유지하는 것을 의미
    • 결제 이벤트를 예로 들면 2번의 중복 결제가 있는 경우, 재고가 2개 빠지고, 포인트가 2번 적립되며, 택배가 2번 발송 되는 사건이 발생할 수 있음

1. Apache Flink란?

[데이터 스트림에 대한 상태 기반 연산]

  • Apache Flink는 유한 및 무한 데이터 스트림에 대한 상태 기반 연산을 처리하기 위한 프레임워크이자 분산 처리 엔진
  • Flink는 모든 일반적인 클러스터 환경에서 실행되도록 설계되었으며, 인메모리 속도로 어떤 규모에서도 연산을 수행할 수 있도록 만들어짐 → YARN, Kubernetes(EKS 포함), Mesos, EMR, Standalone 등의 다양한 클러스터 환경에서 무리 없이 실행 가능하도록 설계됨

2. Flink 특징 및 장점

1) Process Unbounded and Bounded Data(유한 무한 데이터 처리)

고급 분석용 API에서 상세한 제어 기능을 제공하는 상태 저장 이벤트 기반 애플리케이션 수준에 이르기까지 *계층화된 API를 제공

  • SQL / Table API: Flink 애플리케이션 작성 시 Bounded 및 Unbounded Streams 모두에서 사용 가능한 선언적 고수준 API
  • DataStream API: Flink 애플리케이션 작성 시 UnBounded Streams 에서 사용되는 고수준 API
  • DataSet API: Flink 애플리케이션 작성시 Bounded Streams에서 사용되는 더 낮은 수준의 API

무한 스트림 (Unbounded Streams)

  • 시작점은 있지만 끝이 정의되지 않은 스트림
  • 지속적으로 데이터가 생성되며, 종료되지 않음
  • 데이터를 계속해서 실시간으로 처리해야 하며, 데이터를 모두 수집한 후 처리하는 것은 불가능(왜냐하면 끝이 없기 때문)
  • 따라서 이벤트가 발생한 순서대로 처리하는 것이 중요할 수 있음, 그래야 결과의 정확성과 완전성을 판단할 수 있기 때문

유한 스트림 (Bounded Streams)

  • 시작과 끝이 명확하게 정의된 스트림
  • 모든 데이터를 먼저 수집한 후, 이후에 처리할 수 있음
  • 이벤트의 순서가 중요하지 않음
    유한한 데이터셋은 항상 정렬할 수 있기 때문
  • 이런 유한 스트림 처리 방식은 흔히 배치 처리(Batch Processing) 라고도 함
  • Flink는 "스트리밍이 기본, 배치는 특수 케이스" 라는 철학을 가지고 설계되었음
    • 스트리밍을 기본 단위로 처리 → 실시간 데이터 처리에 최적화
    • 배치도 내부적으로는 유한한 스트림으로 간주하여 처리
    • Spark 같은 시스템은 기본적으로 배치(batch) 기반이고 스트리밍은 그 위에 올라간 구조라서,
      실시간 처리의 지연 시간이나 처리 방식에서 Flink보다 불리한 경우가 많음.
  • 스트리밍 시스템은 윈도우를 통해 무한한 스트림 데이터를 유한개의 데이터로 바꿔서 처리한다는 아이디어


2) Deploy Applications Anywhere(어디서나 앱을 배포)

  • Hadoop YARN, Kubernetes 등 일반적으로 사용되는 모든 클러스터 리소스 관리자와 통합되며, 단독(standalone) 클러스터로 설정하여 실행할 수 있음
    • Flink는 각 리소스 관리자에 맞는 배포 모드를 제공하여,리소스 관리자와 그에 맞는 방식(idiomatic way) 으로 상호작용할 수 있도록 함
  • 병렬성(parallelism) 을 기반으로 필요한 리소스를 자동으로 파악하고, 해당 리소스를 리소스 관리자에게 요청
  • 애플리케이션을 제출하거나 제어하는 모든 통신은 REST 호출(REST API) 을 통해 이루어지므로, Flink는 다양한 환경에 쉽게 통합

3) Run Applications at any Scale(다양한 규모의 작업으로 실행)

  • 애플리케이션은 수천 개의 태스크(task) 로 병렬화되며, 이 태스크들은 클러스터 내에서 분산되어 동시에 실행
    • 애플리케이션은 사실상 무제한에 가까운 CPU, 메인 메모리, 디스크, 네트워크 IO 자원을 활용할 수 있음
  • Flink는 매우 큰 규모의 애플리케이션 상태(state) 도 쉽게 관리할 수 있음 →
    Flink의 비동기적(asynchronous)이고 점진적인(incremental) 체크포인팅 알고리즘은 처리 지연(latency)에 거의 영향을 주지 않으면서, 정확히 한 번만 처리되는 상태 일관성(exactly-once state consistency) 을 보장

4) Leverage In-Memory Performance(인메모리 성능 활용)

  • 상태 기반 Flink 애플리케이션은 로컬 상태(local state)에 대한 접근을 최적화하도록 설계되어 있음
    태스크의 상태는 항상 메모리 내에 유지되며, 만약 상태 크기가 가용 메모리를 초과할 경우에는 접근 효율이 높은 디스크 기반 자료 구조에 저장
    (기본 비즈니스 로직을 실행하는 모든 애플리케이션은 이벤트 또는 중간 결과를 기억하여 나중에 다음 이벤트가 수신되거나 특정 기간이 지난 후에 접근할 수 있도록 함)
  • Java 애플리케이션으로 JVM(Java Virtual Machine)에서 실행되지만 JVM GC(Garbage Collector)에 전적으로 의존하지 않고, 대신 커스텀 메모리 관리자를 구현하여 안정적인 메모리 사용량을 유지하면서 성능을 향상시킴
  • Flink는 장애가 발생했을 경우에도 정확히 한 번만 처리되는 상태 일관성(exactly-once state consistency) 을 보장하기 위해, 로컬 상태를 주기적으로 비동기 방식으로 내구성 있는 저장소에 체크포인팅 함
    (경량 분산 스냅샷을 구현해서 Exactly-once 를 보장하면서 오버헤드도 낮출 수 있음)
    • Kafka Streams 같은 경량 스트리밍 라이브러리는 상태 저장이 제한적이고 장애 복구가 어렵고,
      Spark Structured Streaming은 latency나 상태 복구에서 Flink보다 느림
  • 따라서 태스크는 대부분의 연산을 로컬 상태(주로 메모리)에 접근하여 수행하므로, 아주 낮은 처리 지연(latency) 을 달성할 수 있음

 


5) 데이터 처리 방식, Event Time 처리와 정확한 시간 제어

  • lazy evaluation: 계산을 최대한 늦출 수 있는 lazy evaluation을 사용. 즉, 계산이 필요할 때까지 계산이 수행되지 않음(실제 필요할 때 메모리에 올림)
  • 지연 데이터 처리: 이벤트 발생 시간과 처리 시간을 구분하고 워터마크를 사용하여 지연 데이터를 처리 함. 즉, 데이터 포인트는 들어오는 즉시 처리되지 않더라도 처리될 수 있음
  • Event Time 기반 윈도우를 사용하여 데이터가 실제로 언제 발생했는지(event time)를 기준으로 처리 가능
    • 실시간 IoT, 결제, 사용자 행동 분석 같이 시간 순서가 중요하거나 늦게 오는 이벤트가 많은 상황에서
      Flink는 매우 정교한 처리가 가능하지만, Spark는 처리 순서나 지연 데이터 핸들링이 제한적임
    • out-of-order도 watermark("이제 특정 시간 이전의 데이터는 더 이상 도착하지 않을 것이다"라는 신호 )+ event time을 기준으로 데이터 처리 가능

streaming 데이터 시점 기준

기준 설명 특징
Processing Time 데이터를 처리하는 시점 기준 구현 간단, 지연 고려 안 함
Ingestion Time 시스템에 들어온 시점 기준 중간 타협, 약간의 시간 보존 가능
Event Time 데이터가 실제로 발생한 시각 기준 가장 정확, 워터마크 필요

SparkStreaming의 처리 시점은?

 

  • 기본값: Processing Time 기반 (마이크로배치 시점 기준)
  • 옵션으로 Event Time 처리 가능:
    • withWatermark()를 사용해 event time + 늦은 데이터 처리 지원
    • 하지만 Flink만큼 정교하거나 저지연은 아님
  • Ingestion Time은 명시적으로 지원하지 않음 (사용자가 처리 시점 기록해야 함)

 

Out-of-order 데이터
이벤트가 실제로 발생한 시간과는 다른 순서로 도착한 데이터를 의미합니다.
Ex)
12:02에 발생했지만,12:01에 도착해서 순서가 뒤바뀐(out-of-order) 예시

발생 이유
1. 네트워크 지연
2. 버퍼링
3. 복잡한 데이터 경로
4. 모바일/IoT 기기에서의 오프라인 저장 후 업로드

 


3. Flink 아키텍처, EcoSystem

1) 아키텍처

  • JobManager(Master node): 하나 이상의 TaskManager로 구성되어 있으며, 제출된 작업을 예약 및 관리하고 작업에 자원을 할당해 실행 계획을 조율
    • Job Manager 데몬은 클러스터의 마스터 노드에서 실행되며, Flink 시스템에서 조정자(coordinator) 역할을 함
    • Job Manager는 클라이언트 시스템으로부터 프로그램 코드를 전달받아, 그 작업을 슬레이브 노드(작업 노드)할당하여 처리를 수행
  • TaskManager(Slave node): 클러스터의 여러 노드에 걸쳐 할당된 자원에서 사용자 정의 기능을 실행
    • Task Manager 데몬은 클러스터의 슬레이브 노드(작업 노드) 에서 실행되며, Flink 시스템에서 실제 연산을 수행하는 역할
    • Job Manager로부터 명령을 전달받아, 요구된 작업을 수행

이 아키텍처의 장점은 대규모 데이터 세트를 거의 실시간으로 처리할 수 있도록 효율적으로 확장할 수 있다는 것

 


2) Flink 실행 흐름

2-1. Program (프로그램 작성)

클라이언트 시스템이 실행을 위해 제출하는, 사용자가 개발한 애플리케이션 프로그램

2-2. Parse and Optimize (파싱 및 최적화)

이 단계에서는 코드를 파싱하여 문법 오류를 확인하고, 타입 추출(Type Extractor), 최적화 작업을 수행

2-3. DataFlow Graph (데이터 플로우 그래프 변환)

애플리케이션 작업이 데이터 플로우 그래프로 변환되어 이후 실행 단계에서 사용할 수 있도록 준비

2-4. Job Manager (잡 매니저 처리)

이 단계에서 Flink의 Job Manager 데몬이 태스크를 스케줄링하고, Task Manager에게 실행을 위임하고,
중간 처리 결과를 모니터링하는 역할도 수행

2-5. Task Manager (태스크 매니저 처리)

이 단계에서 Task Manager는 Job Manager가 할당한 작업을 실제로 실행


3) EcoSystem

 

  • DataSet API: 일괄 처리를 위한 Flink의 핵심 API로 Map, Reduce, Join, Co-group 같은 반복 연산에 사용
  • DataStream API: 스트리밍 데이터(무제한 및 무한 라이브 데이터 스트림)를 처리하는 데 사용되며, 이를 통해 사용자는 외부 데이터 저장소를 쿼리하여 윈도우잉, 시간당 기록 변환, 이벤트 보강 등 들어오는 이벤트에 대한 임의의 연산을 정의할 수 있음
  • 복합 이벤트 처리(CEP: Complex Event Processing) 정규식이나 StateMachine을 사용하여 이벤트 패턴을 지정해DataStream API와 통합되어 데이터에 대한 패턴 인식을 실시간으로 수행할 수 있음. 네트워크 이상 탐지, 규칙 기반 알림, 프로세스 모니터링, 사기 탐지 같은 애플리케이션에 사용
  • SQL 및 Table API: SQL 쿼리와 Table API를 사용해 테이블 스키마를 기반으로 데이터를 쉽게 조작하여 최소한의 노력으로 복잡한 데이터 변환 파이프라인을 구축할 수 있음
  • Gelly
    • DataSet API 위에서 실행되는 다목적 그래프 처리 및 분석 라이브러리로 확장성과 견고함을 모두 갖추고 있음
    • Gelly는 label propagation, triangle enumeration, page rank와 같은 기본 제공 알고리즘을 갖추고 있으며 쉽게 구현할 수 있는 사용자 정의 그래프 알고리즘 API도 지원
  • FlinkML
    • DataSet API 위에서 실행되는 분산 머신 러닝 알고리즘 라이브러리로 선형 회귀, 로지스틱 회귀, 의사 결정 트리, K-평균 클러스터링, LDA 등과 같은 지도 및 비지도 학습 기법을 모두 적용할 수 있는 통합된 방법을 사용자에게 제공
    • 신경망 구축을 위한 실험적인 딥 러닝 프레임워크(TensorFlow 패키징)를 제공

4. Window

내부적으로 어떻게 flink가 데이터를 처리하는지를 확인하려면 Window를 살펴봐야 합니다.

  • Apache Flink에서 윈도우는 위 그림과 같은 라이프 사이클을 가짐
  • 하나의 윈도우는 입력 스트림(Input Stream)을 소스로 받고 출력 스트림(Output Stream)을 생성하는 큰 구조로 이루어져 있고, 이렇게 생성된 출력 스트림은 또 다른 곳에서 입력 스트림이 됨

윈도우 할당자 (Window Assigner)

  • 들어온 데이터를 하나 이상의 윈도우에 할당하는 역할
  • Flink에는 기본적으로 텀블링 윈도우, 슬라이딩 윈도우, 세션 윈도우 글로벌 윈도우 4개의 기본 윈도우 할당자를 제공
  • 윈도우 할당자는 입력 데이터를 보고 현재 조건에 만족하는 윈도우가 없으면 새로운 윈도우를 생성하고 데이터를 삽입
  • 하나의 윈도우는 데이터가 모두 담겨있다는 확신이 들면 윈도우 함수를 먹여서 데이터에 연산을 수행하여 데이터를 변환하고 윈도우를 삭제

트리거 (Trigger)

  • 윈도우는 하나의 트리거와 윈도우 함수(Window Function) 를 가지고 있음
  • 함수에는 윈도우에 들어온 데이터에 대해 어떤 연산을 적용할 것인지 정의하고, 트리거는 언제 윈도우에 있는 데이터로 연산을 수행할 지 결정하는 역할을 함
  • 예를 들면, 윈도우 안에 있는 데이터가 4개 이상이라면 혹은 워터마크가 윈도우 종점을 통과했다면 이라는 조건을 달 수 있음

소멸자 (Evictor)

트리거가 발생해서 윈도우를 구체화 하기 전에, 데이터 일부를 연산에서 제외시키도록 결정하는 역할(필터)

Keyed or Non-Keyed Window

  • Flink에서는 keyBy 함수로 데이터의 특정 값을 키로 잡을 수 있음
  • 만약 키를 잡지 않으면 하나의 세션에서 처리, 키를 잡으면 병렬로 처리(카프카에서 PartitionKey)

4가지 기본 Window

1) 텀블링 윈도우 (Tumbling Window)

  • 고정 크기 윈도우라고도 부르며 일정한 크기로 윈도우를 할당, 데이터의 개수가 될수도 있고 시간이 될수도 있음
  • 윈도우의 기준을 이벤트 시간으로 나눌지 프로세싱 시간으로 나눌지도 결정할 수 있고 시간도 밀리초 단위까지 세분화 해서 윈도우를 자를 수 있음

2) 슬라이딩 윈도우(Sliding Window)

  • 슬라이딩 윈도우 또한 고정 크기의 윈도우를 가지는데, window slide parameter 를 지정해서 윈도우가 생성되는 빈도를 결정
  • 즉, 크기와 생성 빈도수를 결정하기 때문에 빈도수를 크기보다 작은 값으로 주면 데이터가 여러 윈도우에 겹치게 됨

3) 세션 윈도우 (Session Window)

  • 세션 윈도우는 특이하게 특정 시간 동안 데이터가 나타나지 않으면 구체화 하는 윈도우
  • 유저 단위로 프로세싱하려고 할 때 사용할 수 있음

4) 글로벌 윈도우(Global Window)

  • 글로벌 윈도우는 같은 키를 가진 모든 데이터를 하나의 전역 윈도우에 담음
  • 글로벌 윈도우는 반드시 커스텀 트리거를 정의해서 사용해야 함, 그러지 않으면 아무런 역할도 하지 않음. 왜냐면 윈도우에 끝 지점이라는게 존재하지 않아서 기본 트리거는 아무런 Firing 도 안하기 때문


5. WaterMark

WaterMark의 중요성은 데이터 처리에 있어서 중요한 역할을 하기 때문에 그 개념과 어떤식으로 사용하는지, 다른 시스템에는 존재하는지 확인하고 비교해보겠습니다.

해당 개념은 이렇게 보면 간단합니다.

워터마크: 지연된 이벤트(out-of-order data)를 다루기 위한 기준 시점

스트리밍 시스템은 실시간으로 들어오는 데이터를 일정 단위(윈도우)로 모아 처리하는데, 실제 발생한 시각과 도착한 시각의 차이는 발생할 수 있기 때문에
이벤트 시간(Event Time) 을 기준으로 처리하되, "언제쯤 데이터를 마감해도 될지" 알려주는 장치가 바로 워터마크

(
실제 세상에서는 10:09 의 데이터가 10:11 에 도착할 수 있기 때문에 인입 시간을 기준으로 윈도우를 구체화 하는 건 데이터가 누락 될 위험이 굉장히 커집니다.)

 

 

 

워터마크는 대체로 휴리스틱(추정)하며, 항상 정확하지는 않습니다.

F(P) -> E 의 형태로 인입 시간을 받으면 이벤트 시간을 리턴하는 함수로 표현할 수 있습니다. 반환된 E는 지금 이 순간 부터 E 이전에 존재하는 모든 데이터를 받았다는 의미로, 다르게 말하면 앞으로는 E 이전의 시간을 가진 데이터가 입력으로 주어지는 일이 없다는 말이 됩니다.

 

완벽한 워터마크를 만들려면?

  1. Apache Kafka 처럼 부분 순서를 보장하는 시스템이 존재하고 이벤트를 완벽히 시간 순서대로 순차적으로 쌓은 경우
    (애초에 순서대로 데이터가 도착한다는 보장이 있으면 완벽한 워터마크를 쉽게 만들 수 있음)
  2. 그냥 프로세싱 시간을 기준으로 윈도우를 구체화
    (이벤트 시간을 무시하는 것이기 때문에 완벽한 워터마크를 만들 수 있음)

위 두가지 경우가 아니라면 워터마크는 항상 휴리스틱 할 수 밖에 없고 완벽한 계산을 요구하는 비즈니스라면 늦게 들어온 데이터(lateness)를 어떻게 처리해야 하는가를 고민해야 함

워터마크는 시스템이 데이터를 수집하는 과정 중에 계속 갱신합니다.
즉, 이벤트가 도착할 때마다:

  1. 그 이벤트의 이벤트 시간을 확인하고
  2. 가장 늦은 이벤트 시간을 추적하고
  3. (그 시간 - 허용 지연 시간) 만큼을 워터마크로 설정
Watermark = max_event_time_seen_so_far - allowed_lateness

허용 지연시간
현실 세계에서 이벤트가 "얼마나 늦게" 도착할 수 있을지를 예상해서 정한 시간 범위입니다.
이 시간 내에 들어온늦은 데이터는 윈도우에 포함되도록 허용하고, 그 이후에 오는 데이터는 버리거나(side output) 별도로 처리

 

워터마크 방식과 코드

1. Bounded Out-of-Orderness (가장 일반적)

  • 이벤트가 max X초 늦게 도착할 수 있음을 가정
  • Watermark = max(event.timestamp) - delay

2. Punctuated Watermarks (데이터 기반 워터마크)

  • 특정 조건을 만족하는 이벤트에서 워터마크를 추출

3. Idleness (Stream 정체 대응)

  • 소스가 일정 시간 이벤트를 안 보낼 경우 워터마크 전파 중단 방지

JAVA code

DataStream<Event> stream = env
  .socketTextStream("localhost", 9999)
  .map(line -> parseEvent(line))
  .assignTimestampsAndWatermarks(
    WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ofSeconds(5))
      .withTimestampAssigner((event, timestamp) -> event.getEventTime())
  );

Flink Table, SQL API

CREATE TABLE sensor_data (
  id STRING,
  ts TIMESTAMP(3),
  value DOUBLE,
  WATERMARK FOR ts AS ts - INTERVAL '5' SECOND
) WITH (
  'connector' = 'kafka',
  ...
);

SparkStreaming

SparkStreaming도 워터마크를 지원하는데 withWatermark() 메소드를 사용해서 WaterMark를 지원함

  • 이벤트 시간 기반 처리 가능
  • 정확한 처리 위해 late event 보존 기간 지정 필요

6. Exactly once

Exactly-once가 중요한 이유는 위에서도 언급을 했는데, flink는 어떻게 exactly-once를 구현하는지를 확인해보고, 다른 시스템과 비교를 해보겠습니다.

스트리밍 시스템들을 보면 정확히 한 번 처리(Exactly Once)하는 것을 아주 중요하게 강조하고 있습니다.

  1. 윈도우가 정확히 한 번 구체화 되었는가?
  2. 데이터가 중복으로 들어가진 않았는가?

1) 윈도우가 정확히 한 번 구체화 되었는가?

  • 윈도우 함수 자체는 멱등(idempotent)하지 않을 수 있기 때문에 한 번만 구체화 되는 것이 중요함

비결정적인 특성

예를 들어 처리 중간에 랜덤 수를 생성하거나, 현재 시각을 사용하는 로직이 있다면:

  • 장애 이전엔 랜덤값 A,
  • 장애 이후 재처리에서는 랜덤값 B → ❌ 결과가 다름

체크포인트

Flink는 주기적으로 다음을 체크포인트에 저장(Amazon S3에 체크포인트를 저장하고 관리)

  • 연산 중이던 연산자들의 상태(state)
  • 처리하던 데이터의 위치(오프셋 등)

→ 결과적으로

  1. 장애 발생 시, 과거 저장된 상태로 되돌아감
  2. 같은 상태 + 같은 입력을 다시 처리
  3. 따라서 결과는 항상 동일하게 유지됨 = 결정적 처리

2) 데이터가 중복으로 들어가진 않았는가?

  • 이는 간단하게 데이터에 고유 ID를 부여해서 윈도우에 중복된 데이터가 들어가 있는지 아닌지만 검증해서 해결할 수 있음
  • 데이터의 중복은 배치, 스트리밍 구분없이 항상 중요한 문제이기 때문에, 중복의 후 처리 로직이 있지 않는 이상, 한 번만 정확히 실행(Exactly once)되는 것이 중요함

3) exactly once를 구현하는 방법, property 예시

kafka 및 sparkstreaming은 조건부로 exactly once를 지원하는 것에 반해 flink는 checkpoint + 상태관리로 Exactly Once를 보장합니다.

Flink가 exactly once를 구현하는 방법

  • Flink는 일정 간격으로 전체 파이프라인의 상태를 체크포인팅
  • Sink 연산(예: Kafka, DB 등)도 2-phase commit 또는 idempotent 방식으로 구성
  • 실패 시 체크포인트 지점부터 복구하여, 중복 없이 재처리

flink는 아래 3가지의 처리 보장 수준을 지원하며, 변경할 수도 있습니다.

모드 의미 보장
AT_MOST_ONCE 최대 한 번 처리 빠르지만 유실 가능
AT_LEAST_ONCE 최소 한 번 처리 유실 없음, 중복 가능
EXACTLY_ONCE 정확히 한 번 처리 가장 안전, Flink의 기본값 

Flink에서 처리 보장 수준 변경 방법

3-1) Java/Scala 코드 설정
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

// 체크포인팅 주기 설정 (필수)
env.enableCheckpointing(5000); // 5초

// 처리 보장 수준 변경 가능
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.AT_MOST_ONCE);
// 또는
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.AT_LEAST_ONCE);
// 또는
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE); // 기본값
 
3-2) Flink 설정 파일 (flink-conf.yaml)에서 설정
execution.checkpointing.mode: EXACTLY_ONCE   # 또는 AT_LEAST_ONCE / AT_MOST_ONCE
execution.checkpointing.interval: 5000ms     # 체크포인트 주기 (필수)

 

728x90

댓글