Skip to content
Published on

ストリーム処理 2026 完全ガイド - Kafka Streams・Flink SQL・RisingWave・Materialize・Arroyo・ksqlDB・Bytewax・Decodable 徹底解説

Authors

プロローグ — 「リアルタイムでお願い」という一言の重さ

2026年のあるフィンテックの会議室。

PM: 「リアルタイム不正検知ダッシュボード作れますよね?」 エンジニア: 「リアルタイムってどのくらい?」 PM: 「えっと... すぐに?」 エンジニア: 「1秒?100ミリ秒?それとも5分?」

この短い会話に 2026年のストリーム処理のすべてが詰まっている。一方には「Kafka からデータを取ってくればリアルタイムだ」という漠然とした期待があり、もう一方にはウィンドウ、ウォーターマーク、exactly-once、バックプレッシャー、状態バックアップを毎日触っているエンジニアのため息がある。その間を Flink、Kafka Streams、RisingWave、Materialize、Arroyo、ksqlDB、Bytewax が埋めている。

2026年現在、ストリーム処理は三つのパラダイムに分かれる。プログラミングフレームワーク(Flink、Kafka Streams、Bytewax)、SQL ストリーミング DB(RisingWave、Materialize、ksqlDB)、そしてマネージド SaaS(Decodable、Confluent Cloud Flink、Aiven Flink、Quix)。さらにその上に状態管理モデルの二軸が重なる — 組み込み RocksDB vs S3 上の Disaggregated State。

本記事はその全地形を一気に整理する。Flink 2.0 の Disaggregated State Backend から、RisingWave 2.x の Postgres ワイア、Materialize の Differential Dataflow、Arroyo の Rust SQL エンジン、ksqlDB の Confluent による収束、Bytewax の Python での飛躍、そして韓国・日本のビッグテックが何をどう使っているかまで。


1章 · 2026年ストリーム処理の地図 — Framework / Stream DB / Managed の 3 パラダイム

まず用語から。「ストリーム処理」という一語の中に違う三つが入っている。

パラダイム意味代表利用者
Stream Processing Frameworkコードでトポロジーを書く(DataStream、KStream)Flink、Kafka Streams、Bytewax、Beamデータエンジニア
Streaming DatabaseSQL でビューを定義、incremental に計算RisingWave、Materialize、ksqlDBアナリスト、バックエンド
Managed Streaming SaaS上記をホスティングDecodable、Confluent Cloud Flink、Quix小規模チーム

2026年には境界が曖昧になった。Flink は Materialized Tables を追加し、RisingWave は Rust UDF を受け入れ、Kafka Streams は事実上 ksqlDB の後継として吸収されつつある。

それでも選択の出発点はパラダイムだ。次の意思決定ツリーを推奨する。

  1. 「Kafka トピック間のデータ変換と集計だけ必要」 → Kafka Streams(Java/Scala)または ksqlDB(SQL)。
  2. 「複雑なウィンドウ/ジョイン/CEP、非 Kafka ソース、ペタバイト級」 → Flink(SQL または DataStream API)。
  3. 「アプリは Postgres でクエリしたい、Materialized View が自動更新されてほしい」 → RisingWave または Materialize。
  4. 「Python データサイエンティストが直接使えなければ」 → Bytewax または Quix。
  5. 「運用したくない、SaaS で済ませたい」 → Decodable、Confluent Cloud Flink、Aiven Flink。
  6. 「Rust モノトーンワークロード、シングルバイナリ」 → Arroyo。

Flink がハンマーなら全ての問題が釘になる。2026年のベテラン曰く「秒間1万件のイベント、単純集計なら ksqlDB か Materialize で十分だ。Flink クラスター運用は後悔する」。


2章 · ストリーミング vs バッチ vs マイクロバッチ — レイテンシのスペクトラム

まずパラダイムそのものから。

モデル処理単位レイテンシ代表
Batch大きなデータセット一括分〜時間Spark batch、Hive、dbt
Micro-batch小バッチを定期実行秒〜分Spark Structured Streaming、Trino on Iceberg
True streamingイベント1件ずつms〜秒Flink、Kafka Streams、RisingWave
Continuous queryビュー結果を incremental 更新秒〜分Materialize、RisingWave、Snowflake Dynamic Tables

Spark Structured Streaming のマイクロバッチは毎回小さなバッチジョブを回す。P99 は通常 1〜10秒。Flink は真の record-at-a-time(または mini-batch モード)で P99 100ms 未満が可能。だから HFT、ゲームマッチング、不正検知は Flink/Kafka Streams、分析ダッシュボードは Materialize/RisingWave、日次レポートは Spark/Trino へと流れる。

核心は「1秒以内のリアルタイムがビジネス価値を生むか」という問いだ。多くの BI ダッシュボードは 5分遅延でも問題ない。それならマイクロバッチで十分。本物のストリーム処理は「1秒の遅延が売上を左右する」場所でのみ必要だ。


Apache Flink は 2014年の Stratosphere プロジェクトに始まり、data Artisans(現 Ververica、Alibaba 買収)が主導。2025年3月にリリースされた Flink 2.0 が転換点だ。本章では Flink の SQL/Table API/DataStream API/状態/ウォーターマーク/exactly-once を一気に整理する。

Flink 2.0 の主要変更。

  • Disaggregated State Backend (ForSt): state を broker のディスクではなく S3/GCS に置き、ローカルキャッシュで hot データを保持。状態にも tiered storage が来た。
  • Async State API: 状態アクセスを非同期化し P99 を改善。
  • Materialized Tables (FLIP-435): SQL でビュー定義 → バックグラウンドで incremental refresh。RisingWave/Materialize の領域を正式に吸収。
  • Adaptive Batch Scheduler のデフォルト化: ストリームとバッチを同じエンジンで。
  • Java 17 ベースライン、Scala 2.13 移行完了、Python 3.12 対応。

Flink のアーキテクチャは 4層。

責務
Flink SQLANSI SQL、Catalog、Hive 互換CREATE TABLE orders ...
Table APIリレーショナル API(Java/Scala/Python)table.groupBy("user").select(...)
DataStream API低レベル変換dataStream.map().keyBy().window()
Stateful Functions / ProcessFunction最低レベル、直接状態RichFlatMapFunction

Flink SQL で Kafka トピックを読み込みジョインする例。

CREATE TABLE orders (
  order_id BIGINT,
  user_id BIGINT,
  amount DECIMAL(10,2),
  event_time TIMESTAMP_LTZ(3),
  WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
  'connector' = 'kafka',
  'topic' = 'orders',
  'properties.bootstrap.servers' = 'kafka:9092',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'avro-confluent',
  'avro-confluent.schema-registry.url' = 'http://schema-registry:8081'
);

CREATE TABLE users (
  user_id BIGINT,
  segment STRING,
  PRIMARY KEY (user_id) NOT ENFORCED
) WITH (
  'connector' = 'jdbc',
  'url' = 'jdbc:postgresql://pg:5432/app',
  'table-name' = 'users'
);

SELECT
  segment,
  TUMBLE_START(event_time, INTERVAL '5' MINUTE) AS window_start,
  SUM(amount) AS revenue
FROM orders o
JOIN users u ON o.user_id = u.user_id
GROUP BY segment, TUMBLE(event_time, INTERVAL '5' MINUTE);

この一つのクエリに Flink の核心が全部入っている — Kafka source、JDBC lookup、watermark、tumbling window、group-by aggregate。


Flink SQL では表現できない領域もある。複雑な状態機械、カスタムパーティショニング、動的ルーティング、CEP など。そのとき DataStream API の出番だ。

Java の例 — ユーザー別セッションウィンドウとアラート。

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(30_000); // 30s

DataStream<Event> events = env.fromSource(
    KafkaSource.<Event>builder()
        .setBootstrapServers("kafka:9092")
        .setTopics("clicks")
        .setStartingOffsets(OffsetsInitializer.earliest())
        .setValueOnlyDeserializer(new EventDeserializer())
        .build(),
    WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ofSeconds(5))
        .withTimestampAssigner((e, ts) -> e.eventTimeMs()),
    "kafka-source"
);

events
    .keyBy(Event::userId)
    .window(EventTimeSessionWindows.withGap(Time.minutes(10)))
    .process(new ProcessWindowFunction<Event, Alert, Long, TimeWindow>() {
        @Override
        public void process(Long userId, Context ctx, Iterable<Event> elems, Collector<Alert> out) {
            int count = 0;
            for (Event e : elems) count++;
            if (count > 100) out.collect(new Alert(userId, count, "abusive"));
        }
    })
    .sinkTo(KafkaSink.<Alert>builder()
        .setBootstrapServers("kafka:9092")
        .setRecordSerializer(...)
        .setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
        .build());

env.execute("session-alert");

形は keyBy → window → process。keyBy が同一キーのイベントを同タスクにルーティング、window が時間/セッションでまとめ、process がウィンドウ単位で結果を出す。

状態は RichFunction 経由でアクセス。

public class FraudDetector extends KeyedProcessFunction<Long, Tx, Alert> {
    private transient ValueState<Double> lastAmount;
    private transient ListState<Tx> recentTxs;

    @Override
    public void open(Configuration cfg) {
        lastAmount = getRuntimeContext().getState(
            new ValueStateDescriptor<>("last", Double.class));
        recentTxs = getRuntimeContext().getListState(
            new ListStateDescriptor<>("recent", Tx.class));
    }

    @Override
    public void processElement(Tx tx, Context ctx, Collector<Alert> out) throws Exception {
        Double prev = lastAmount.value();
        if (prev != null && tx.amount() > prev * 10) {
            out.collect(new Alert(tx.userId(), "amount-spike"));
        }
        lastAmount.update(tx.amount());
        recentTxs.add(tx);
    }
}

Flink は ValueState、ListState、MapState、ReducingState、AggregatingState を提供する。全て keyed scope で、同じキーのイベント同士でのみ共有される。


Flink の強みは exactly-once セマンティクスだ。Kafka source + Kafka sink のとき、障害が起きても結果に重複も欠落もなく正確に 1回適用される。どうやって?

核心は Chandy-Lamport アルゴリズムに基づく分散スナップショット。

  1. JobManager が定期的に checkpoint barrier を source に注入。
  2. Barrier がデータと共に dataflow を下流に流れる。
  3. 各 operator が barrier を受け取ると自身の状態をスナップショット。
  4. Sink が barrier を受け取ると sink 固有の commit(Kafka は transactional producer commit)。
  5. 全 operator が ack するとチェックポイント完了。

障害時。

  1. 最後の成功した checkpoint から全 operator の状態を復元。
  2. Source は当該 checkpoint の offset から再読込。
  3. Sink は transactional producer なので committed transaction のみ外部に見える。

設定例。

env.enableCheckpointing(60_000);
env.getCheckpointConfig().setCheckpointStorage("s3://flink-state/checkpoints");
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(30_000);
env.getCheckpointConfig().setCheckpointTimeout(300_000);
env.getCheckpointConfig().enableUnalignedCheckpoints();
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
env.setStateBackend(new EmbeddedRocksDBStateBackend());

Flink 2.0 の ForSt(Disaggregated state)は RocksDB を S3 にバックアップする方式。状態がペタバイト規模でも broker ディスクに縛られない。


ストリーム処理の中心的抽象はウィンドウだ。無限ストリームを有限のチャンクに切る方法。

ウィンドウ意味
Tumbling重ならない固定サイズ5分単位の売上
Sliding重なる固定サイズ30秒ごとに直近5分平均
Session非アクティブギャップ基準30分無活動でセッション終了
Global全体無限全体カウント(状態無限増加のリスク)

Tumbling の例(Flink SQL)。

SELECT
  TUMBLE_START(event_time, INTERVAL '5' MINUTE) AS w_start,
  COUNT(*) AS cnt
FROM clicks
GROUP BY TUMBLE(event_time, INTERVAL '5' MINUTE);

Sliding(HOP)。

SELECT
  HOP_START(event_time, INTERVAL '30' SECOND, INTERVAL '5' MINUTE) AS w_start,
  AVG(latency) AS avg_latency
FROM requests
GROUP BY HOP(event_time, INTERVAL '30' SECOND, INTERVAL '5' MINUTE);

Session。

SELECT
  user_id,
  SESSION_START(event_time, INTERVAL '30' MINUTE) AS s_start,
  COUNT(*) AS events_in_session
FROM user_events
GROUP BY user_id, SESSION(event_time, INTERVAL '30' MINUTE);

ウィンドウ選択の基準。

  • 固定周期レポート(時/日別): Tumbling。
  • 移動平均、ホットメトリクス: Sliding(slide を小さく)。
  • ユーザー行動分析: Session。
  • 不定区間の状態機械: ProcessFunction + timer。

7章 · イベント時刻 vs 処理時刻 — ウォーターマークの本質

ストリーム処理で最も難しい概念。「イベント時刻」はイベントが実際に発生した時刻、「処理時刻」はシステムがそれを見た時刻。二つは違う。

  • モバイルアプリがオフラインのときに発生したイベントが10分後に到着。
  • ネットワーク遅延で一部が遅れて到着。
  • システムが一時停止して目覚めた。

ウォーターマーク (watermark) は「この時刻より前のイベントはもう来ないと仮定してよい」というシグナル。ウォーターマークはウィンドウクローズ、結果 emit、late data 分離のトリガーだ。

Flink のウォーターマーク戦略。

WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ofSeconds(10))
    .withTimestampAssigner((event, ts) -> event.eventTimeMs())
    .withIdleness(Duration.ofMinutes(1));

forBoundedOutOfOrderness(10s) の意味は「私が見た最大イベント時刻が T なら、T-10s より前のイベントだけ処理する。それ以降に到着したら late data」。

Late data 処理。

SingleOutputStreamOperator<Result> main = stream
    .keyBy(...)
    .window(TumblingEventTimeWindows.of(Time.minutes(5)))
    .allowedLateness(Time.minutes(2))
    .sideOutputLateData(lateTag)
    .process(...);
DataStream<Event> late = main.getSideOutput(lateTag);

ウォーターマークは正確性と遅延のトレードオフだ。短ければ結果は早いが late data が多く、長ければ正確だが結果が遅い。


8章 · CEP — Complex Event Processing

CEP はイベントパターンマッチングだ。例:「ログイン失敗 5回連続 → アカウントロック」「5分以内に決済 → 返金 → 決済 → 不正疑い」。

Flink CEP の例。

Pattern<LoginEvent, ?> pattern = Pattern.<LoginEvent>begin("first")
    .where(SimpleCondition.of(e -> !e.success()))
    .next("repeat")
    .where(SimpleCondition.of(e -> !e.success()))
    .times(4)
    .within(Time.minutes(5));

PatternStream<LoginEvent> ps = CEP.pattern(events.keyBy(LoginEvent::userId), pattern);
DataStream<Alert> alerts = ps.select(match -> {
    LoginEvent last = match.get("repeat").get(3);
    return new Alert(last.userId(), "5-fail-in-5min");
});

CEP は Flink CEP、Esper(長い歴史)、Drools Fusion(ルールエンジン系)が代表。不正検知、IDS、取引ルール、IoT アラートの核心。

CEP の難しさは状態管理。5分のパターンなら 5分分の部分マッチを全部持つ必要がある。トラフィックの多い場所で state が爆発する。解決策は partition by key + state TTL + パターン単純化。


9章 · Kafka Streams 4.0 — ライブラリとしてのストリーム処理

Kafka Streams は Confluent が Kafka 0.10(2016)に追加したライブラリだ。Flink が「分散クラスターにジョブを投入」なら、Kafka Streams は「自分の Spring Boot アプリに import して使うライブラリ」。

2025年リリースの Kafka Streams 4.0 のハイライト。

  • Share Groups (KIP-932) との統合 — 同じトピックをキューのように消費。
  • Async Processing API — non-blocking I/O フレンドリー。
  • State Store on RocksDB 7.x — 圧縮向上、faster recovery。
  • Java 17 ベースライン、実験的 GraalVM Native Image サポート。
  • Kafka Streams DSL 安定化 — KTable.join、KStream-KTable join のバリエーション拡充。

Kafka Streams の二つの抽象。

  • KStream: 無限の record stream(insert-only)。
  • KTable: キー別の最新値を保持する changelog ベースのテーブル。

ワードカウントの基本例(Java)。

Properties props = new Properties();
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "wc-app");
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092");
props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> source = builder.stream("text-input");
KTable<String, Long> counts = source
    .flatMapValues(v -> Arrays.asList(v.toLowerCase().split("\\W+")))
    .groupBy((k, v) -> v)
    .count();
counts.toStream().to("word-count-output", Produced.with(Serdes.String(), Serdes.Long()));

KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();

Kafka Streams の魅力はただのライブラリであること。同じ jar を N 個立てれば自動でパーティションを分け合う(Kafka consumer group + 内部リバランス)。別途クラスターマネージャ不要。Spring Boot、Quarkus、Micronaut どこにでも埋め込める。


10章 · Kafka Streams の状態 + Interactive Queries

KTable と aggregate は state store に保存される(デフォルト RocksDB、in-memory も可)。そしてその状態を外部から直接クエリできる(Interactive Queries)。

Interactive Queries の例。

ReadOnlyKeyValueStore<String, Long> store = streams.store(
    StoreQueryParameters.fromNameAndType("word-counts", QueryableStoreTypes.keyValueStore())
);
Long count = store.get("kafka");

ここで強力なパターン — Streams App = マイクロサービス。Kafka からデータを読み、自前 RocksDB に集計結果を保存、REST API で外部に公開。別途 OLAP DB なしでリアルタイムビューを提供。

代償は分散 state の複雑さ。どのキーがどのインスタンスにあるか知る必要がある。Kafka Streams は metadataForKey() API でそれを教えてくれ、gRPC/REST ルーティングは自分で書く必要がある。

GlobalKTable で小さな lookup テーブルを全インスタンスにレプリケートすることもできる(全パーティションを全インスタンスが読む)。

Kafka Streams は **「Kafka にあるデータのみ」**を処理する。外部 JDBC、REST API とのジョインは限定的(Kafka Connect で先に sourcing する必要)。これが Flink との最大の違い。


11章 · ksqlDB 0.30 — SQL on Kafka の興亡

ksqlDB は Confluent が 2017年に公開した「Kafka 上の SQL データベース」。内部的に Kafka Streams を使用。一行 SQL クエリを投げるとバックグラウンドのストリーミングジョブが回る。

CREATE STREAM orders (
  order_id BIGINT KEY,
  user_id BIGINT,
  amount DECIMAL(10,2)
) WITH (KAFKA_TOPIC='orders', VALUE_FORMAT='AVRO');

CREATE TABLE user_revenue AS
  SELECT user_id, SUM(amount) AS total
  FROM orders
  GROUP BY user_id
  EMIT CHANGES;

SELECT * FROM user_revenue WHERE user_id = 42 EMIT CHANGES;

最後の EMIT CHANGES は「継続的に結果の変化を push」という意味。これがストリーミング SQL の本質だ。

ksqlDB 0.30(2025)は事実上最後のメジャーリリース。Confluent が 2025年初頭に発表した方向は 「ksqlDB → Flink SQL」。すなわち Confluent Cloud の SQL ストリーミングは Flink に統合され、ksqlDB はメンテナンスモードへ。新規プロジェクトは Flink SQL 推奨。

それでも ksqlDB は多くの場所で稼働中だ。マイグレーションパスが重要な理由。


12章 · RisingWave 2.x — Postgres ワイア上のストリーミング DB

RisingWave は 2021年に Singularity Data(現 RisingWave Labs)が始めた Rust ベースのストリーミング DB。2025年リリースの RisingWave 2.0 を一行で要約すると「Postgres のように見えるが中で streaming SQL が走る」。

主要特徴。

  • Postgres wire protocol 100% 互換: psql、JDBC、ORM がそのまま動く。
  • Materialized Views が一級市民: CREATE MATERIALIZED VIEW が incremental streaming ジョブ。
  • Rust エンジン、thread-per-core: 低オーバーヘッド、安定した P99。
  • S3 に state オフロード: 初日から Disaggregated state。
  • Cluster + Cloud + Standalone のデプロイモード
  • CDC source 内蔵: Postgres、MySQL の binlog 直読。

基本使用例。

CREATE SOURCE orders_source (
  order_id BIGINT,
  user_id BIGINT,
  amount NUMERIC,
  event_time TIMESTAMPTZ
) WITH (
  connector = 'kafka',
  topic = 'orders',
  properties.bootstrap.server = 'kafka:9092',
  scan.startup.mode = 'earliest'
) FORMAT PLAIN ENCODE JSON;

CREATE MATERIALIZED VIEW hourly_revenue AS
SELECT
  date_trunc('hour', event_time) AS hour,
  SUM(amount) AS revenue,
  COUNT(*) AS orders
FROM orders_source
GROUP BY 1;

SELECT * FROM hourly_revenue ORDER BY hour DESC LIMIT 24;

最後の SELECT が魔法だ。RisingWave は hourly_revenue をバックグラウンドで incremental に更新しており、クエリはその結果の現在状態を即座に返す。なので OLAP DB のようにユーザーが直接ダッシュボードでクエリしてもよい。

RisingWave 2.x の新機能。

  • Iceberg Sink + Iceberg Source: データレイクと直結。
  • Python / JavaScript / Rust の UDF
  • Subscription: Postgres LISTEN/NOTIFY のような変更購読。
  • Snowflake / BigQuery / Redshift sink

13章 · Materialize — Differential Dataflow の商用化

Materialize は 2019年に Frank McSherry(Microsoft Research、Naiad/Differential Dataflow の著者)と Arjun Narayan が創業。一行で要約すると「本物の incremental view maintenance」。

主要な違い。

  • Differential Dataflow エンジン: 1996年から研究されている本物の incremental 計算。delta だけ伝播。
  • Postgres ワイア: RisingWave のように psql/JDBC 互換。
  • SQL 99% カバー: Postgres 互換 dialect、recursive CTE まで。
  • Strict serializability: 全クエリが一貫したスナップショットを見る。
  • 2024年に Cloud リリース: セルフホストも可能だが事実上 SaaS 優先。

基本例。

CREATE SOURCE orders FROM KAFKA BROKER 'kafka:9092' TOPIC 'orders'
  FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY 'http://schema-registry:8081'
  ENVELOPE NONE;

CREATE MATERIALIZED VIEW revenue_by_segment AS
SELECT
  u.segment,
  SUM(o.amount) AS revenue
FROM orders o
JOIN users u ON o.user_id = u.user_id
GROUP BY u.segment;

SELECT * FROM revenue_by_segment;

Materialize の差別性は任意の SQL を incremental にすること。一般的なストリーミング SQL は group by aggregate、window などの定型パターンだけ incremental。Materialize は join、subquery、recursive CTE まで incremental。

代償は state メモリ。Differential Dataflow は基本インメモリ(ディスク spill オプション追加中)。なので大規模は RisingWave、複雑な SQL は Materialize が強み。


Arroyo は 2023年に Micah Wylde(Lyft Streaming 出身)が始めた Rust ベースのストリーミングエンジン。一行で要約すると「Flink SQL 互換 + シングルバイナリ + 速い」。

主要特徴。

  • Rust エンジン: JVM なしのシングルバイナリ。
  • Arroyo SQL = Flink SQL 互換サブセット
  • Web UI 優先: ジョブ作成と監視が SaaS のよう。
  • S3 state: tiered、RocksDB なし。
  • Kubernetes operator 提供。

CLI でジョブ作成。

docker run -p 8000:8000 ghcr.io/arroyosystems/arroyo:latest

Web UI で SQL 入力。

CREATE TABLE events (
  user_id BIGINT,
  event_type TEXT,
  amount FLOAT,
  ts TIMESTAMP
) WITH (
  connector = 'kafka',
  bootstrap_servers = 'kafka:9092',
  topic = 'events',
  type = 'source',
  format = 'json',
  'event_time_field' = 'ts',
  'watermark_field' = 'ts'
);

CREATE TABLE sinks WITH (connector = 'kafka', topic = 'alerts', type = 'sink', format = 'json');

INSERT INTO sinks
SELECT user_id, SUM(amount) AS total
FROM events
WHERE event_type = 'purchase'
GROUP BY user_id, TUMBLE(INTERVAL '5' MINUTE);

Arroyo は 2026年時点で production 採用が増えている。**「Flink を運用したくない、かつ Confluent に縛られたくない」**チームがよく選ぶ。Lyft、Reddit、Stripe の一部チームで利用中。

弱点は SQL カバレッジ。Arroyo SQL は Flink SQL のサブセットなので一部関数が無い。急速に追いついているが未到達。


15章 · Bytewax — Python でストリーム処理

Bytewax は 2022年に Bytewax(会社)が始めた Python ストリーミングフレームワーク。一行で要約すると「Flink に似ているが Python で書く」。

主要特徴。

  • Pure Python API: データサイエンティストが直接書ける。
  • Rust コア + PyO3: 性能は Rust、ユーザーコードは Python。
  • PyData 統合: NumPy、Pandas、scikit-learn を直接。
  • Connectors: Kafka、Redpanda、Kinesis、S3、Iceberg、ClickHouse など。

基本例 — ワードカウント。

from bytewax.dataflow import Dataflow
from bytewax.connectors.kafka import KafkaSource, KafkaSink
from bytewax import operators as op
from bytewax.connectors.stdio import StdOutSink

flow = Dataflow("word-count")

stream = op.input("kafka-in", flow, KafkaSource(
    brokers=["kafka:9092"], topics=["text"]
))

words = op.flat_map("split", stream, lambda msg: msg.value.decode().split())
keyed = op.key_on("key", words, lambda w: w)
counts = op.stateful_map("count",
    keyed,
    lambda: 0,
    lambda count, word: (count + 1, (word, count + 1))
)

op.output("stdout", counts, StdOutSink())

Bytewax の強みは ML 推論との統合。PyTorch / scikit-learn / Hugging Face モデルをそのままストリームに適用できる。

import torch
from transformers import pipeline

clf = pipeline("text-classification", model="distilbert-base-uncased")

def classify(text):
    return clf(text)[0]

stream = op.input(...)
labeled = op.map("classify", stream, classify)
op.output("sink", labeled, ...)

これを Flink でやると Python UDF 経由になり、モデルロードが非効率。Bytewax は同じ Python プロセス内なので速く直感的。

弱点は運用成熟度。Flink のような巨大クラスター、数年検証された exactly-once を期待してはいけない。100〜1000 events/sec 規模、データサイエンスパイプラインに適している。


16章 · Apache Beam — 統合 API の約束と限界

Apache Beam は 2016年に Google が Cloud Dataflow のモデルをオープンソース化したもの。一行で「Stream と Batch を同じ API で」。

中心アイデア。

  • PTransform / PCollection / Pipeline 抽象。
  • Runner 分離: Flink Runner、Spark Runner、Dataflow Runner、Samza Runner。
  • Java / Python / Go SDK
import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions

with beam.Pipeline(options=PipelineOptions()) as p:
    (p
     | 'Read' >> beam.io.ReadFromKafka(...)
     | 'Window' >> beam.WindowInto(beam.window.FixedWindows(60))
     | 'Count' >> beam.combiners.Count.PerKey()
     | 'Write' >> beam.io.WriteToBigQuery(...))

同じコードを Flink Runner でも、Dataflow Runner でも動かせる。理論上は

実際には Runner ごとにサポート機能が違い、デバッグが難しく、ネイティブ API に比べて一段の抽象化が余分にある。2026年時点で Beam は Google Cloud Dataflow を使うチームが主に使う。マルチクラウドの約束を真剣に追求するケースは稀だ。


直接 Flink を運用するのは大変だ。だからマネージドが成熟した。

提供元エンジン価格モデル特徴
Confluent Cloud FlinkFlink 1.20+Compute Unit + データ処理Schema Registry / Kafka 統合が最高
Aiven for FlinkFlink(Apache)インスタンス時間 + ストレージマルチクラウド、Karapace
DecodableFlink + 自前 OSスループット課金「5分でパイプライン」、connector 豊富
Ververica Platform CloudFlink + Ververica EnterpriseインスタンスFlink オリジナル企業、オンプレ強し
Striim自前エンジン(Flink ベース一部)ライセンスCDC + ストリーミング統合
Amazon MSFFlink時間 + スループットAWS Managed Service for Apache Flink

2026年の推奨ガイド。

  • Kafka 中心フルスタック: Confluent Cloud Flink。
  • 安価、マルチクラウド OSS: Aiven Flink。
  • クイックスタート、GUI 優先: Decodable。
  • AWS ロックイン OK: MSF。
  • オンプレ / エンタープライズサポート: Ververica Platform。

Decodable の魅力は YAML でパイプライン定義 → 即実行。小規模チームで「今日中に CDC パイプラインを作る」が可能。

sources:
  - name: orders-kafka
    type: kafka
    bootstrap_servers: kafka:9092
    topic: orders
pipelines:
  - name: enrich-orders
    sql: |
      SELECT o.*, u.segment
      FROM orders o
      JOIN users u ON o.user_id = u.user_id
sinks:
  - name: enriched-snowflake
    type: snowflake
    table: enriched_orders

18章 · Quix、Pulsar Functions、Memphis、Redpanda Connect — 軽量オプション

大きな Flink がオーバーキルなケースの選択肢。

Quix Streams — Python ライブラリ。Bytewax よりさらに軽量、Kafka に特化。

from quixstreams import Application

app = Application(broker_address="kafka:9092")
events = app.dataframe(topic=app.topic("events"))

events["amount_x2"] = events["amount"] * 2
events.filter(lambda row: row["amount"] > 100).to_topic(app.topic("alerts"))

app.run()

Apache Pulsar Functions — Pulsar 内蔵。軽量な per-message transform。

def process(input, context):
    return input.upper()

デプロイは pulsar-admin functions create 一発。

Memphis.dev / Superstream — Kafka 互換 OSS キュー、ストリーミング機能の一部を内蔵。

Redpanda Connect(旧 Benthos)— 強力な YAML ベース ETL。200以上の connector。

input:
  kafka:
    addresses: [kafka:9092]
    topics: [events]
pipeline:
  processors:
    - mapping: |
        root = this
        root.processed_at = now()
        root.amount_usd = this.amount * 0.93
output:
  kafka:
    addresses: [kafka:9092]
    topic: events-processed

Redpanda Connect は「stream processor」よりも「stream ETL」に近い。ウィンドウ・ジョインは弱いが、変換・ルーティング・エンリッチメントは抜群。


19章 · Estuary Flow — CDC + ストリーミングの融合

Estuary Flow は 2023年から CDC ストリーミングを扱う SaaS。Kafka のようなメッセージブローカーなしで直接 source-to-sink ストリーミング。

特徴。

  • Gazette(オープンソース log broker、Kafka 互換ではない)をバックボーンに。
  • Captures: Postgres binlog、MongoDB oplog、MySQL、MSSQL CDC。
  • Materializations: BigQuery、Snowflake、ClickHouse、Postgres sink。
  • Derivations: SQL/TypeScript で変換定義。
captures:
  acme/source-postgres:
    endpoint:
      connector:
        image: ghcr.io/estuary/source-postgres:dev
        config:
          address: pg:5432
          database: app
          user: estuary
          password: secret
    bindings:
      - resource: { table: orders, namespace: public }
        target: acme/orders

Estuary のアイデンティティは「Kafka なしのストリーミング」。CDC → 変換 → DW までを単一 SaaS で。ClickHouse + ELT バックエンドを高速構築するチームに人気。


20章 · バックプレッシャー — ストリーミングが難しい理由 #1

バックプレッシャー (backpressure) は「コンシューマが追いつかないときどうするか」の問題。ストリーム処理の 80% は結局これをうまく扱うこと。

問題シナリオ。Kafka に毎秒10万件流入 → Flink が変換 → Elasticsearch に sink。ES が遅くなり毎秒5万件しか受け取らない。すると?

  • Flink operator chain が全体で詰まる。
  • 結局 Kafka source が fetch を止める → コンシューマラグ増加。
  • メモリ/ディスクが徐々に埋まって OOM リスク。

対応パターン。

  1. 自然な backpressure(pull ベース): Flink/Kafka Streams は基本 pull ベースで backpressure を自然に伝播。
  2. バッファリング: Kafka 自体が巨大バッファ。データロスなくコンシューマがキャッチアップする時間を与える。
  3. Async I/O: Flink AsyncFunction で外部呼び出しを並列化。
  4. Drop / Sample: 本当に追いつかないなら一部イベントを drop(モニタリング・メトリクスは OK、決済は NG)。
  5. Scale out: パーティション増、コンシューマ増。

Flink のバックプレッシャーは Web UI の backpressure タブで色で見える(LOW/HIGH)。HIGH が数日続けばその operator がボトルネック。


21章 · スキーマ進化と Schema Registry

ストリーミングでスキーマ互換性は運用の核心。Avro/Protobuf + Schema Registry が標準パターン。

curl -X POST http://schema-registry:8081/subjects/orders-value/versions \
  -H "Content-Type: application/vnd.schemaregistry.v1+json" \
  -d '{
    "schema": "{ \"type\": \"record\", \"name\": \"Order\", \"fields\": [{\"name\":\"order_id\",\"type\":\"long\"}] }"
  }'

curl -X PUT http://schema-registry:8081/config/orders-value \
  -H "Content-Type: application/vnd.schemaregistry.v1+json" \
  -d '{"compatibility": "BACKWARD"}'

互換性モード。

  • BACKWARD: 新スキーマで old データを読める(フィールド追加可、削除は default がある場合のみ)。
  • FORWARD: 旧スキーマで新データを読める(フィールド削除可、追加は無視)。
  • FULL: 双方向。
  • NONE: 互換性チェックなし(危険)。

推奨: BACKWARD をデフォルトに。Producer は新スキーマで書き、Consumer は段階的にアップグレード。


22章 · 韓国ビッグテックのストリーム処理採用事例

韓国ビッグテックの実例(公開された技術ブログ・カンファレンス発表ベース)。

Coupang — Kafka + Flink + ksqlDB。リアルタイム価格決定、異常取引検出、検索クリック追跡。Disaggregated state 導入でペタバイト state 運用。2024年 Coupang Engineering Blog で Flink-on-Kubernetes 事例を共有。

NAVER 検索 — 自前ストリーム処理(Kafka Streams ベース)+ Flink SQL。検索トラフィックのリアルタイム統計、A/B テストメトリクス。自前 Schema Registry。

Kakao Pay / Kakao Bank — Flink + Kafka。取引リアルタイム分析、不正検知、決済ストリーム。2025年 if(kakao) で Flink CEP 不正パターン事例を発表。

NCsoft — Kafka Streams(Java)+ Flink。リアルタイムゲームマッチング、ログ分析、不正検知。ゲームトラフィックの特性上 P99 50ms 以下を要求。

ベミン(Woowa Brothers) — Kafka + Flink + Elasticsearch。リアルタイム配達位置、注文状態機械、異常パターン。2024年 WoowaCon で Flink-on-K8s 運用を共有。

Kakao Mobility — Kafka Streams + 自前処理。リアルタイムマッチング、位置追跡、動的価格。

Toss — Kafka + Flink + Druid。リアルタイム決済モニタリング、BI ダッシュボード。2025年 SLASH で Materialize 評価事例を共有(移行はまだ)。

NAVER Z(ZEPETO) — Kafka + Flink。仮想空間イベント処理、リアルタイム行動分析。

SK Telecom — Kafka + Spark Structured Streaming → Flink への段階的移行。通話品質・基地局メトリクス。


23章 · 日本ビッグテックのストリーム処理採用事例

Mercari — Kafka + Flink(GCP Dataflow も一部)。リアルタイム不正検知(CEP 多用)、レコメンド、商品検索インデキシング。2025年 Mercari Engineering Blog で Flink CEP 不正パターン事例。

LINE ヤフー — 自前 Kafka + Flink + ksqlDB。リアルタイムプッシュ通知ルーティング、トレンド検出、広告入札。2024年 LY Tech Conf で Flink-on-K8s 事例。

楽天 — Kafka + Spark Streaming → Flink + RisingWave 評価中。リアルタイム価格、レコメンド。グローバルマルチリージョン。

SmartNews — Kafka + Flink。リアルタイムニューストレンド、ユーザー行動追跡。広告入札に CEP。

サイバーエージェント — Kafka + Flink。広告入札、動画視聴分析、AbemaTV リアルタイム視聴メトリクス。

ZOZO — Kafka + Flink。商品検索インデキシング、レコメンド、ユーザー行動。

DeNA — Kafka + Spark Streaming + Flink。ゲーム不正検知、決済モニタリング、マーケティング分析。

LINE Pay — Flink + Kafka。取引モニタリング、不正検知。

ミクシィ — Kafka + Flink(特にモバイルゲーム分野)。リアルタイムイベントカウンター、マッチング。

NTT Communications — Apache Beam + Dataflow。IoT テレメトリ。


24章 · 運用パターン — クラスター、モニタリング、デバッグ

ストリーミングジョブの運用は OLTP・OLAP と違う。24/7 で回り、state が積もり、一度間違えると backfill が悲惨。

基本ガイド。

  1. 分離されたクラスター / 分離されたジョブ: 一つの OOM が他に飛び火しないよう。
  2. チェックポイント頻度: 30s〜1m が一般的。短いと負荷、長いと復旧が遅い。
  3. State TTL 必須: そうしないと keyed state が無限累積。
  4. メトリクス: Prometheus + Grafana で Flink JobManager・TaskManager メトリクス。lag、checkpoint 時間、backpressure、state サイズ。
  5. アラート: コンシューマ lag、checkpoint 失敗、restart カウント、late events。
  6. Backfill 戦略: state-free ジョブは Kafka 最初から再処理。state-ful は savepoint 活用。
  7. Blue/green デプロイ: 新バージョンを別コンシューマグループで立ち上げ、結果比較後に cutover。

Flink-on-Kubernetes は標準になった。Flink Kubernetes Operator(Apache OSS)が安定し、Helm chart 一発で開始可能。

helm repo add flink-operator-repo https://downloads.apache.org/flink/flink-kubernetes-operator-1.10.0/
helm install flink-kubernetes-operator flink-operator-repo/flink-kubernetes-operator

FlinkDeployment CRD でジョブ定義。

apiVersion: flink.apache.org/v1beta1
kind: FlinkDeployment
metadata:
  name: my-streaming-job
spec:
  image: flink:2.0
  flinkVersion: v2_0
  taskManager:
    replicas: 4
    resource: { memory: "4096m", cpu: 2 }
  job:
    jarURI: s3://my-jobs/my-job.jar
    parallelism: 8
    upgradeMode: savepoint

25章 · コストモデル — ストリーム処理の本当の値段

ストリーム処理のコストは常時稼働から来る。バッチは終われば 0 だがストリーミングは 24/7。

コスト構成。

  • コンピュート: TaskManager インスタンス。通常最大費目。
  • 状態ストレージ: RocksDB ローカル SSD または S3(ForSt)。
  • Kafka inter-AZ 転送: 上述の Kafka コスト。
  • チェックポイント S3 PUT/GET
  • モニタリング・ログコスト(Datadog、NewRelic)。

コスト削減パターン。

  1. state TTL で RAM 削減
  2. Disaggregated state(ForSt、RisingWave)で SSD 節約
  3. オートスケーリング: Flink Adaptive Scheduler で負荷に応じて TM 数調整。
  4. Spot/Preemptible: stateless operator は spot OK。
  5. Confluent KIP-848 / Share Groups でコンシューマ効率化
  6. WarpStream + Flink: state は ForSt、データは WarpStream → S3 コストのみ。

Confluent Cloud Flink は Compute Pool 単位で課金、未使用時は 0 にスケール(scale to zero)。小規模チームには合うが、hot ジョブのコストは一般的に OSS Flink + EKS より高い。


26章 · まとめ — 2026年のストリーム処理推奨

長い記事だった。最後に一行ガイド。

  • Kafka 中心 + Java チーム + ストリーム処理開始: Kafka Streams + ksqlDB(小規模)または Flink SQL(中大規模)。
  • 複雑な CEP / 大きな state / マルチソース: Apache Flink 2.0(DataStream + SQL)。
  • アプリが Postgres でクエリ / Materialized View 必要: RisingWave 2.x(大規模)または Materialize(複雑 SQL)。
  • Python ML 統合 / 小規模: Bytewax または Quix Streams
  • 運用したくない、GUI 必要: Decodable または Confluent Cloud Flink
  • 単純 ETL/変換(ウィンドウほぼ無し): Redpanda Connect (Benthos) または Pulsar Functions
  • CDC + ストリーミング統合: Estuary Flow または Debezium + Flink
  • Rust モノトーンシングルバイナリ好み: Arroyo

2026年に最大のトレンドはストリーミングデータベースの台頭。RisingWave と Materialize が「ストリーム処理はデータエンジニアの領域」という通念を崩している。一行の CREATE MATERIALIZED VIEW でバックエンドエンジニアが直接リアルタイムビューを作る。Flink は依然として強力だが、**「Flink が必要か?」**を先に問う時代になった。

そしてもう一つ — 状態がクラウドストレージへ移動している。ForSt、RisingWave の S3 backed state、Arroyo の設計全てが同じ方向。broker が stateless に近づき、データは S3 に。これは Kafka で始まった disaggregation トレンドが stream processor まで来たもの。

長い記事の終わり。2026年のストリーム処理はもはや一つの正解がない。選択肢が増え、それゆえに選択の責任が大きくなった。どうか自分のワークロードに合った道具を選んでほしい。


参考資料