Streaming for the AI age (StreamFusion)

Source: streamfusion.tech/blogs | Published: 2026

ℹ️ 같은 아티클이 dew_284 클리핑에도 중복 포함되어 있다. 그쪽은 이 문서를 가리키는 포인터만 두었다 → Streaming for the AI Age (duplicate)


한 줄 요약

Spark에는 Photon·Gluten·Comet 같은 가속기가 넘치는데 Flink에는 인기 있는 오픈소스 가속기가 없다 — Flink의 플래닝·체크포인팅·오토스케일링은 그대로 두고 실행 레이어만 Rust + Arrow/DataFusion으로 교체하는 프로젝트.

핵심 주장/내용

  • 왜 Flink 가속기인가: Flink는 2014년 Apache 프로젝트가 되었고 Spark와 함께 각자의 영역에서 여전히 지배적이다. 편재성·커뮤니티·프로덕션 경험·다른 도구와의 통합 때문에 벗어나기 어렵지만 성능은 아쉬움이 많다
    • 2022년 Databricks의 Photon이 Spark의 모든 이점(그리고 API·동일 결과)을 유지하면서 성능을 개선하기 위해 실행 엔진을 벡터화 C++ 쿼리 연산자로 재작성했다. 비슷한 시기에 Project Gluten(Meta Velox 실행), Nvidia Rapids(GPU 실행), DataFusion Comet(DataFusion 실행) 등 많은 Spark 가속기가 등장했다. 이들의 설계는 대체로 같은 아키텍처를 공유한다 — Spark에서 분산 컴퓨팅·쿼리 플래닝·잡 스케줄링을 재사용하고 실제로 개별 데이터 항목에 닿는 레이어를 개선한다
    • 놀랍게도 데이터 스트리밍에서는 이 추세가 덜 흔하다. Alibaba(Flash)와 Ververica(Vera-X, 같은 프로젝트)의 클로즈드 소스 엔진 정비가 있고 일반 Flink 대비 5~10배 성능 개선을 주장하지만 유료 벽 뒤에 있다
  • Flink가 정말 가속 가능한가: 스트리밍 데이터는 보통 한 번에 한 row씩 갱신되고 데이터가 종종 Kafka(row 기반)로 오간다. 저자는 JVM을 걷어내고 컬럼 배치로 작동하는 것의 이점이 스스로를 증명한다고 본다
    • Flink 잡이 전부 손으로 쓴 Java(DataStream API)라 가속 불가라는 인상이 있을 수 있지만 SQL/Table API가 최근 몇 년 크게 인기를 얻었다. Confluent와 AWS가 관리형 Flink SQL 잡을 밀고 있고, 저자가 대화한 다른 대형 미국 테크 기업은 수천 개 잡 중 3분의 1이 SQL로 작성되어 있다고 알려줬다. RisingWave, Arroyo 같은 신규 스트리밍 시스템은 SQL을 1급 시민으로 만들어 설계되었다. 미리 정의된 연산자 수가 제한적이므로 Flink 호환 구현을 직접 써서 성능을 개선할 수 있다
  • 왜 컬럼 배치인가: 전통 시스템은 배치든 스트리밍이든 for 루프에서 한 번에 한 row를 다룬다. 비교적 최근 역사에서 CPU가 (네트워크·디스크 I/O가 아니라) 주된 쿼리 병목이 되었고, 흔한 대응이 데이터 청크를 “벡터”로 처리해 한 번에 한 row가 아니라 한 컬럼씩 연산하는 것이다
    • 도움이 되는 이유: 같은 연산을 반복하면 연속된 메모리 바이트 prefetching으로 CPU 캐시 지역성이 좋아지고 tight loop로 반복할 수 있다. 또한 같은 데이터 타입에 같은 단순 연산을 여러 번 하면 CPU SIMD 명령을 더 활용해 단일 스레드 내 병렬성을 얻는다
    • Apache Arrow가 컬럼 지향 인메모리 표현의 표준 포맷(Java, Rust, C++, Go, Python 라이브러리)을 제공하고 기존 쿼리 엔진의 지원이 많아 자연스러운 building block이다. 그 위에 Apache DataFusion을 실행 레이어의 주력으로 — Rust 라이브러리라 JVM과 GC가 없고 메모리 할당에 세밀한 통제가 가능하며 표준 SQL 쿼리 연산에 고도로 최적화되어 있다. 모듈러하게 만들어져 필요한 부분(컴퓨트 프리미티브)만 떼어 쓰고 필요 없을 수 있는 부분(SQL 파서·옵티마이저)은 피할 수 있고, Arrow 버퍼를 1급 시민으로 다뤄 zero-copy 입출력이 된다
    • 다만 DataFusion 자체는 배치 처리에 집중하므로 특정 projection·filter·(윈도우) 조인·집계는 빨라져도 Flink SQL 연산자 전체 스펙트럼을 커버할 수 없다. 이를 위해 직접 최적화 코드를 써야 하고, 다행히 RisingWave와 Arroyo 같은 Rust 기반 스트리밍 엔진이 이미 컬럼형 스트리밍 시스템을 처음부터 구현해 영감이 된다
    • StreamFusion 연산자는 여전히 Flink의 체크포인팅·오토스케일링·플래닝·모니터링 메커니즘에 hook한다
  • 플래닝 레이어 — “all-or-nothing” 가속: Flink가 특정 잡의 플랜을 세우게 하고 그 플랜을 훑어 어느 Flink SQL 연산자를 네이티브 실행으로 변환할 수 있는지 판단한다. 매우 단순한 휴리스틱 — 전체 플랜이 가속되거나 아니거나. 판단은 중간 노드(source·sink 제외)를 보고, 각각이 가속 가능하면 전체가 가속된다
    • 개별 노드의 가속을 두 기준으로 gate한다: 네이티브 버전을 실제로 구현했는지, 그리고 정확성 이유로 재구현하기 어려운 연산자인지. 좋은 예가 regex 평가로 Java와 Rust 사이에서 미묘하게 다른 값을 반환할 수 있다. 그런 연산에는 결과가 동일하지 않을 대가를 치르고 가속할 토글을 노출할 수 있다. Flink 결과와의 정확한 parity가 north star
    • 중간 노드는 서로 Arrow 배치로만 소통한다. Parquet 파일 같은 일부 source/sink는 이미 컬럼형이라 Arrow 변환에 성능 페널티가 거의 없지만, 다른 경우 row ↔ 컬럼 배치 전치가 필요하고 이 연산을 효율적으로 만드는 것이 좋은 성능에 결정적
  • stateful 연산자 — Flink의 체크포인팅에 hook: 상태 관리와 체크포인팅이 Flink의 최대 가치이므로 가속기가 거기에 hook해야 하지만 Flink의 asynchronous barrier snapshotting 알고리즘을 Rust로 재구현하고 싶지는 않다. 대신 체크포인트와 watermark가 평소처럼 JVM에서 job graph를 흐르게 두고, 네이티브 연산자(Java hook + JNI로 호출되는 Rust 로직)에 도달하면 그 연산자의 체크포인팅·스냅샷 로직이 트리거된다
    • 다른 스트림 처리 시스템은 다른 체크포인팅 알고리즘을 쓸 수 있어(예: Feldera는 DBSP 기반) 연산자를 slot in하기 어렵지만, Arroyo와 RisingWave(그리고 C++로 쓰인 TimePlus Proton)는 Flink와 같은 Chandy-Lamport식 barrier-passing 기반이라 코드를 쉽게 포팅할 수 있다
    • StreamFusion stateful 연산자는 필요에 따라 keyed “raw state” 를 쓴다 — 연산자 상태 바이트가 Java에게는 불투명하지만 잡 생성 시점에 정적으로 정의된 key group(잡의 max parallelism 기반)과 연관되어 Flink가 해석하는 법을 안다. 잡이 스케일하면 Flink가 상태 내부를 해석하지 못해도(불투명한 blob으로 보일 뿐) 적절한 key group을 각 병렬 task 호출에 재분배할 수 있다. 정렬·비정렬 체크포인트 모두에서 작동
    • 이것이 제대로 작동하려면 Flink의 해싱 로직을 정확히 복제해 들어오는 row가 키에 따라 적절한 task로 라우팅되어야 한다. Flink는 row 키의 정확한 바이트로 라우팅을 결정하므로 Flink 내부 binary row layout의 Rust 표현이 필요했고, 다행히 Paimon과 Fluss Rust 클라이언트에 이미 있는 로직을 빌려왔다
  • 커스텀 커넥터: Flink는 기본적으로 RowData(Flink 내부 row 표현)로 작동해 모든 source가 출력을 RowData로 변환하고 모든 sink가 RowData를 입력으로 받아야 한다. 모든 source 바이트를 Arrow 배치로 바꾸려고 RowData로 변환하는 것은 낭비다. Kafka 데이터가 (Confluent) Avro·JSON·Protobuf일 수 있는데, 브로커의 바이트에서 RowData로의 변환을 건너뛰고 바로 Arrow 버퍼로 디코딩하려고 포맷별로 여러 접근·라이브러리를 벤치마킹하고 가능한 곳에서 SIMD 디코딩 구현(simd-json, arrow-avro)을 활용했다
    • 현재는 Flink Kafka 호환성과 코드 단순성을 극대화하기 위해 브로커 폴링·쓰기 자체는 여전히 Java 클라이언트로 하고 직렬화·역직렬화만 네이티브다. 향후 API 호출 자체를 네이티브 레이어로 내려 더 많은 성능을 얻을 수 있다
  • 테스트 — AI로 만드는 것에 대한 정당화: “어떻게 그걸 신뢰할 수 있나” 가 첫 질문인데, 저자는 StreamFusion이 AI로 만들기 좋은 프로젝트라고 본다. 이미 존재하는 것을 큰 테스트 케이스 스위트와 함께 재구현하는 것이기 때문이다. Flink와 StreamFusion 사이의 big data parity harness(출력, 중간 결과, 스케일링·라우팅 시맨틱 모두)를 만들고, 기존 Flink SQL 테스트(및 커넥터 Flink SQL 테스트)를 CI에 포함시켰다 (DataFusion Comet에서 영감)
  • 벤치마크 — 최악 시나리오를 일부러 테스트: Spiral 창업자 Will Manning의 벤치마크 “steelman” 원칙을 따라 StreamFusion의 최악 시나리오인 row 지향 데이터가 source로 들어와 sink로 나가는 경우를 의도적으로 테스트했다. Kafka 파티션 4개를 입출력으로 하는 Nexmark(표준 스트리밍 벤치마크) 스위트를 exactly-once 체크포인팅으로 돌려 byte-identical 결과셋과 함께 Flink 대비 33% 이상 높은 처리량을 이미 달성. 0.1.0 버전에서 코드 복잡도 증가를 대가로 하는 일부 최적화를 의도적으로 피한 상태이고 전반적으로 2배가 쉬운 목표라고 본다
  • AI와 오픈소스 리뷰: Iceberg, DataFusion, Comet, Arrow-Java, Paimon에 기여하며 공통적으로 느낀 것은 리뷰어 대역폭이 제한적이라는 것 — 특히 코드 작성이 그 어느 때보다 빨라지고 읽기는 그 어느 때보다 어려워진 AI 시대에. 기여자로서 리뷰어 대역폭·피드백 루프의 부재가 오픈소스 기여를 망설이게 하는 가장 큰 낙담 원인
    • StreamFusion이 독특한 이유는 가속기 프로젝트이기 때문이다. 아키텍처 결정은 있지만 StreamFusion이 자기 공개 API를 결정하지 않는다. Flink가 한다. 그리고 목표가 “Flink와 정확히 parity, 내부적으로는 가능한 한 빠르게” 로 매우 명확하다. 비교할 baseline이 있으므로 AI가 작업하고 최적화하기에 완벽한 유형의 문제
    • 목표하는 리뷰 프로세스: 사람이 먼저 플래닝·아키텍처 문서에 sign off하고, 그다음 AI가 코드 자체를 리뷰해 계획을 지키는지 확인하며, 모호함과 판단 호출은 사람에게 되돌린다
  • 향후: 첫 타겟 유스케이스(Kafka source, Kafka sink)가 실제로는 StreamFusion이 최종 사용자에게 가장 적은 이득을 주는 곳이라는 높은 확신. 적어도 하나의 비싼 source나 sink 연산자가 본질적으로 컬럼형인 상황(Parquet/ORC/Vortex/Lance, Apache Fluss 브로커, ADBC)이 진짜 값어치를 할 곳

관련 위키


Source: 원문 보기