Flink Introduction

필자는 Flink가 너무 현업에서 써보고 싶다.. 공부한 기초 내용이라도 간단히 여기 적어 본다.

Flink란?

Flink는 Stream Processing을 위한 오픈소스 Framework이다! 역시 분산처리 시스템이며 따라서 고성능/고가용성 특징이 있다 (Spark처럼 인메모리 연산을 한다). 배치 프로세싱을 지원하기도 한다 (물론 그걸 위해 쓰진 않을거 같다).가장 중요한 점은 Flink는 빠른 속도를 자랑하며, Fault-tolerant하다 (장애 직전으로 돌아갈 수 있다).

Stream Processing은 Batch Processing과 달리 작은 데이터를 실시간으로 전달하는데 쓰인다. 데이터를 무한이라고 가정하고, 처리량보다는 처리속도에 포커스를 둔다.

Flink의 Streaming Dataflow는 하나 이상의 Source로 시작하여 Operators들로 변환을 거치고 Sink로 데이터를 출력하고 저장한다. 이러한 Dataflow는 checkpoint를 설정하여 fault-tolerant하고, exactly once를 보장하고 있다. Flink는 데이터 처리만 하므로 HDFS, Local File System, S3, RDBMS 등의 저장 시스템과 연동이 가능하다. 또한 connector로 쉽게 kafka, redis 등과 연동할 수 있다.

추가적으로 Flink는 Java로 개발이 되었고 내장 메모리 매니저가 있어서 OOM이 잘 나지 않는다. Spark와 같이 DAG로 관리하지않고 Controlled Cyclic Dependency Graph를 가진다.

Flink의 구성을 추상화해본다면, 가장 밑에 Stateful Stream Processing을 두고, Data Stream API, Table API 그리고 SQL로 이루어져 있다.

Stateful Stream Procesing & Timely Stream Processing

Stateful Stream Processing을 이해하기 위해선 State에 대해서 알아야 한다. 여러 이벤트를 한꺼번에 보려고 할때 State가 필요하며 이것을 Stateful하다고 한다. Flink는 Checkpoint와 Savepoint를 이용해 State를 저장하여 Fault tolerant하게 했고 각 State은 Queryable하다. 이러한 State는 Window로 데이터를 모아보거나, Transformation을 하거나 할때 사용한다. State Backend는 크게 2가지가 있는데, 먼저 HashMapStateBackend가 있다. 이는 Java Heap에 저장하고, Hash Table에 변수와 Trigger를 저장해놓는다. 큰 state나 큰 key/value를 저장할때 사용된다. EmbeddedRocksDBStateBackend도 있는데, 이는 RocksDB에 byte array로 serialize해서 저장하고, 매우 큰 state를 저장할 때 사용된다. State는 Checkpointing을 통해 장애 허용을 하는데, 시스템이 망가질 경우 플링크는 작동을 멈추고 checkpoint로 리셋을 한후 dataflow 전체를 re-deploy를 하고 각 operator에게 checkpoint의 state 정보를 주입하고 입력 stream도 체크포인트 시점으로 돌려놓은뒤 재시작을 하게 된다. 이러한 Checkpointing은 Chandy-Lamport 알고리즘 (언젠간 찾아보자..)을 이용해 스냅샷을 만들고 비동기적으로 실행이 된다. Checkpoint를 구현하기 위해 데이터 스트림 중간에 사이사이에 베리어를 넣어 checkpoint를 만들게 된다.

savepoint는 checkpoint와 비슷하지만, 조금 더 expensive하다. Flink 버전을 업데이트하거나 job graph를 바꾸거나 하는 등의 작업을 할때 사용이 된다. 사용자가 지정할 수 있고, checkpoint처럼 자동으로 없어지지 않는다.

checkpoint를 정렬할 수 있는데, 정렬하지않은채 사용하면 조금 빠르지만 at least once가 된다.

Timely Stream Processing은 이것의 연장선이다. 데이터 처리할때 time의 개념이 들어갈때 사용된다. Time은 크게 event timeprocessing time이 있다. Processing Time은 데이터를 처리하는 시스템의 시간으로 빠른 성능을 보이지만, 분산/비동기 환경에서는 이벤트가 시스템에 도달하는 속도에 달려있기때문에 deterministic하지못한다. Event Time은 Event가 생성된곳에서 만들어진 시간이다. Event Time과 Processing Time의 시간이 안맞을 수 있기에 이걸 위한것이 watermark이다. Flink는 워터마크를 통해 event time의 흐름을 잰다. Watermark(t) 라면 적어도 t까진 왔다 라고 하는것이 워터 마크이다. 워터마크가 있음에도 늦는 친구가 있다면 lateness로 추가 이해시간을 줄 수 있다.


Flink는 다음과 같은 아키텍쳐를 가지고 있다. Flink는 크게 Task Manager, Job Manager로 나뉠 수 있다.

Job Manager는 Task를 스케줄링하며 실패/완료된 Task를 관리한다. 또한, 체크포인트 관리 및 Recovery를 담당하고 있다. 크게 3가지 컴포넌트가 있는데 Resource Manager는 task slot을 관리하고, Dispatcher는 Flink App을 등록하는 REST API와 Web UI를 제공하며, JobMaster는 Job Graph를 관리한다 (source - operator- sink를 그리는 graph).

Task Manager (Worker)는 실제로 dataflow의 task를 실행하는 존재이다. Task Slot (Task Manager를 스케줄링하는 가장 작은 단위) 으로 동시에 실행될 수 있는 task들을 설정한다. Task Manager는 JVM process로 여러 쓰레드에서 하나 혹은 여러개의 sub task를 가질 수 있고, 각 Task Manager가 가질 수 있는 task 수는 task slot 수로 조절한다.

Windowing

Windowing이란 스트림 프로세싱의 꽃이다! 스트림으로 들어오는 데이터를 묶어서 처리하는 것을 의미한다. Keyed방식이 있어 Key끼리 묶어서 처리해주는 것이 가능하며, Key 기준으로 병렬처리 해줄 수 있다. 크게 세 가지 방식이 있다. Tumbling Window, Sliding Window, Session Window가 그것이다. Tumbling Window는 시간 블록마다 데이터를 모아보고 싶을때 사용하고 시간만큼 window를 열고 닫는다. Sliding Window는 비슷하지만 업데이트 주기가 더 짧다 (즉 겹칠 수 있다. 주식 같은 것에 좋음). Session Window는 이벤트가 (지속적으로) 들어오는 기준으로 window의 생성과 끝을 결정한다. Window Function은 window안에서 일어날 계산을 정의하는 함수로, ProcessWindowFunction을 이용하여 Window안의 모든 요소 (시간과 state 정보 포함)를 반환한다.

Flink Website를 들어가서 설치하면 된다! tgz 파일을 다운 받은 후 압축을 풀고, pip install apache-flink를 사용해서 pyflink를 다운 받을 수 있다. ./bin/flink run --python example.py 이런식으로 구동할 수 있으며, 8081포트에 UI로 잡을 확인할 수 있다. Pyflink는 Py4J를 이용해 Table API와 Datastream API 위에 연결이 되며, JVM에서 checkpoint, watermark 등이 관리가 된다 (Python VM에선 UDF). 퍼포먼스 최적화는 Data 주고받는 것을 최소화하고, 빠른 Python UDF로 최적화 했다.

Table API와 Datastream API는 어떻게 다른가? Table API는 SQL활용이 가능하고, Batch와 Streaming 둘다에 가능하다. Datastream은 조금 더 generic하고, streaming에 활용가능하다. Custom Logic이 많이 필요하고 복잡한 경우에는 Datastream API를 추천하지만, 아닌 경우엔 Table API가 낫다.

추후에 Flink의 구체적인 사용 예시와 Flink-on-k8s에 대해서도 소개해보겠다.

Reference

실시간 빅데이터 처리를 위한 Spark & Flink Online
https://nightlies.apache.org/flink/flink-docs-release-1.14/