Search

[Apache Flink] 2. Apache Flink 아키텍처와 구성요소 살펴보기

[Apache Flink] 1. 데이터 파이프라인의 진화: 배치에서 스트리밍으로
Data Engineering
Apache Flink
2025/06/22
[Apache Flink] 1. 데이터 파이프라인의 진화: 배치에서 스트리밍으로
Data Engineering
Apache Flink
2025/06/22
지난 글에서는 데이터 파이프라인이 배치(Batch) 방식에서 스트리밍(Streaming) 방식으로 변화하는 흐름과, Apache Flink가 왜 필요한지에 대해서 이야기해봤습니다.
이번 글에서는 Apache Flink의 실제 아키텍처 구성 요소를 하나씩 살펴보고, Apache Flink가 스트리밍 데이터 처리를 어떻게 지원하는지 자세히 알아보려고 합니다.

Apache Flink 아키텍처 개요

Apache Flink는 실시간 스트리밍 데이터를 처리하기 위한 여러 구성 요소로 이루어져 있습니다. 크게 보면 다음과 같은 요소들이 있습니다.
JobManager - 클러스터의 중앙 컨트롤러
TaskManager - 실제 작업을 수행하는 워커 노드
JobClient - 사용자와 클러스터 간의 인터페이스
Execution Graph - 작업 실행 계획을 나타내는 DAG
Checkpointing - 장애 복구를 위한 상태 저장 메커니즘
State Backend - 상태 데이터 저장소
각 구성 요소가 어떤 역할을 하는지 하나씩 자세히 살펴보겠습니다.

1. JobManager: Flink 클러스터의 컨트롤러

JobManager는 Flink 클러스터의 전체 작업을 관리하는 중앙 컨트롤러입니다. 마스터 노드의 역할을 수행하며, 다음과 같은 중요한 책임을 가집니다.

작업 계획 및 스케줄링

사용자가 제출한 작업(Job)을 받아 최적의 실행 계획을 수립
작업을 작은 단위의 Task로 분할하여 TaskManager에 배포
병렬 처리를 위한 최적의 실행 전략을 결정

리소스 관리

클러스터의 자원(CPU, 메모리)을 모니터링
TaskManager가 작업을 수행할 수 있도록 적절한 리소스를 할당
동적 스케일링을 통해 워크로드에 따른 리소스 조정을 수행

장애 복구 및 체크포인트 관리

체크포인트를 주기적으로 트리거하고 관리
장애 발생 시 체크포인트를 기반으로 작업을 복구
전체 클러스터의 상태를 추적하고 장애 감지를 수행

2. TaskManager: 실제 작업을 수행하는 Worker 노드

TaskManager는 실제 데이터 처리 작업(Task)을 수행하는 워커 노드입니다. 분산 환경에서 실제 연산을 담당하는 핵심 컴포넌트입니다.

데이터 스트림 처리 및 연산 실행

JobManager로부터 받은 Task를 실제로 실행
스트리밍 데이터에 대한 변환, 집계, 필터링 등의 연산을 수행
결과 데이터를 다음 단계의 TaskManager나 외부 시스템으로 전달

Task Slot을 통한 병렬 처리

TaskManager는 Task Slot이라는 개념을 통해 병렬 처리를 지원합니다.
각 TaskManager는 여러 개의 Task Slot을 가짐
하나의 Slot은 하나의 병렬 Task를 실행할 수 있음
Slot의 개수는 TaskManager가 동시에 실행할 수 있는 Task의 개수를 결정

메모리 및 상태 관리

데이터 처리 과정에서 필요한 상태(State)를 효율적으로 관리
상태 데이터를 메모리와 디스크에 저장하여 성능과 지속성을 모두 확보
RocksDB를 활용한 대용량 상태 데이터 처리를 지원

장애 발생 시 복구 지원

체크포인트에 저장된 상태 데이터를 활용하여 장애 복구를 수행
장애 발생 시 가장 최근 체크포인트부터 작업을 재시작
TaskManager 간 상태 데이터 재분배를 통한 동적 복구를 지원

3. JobClient: 사용자와 Flink 클러스터의 연결고리

JobClient는 사용자가 Flink 클러스터에 작업을 제출하고 관리하는 인터페이스 역할을 합니다.

주요 기능

작업 제출: 사용자가 작성한 Flink 프로그램을 JobManager로 제출합니다
작업 모니터링: 실행 중인 작업의 진행 상황과 성능 메트릭을 확인합니다
작업 제어: 작업의 중단, 재시작, 취소 등의 제어 작업을 수행합니다
결과 조회: 작업 실행 결과와 로그를 조회합니다

실행 모드

JobClient는 다양한 실행 모드를 지원합니다.
Detached Mode: 작업 제출 후 JobClient가 종료되는 모드
Attached Mode: 작업이 완료될 때까지 JobClient가 대기하는 모드

4. Execution Graph: 작업의 실행 계획을 나타내는 DAG

Execution Graph는 JobManager가 생성한 실행 계획으로, 사용자의 작업이 실제로 어떻게 처리될지를 DAG(Directed Acyclic Graph) 형태로 표현합니다.

Graph 변환 과정

1.
StreamGraph: 사용자 코드를 기반으로 생성되는 초기 그래프
2.
JobGraph: 최적화가 적용된 논리적 실행 계획
3.
ExecutionGraph: 실제 실행을 위한 물리적 실행 계획
4.
Physical Graph: TaskManager에서 실행되는 최종 형태

최적화 기능

Operator Chaining: 연속된 연산을 하나로 묶어 성능을 향상
Task 병합: 네트워크 오버헤드를 줄이기 위해 관련 Task를 병합
병렬도 결정: 각 연산의 최적 병렬도를 자동으로 계산

5. Checkpointing: 장애 복구와 상태 관리를 위한 메커니즘

체크포인트는 Flink의 핵심 기능 중 하나로, Exactly-Once 처리 보장과 장애 복구를 위해 반드시 필요한 메커니즘입니다.

체크포인트 동작 원리

1.
체크포인트 트리거: JobManager가 주기적으로 체크포인트를 시작
2.
배리어 삽입: 데이터 스트림에 체크포인트 배리어를 삽입
3.
상태 스냅샷: 각 TaskManager가 현재 상태의 스냅샷을 생성
4.
분산 저장: 스냅샷을 안정적인 분산 저장소에 저장
5.
완료 통지: 모든 TaskManager의 체크포인트 완료 후 JobManager에 통지

장애 복구 과정

1.
장애 감지: JobManager가 TaskManager 장애를 감지
2.
체크포인트 복구: 가장 최근 체크포인트를 기반으로 상태를 복구
3.
작업 재시작: 체크포인트 시점부터 작업을 재시작
4.
데이터 정합성 보장: Exactly-Once 처리를 통해 데이터 중복이나 손실을 방지

6. State Backend: 상태 데이터를 저장하는 곳

State Backend는 Flink 작업에서 발생하는 상태 데이터를 저장하고 관리하는 핵심 컴포넌트입니다. 상태의 크기와 성능 요구사항에 따라 적절한 백엔드를 선택할 수 있습니다.

State Backend 유형

Backend 유형
저장 방식
장점
단점
적용 사례
HashMapStateBackend
메모리 저장
• 매우 빠른 성능 • 낮은 지연시간
• 메모리 크기 제한 • 대용량 상태 처리 불가
• 작은 상태 크기 • 높은 성능 요구
EmbeddedRocksDBStateBackend
메모리 + 디스크 (RocksDB)
• 대용량 상태 지원 • 메모리 효율적 • 안정적인 성능
• 디스크 I/O 오버헤드 • 직렬화/역직렬화 비용
• 대용량 상태 • 장기 실행 작업

상태 데이터 유형

Flink에서 관리하는 상태는 크게 두 가지로 분류됩니다.
Keyed State: 특정 키에 연관된 상태 (예: 사용자별 누적 금액)
Operator State: 오퍼레이터 전체에 연관된 상태 (예: Kafka 파티션 오프셋)

Flink SQL로 주문 데이터 처리하는 실제 동작 흐름

상황: 실시간으로 들어오는 주문 데이터를 Flink SQL로 처리해서 실시간 대시보드 테이블을 만든다고 가정
-- 예시: 실시간 주문 집계 테이블 생성 CREATE TABLE order_summary AS SELECT product_id, COUNT(*) as order_count, SUM(amount) as total_amount, TUMBLE_START(order_time, INTERVAL '1' MINUTE) as window_start FROM orders GROUP BY product_id, TUMBLE(order_time, INTERVAL '1' MINUTE);
SQL
복사

1. 작업 제출 단계

1.
사용자가 Flink SQL을 실행
SQL 클라이언트나 애플리케이션에서 위 SQL을 실행
2.
JobClient가 SQL을 JobManager로 전달
SQL 쿼리가 내부적으로 Flink Job으로 변환되어 JobManager에게 전달
3.
JobManager가 실행 계획 생성
"orders 테이블에서 데이터를 읽고 → product_id별로 그룹핑하고 → 1분 윈도우로 집계하고 → 결과를 order_summary 테이블에 저장"
이 과정을 병렬로 처리할 최적의 계획을 수립

2. 작업 실행 단계

1.
JobManager가 TaskManager들에게 작업 배포
TaskManager 1: "orders 테이블에서 데이터 읽기 담당"
TaskManager 2: "product_id별 그룹핑 및 집계 담당"
TaskManager 3: "결과를 order_summary 테이블에 쓰기 담당"
2.
각 TaskManager가 실제 SQL 처리 수행
실시간으로 들어오는 주문 데이터를 1분 단위로 집계
각 상품별 주문 건수와 총 금액을 계산
3.
TaskManager들 간 데이터 스트림 처리
원본 주문 데이터 → 그룹핑/집계 → 최종 결과 테이블로 데이터가 실시간 흐름

3. 상태 관리 및 체크포인트 단계

1.
주기적으로 현재 집계 상태 백업
"현재까지 상품A: 150건 주문, 1,500만원 / 상품B: 80건 주문, 800만원..." 상태를 저장
2.
각 TaskManager가 처리 상태를 State Backend에 저장
현재 처리 중인 윈도우 상태, 부분 집계 결과 등을 저장
3.
체크포인트 완료 후 이전 상태 정리
오래된 체크포인트는 삭제하고 최신 상태만 유지

4. 장애 복구 단계

상황: 집계를 담당하던 TaskManager에 장애 발생
1.
JobManager가 장애 감지
"어? 집계 담당 TaskManager가 응답이 없네?"
2.
최근 체크포인트로 상태 복구
"2분 전 체크포인트에서 상품A: 120건, 1,200만원이었네. 여기서부터 다시 시작하자"
3.
중단된 지점부터 재처리
2분 전 상태로 돌아가서, 그 이후 들어온 주문 데이터들을 다시 집계
중요: 이미 처리된 데이터는 중복 집계하지 않고, 누락된 데이터만 정확히 처리

마무리

Apache Flink의 내부 구조를 하나씩 뜯어보니 꽤 복잡해 보이지만, 결국 핵심은 간단합니다. JobManager가 관리자 역할을 하고, TaskManager들이 실제 업무를 담당하며, 중간에 문제가 생기면 체크포인트로 되돌아가서 다시 시작하는 구조입니다.
다음 글에서는 같은 실시간 처리 영역에서 경쟁하고 있는 Kafka Streams와 ksqlDB를 Apache Flink와 비교해보겠습니다. 각각의 특징과 장단점을 파악해서 어떤 상황에서 어떤 도구를 선택해야 하는지 알아보겠습니다.