データフロー プログラミング モデル

抽象化レベル

Flink はストリーミング/バッチ アプリケーションを開発するための異なる抽象化レベルを提供します。

抽象化のプログラミング レベル

  • 一番低レベルの抽象化は単にステートフル ストリーミングを提供します。それはProcess 関数を使ってデータストリーム APIに組み込まれています。ユーザは自由に1つ以上のストリームからイベントを処理することができ、一貫性のある耐障害性状態が使われます。更に、ユーザはイベントタイムと処理タイムのコールバックを登録することができ、プログラムは洗練された計算を理解することができます。

  • 実際には、ほとんどのアプリケーションは上で説明した低レベルの抽象化は必要なく、DataStream API (有限/無限 ストリーム) および DataSet API (有限データセット)のようなCore APIsに対してプログラムが変わりに必要でしょう。これらの柔軟なAPIは、ユーザ定義の変形、join、集約、ウィンドウ、状態などの様々な形式のデータ処理のための共通の構築ブロックを提供します。これらのAPI内で処理されるデータ型はそれぞれのプログラム言語内のクラスとして表されます。

    低レベル プロセス関数データストリーム APIを統合し、特定のオペレーションのみのための低レベル抽出をすることができます。DataSet API はループ/イテレーションのような有限データセット上の追加のプリミティブを提供します。

  • Table APItablesを中心とした宣言型のDSLで、(ストリームを表現する場合は)動的に変更するテーブルかも知れません。The Table API follows the (extended) relational model: Tables have a schema attached (similar to tables in relational databases) and the API offers comparable operations, such as select, project, join, group-by, aggregate, etc. テーブルAPIプログラムは、操作のためのコードがどのように調べるを正確に指定するだけでなく、明確に論理操作が何をしなければならないか を定義します。Table API はユーザ定義関数の様々な型によって拡張可能で、Core APIsよりは表現力が劣りますが、(各コードが少なく)もっと簡単に使えます。更に、Table API プログラムは実行の前に最適化ルールを適用するオプティマイザを通すこともできます。

    プログラムがTable APIDataStreamおよび DataSet API間で混ぜ合わせることができ、テーブルとDataStream/DataSet間をシームレスに変換することができます。

  • Flinkによって提供される高レベルの抽象化はSQLです。この抽象化はセマンティクスと表現の両方においてTable APIに似ていますが、プログラムをSQLクエリ表現として表します。SQL 抽象化は Table API と密接にやり取りをし、SQLクエリはTable APIの中で定義されたテーブル上で実行することができます。

プログラムとデータフロー

Flinkプログラムの基本的な構築ブロックはストリーム変換です。(Flinkで使われるデータセットAPIは内部的にストリームでもあることに注意してください - 後述します。) 概念的には、stream は (終わらないかもしれない)データレコードのflowであり、transformation は1つ以上のストリームを入力として取り、結果として1つ以上の出力を生成する操作です。

実行された場合、Flinkプログラムはストリームと変形オペレータから成るストリーミング データフローにマップされます。各データフローは1つ以上のソース で始まり、1つ以上のシンクに終着します。データフローは任意の有効非循環グラフ (DAGs)に似ています。サイクルの特別な形式は iterationによって許可されますが、たいていは簡単化のためにこれをごまかします。

データストリームプログラムとそのデータフロー。

しばしば、プログラム内の変換とデータフロー内のオペレータの間には1対1の対応があります。しかし、時には1つの変換が複数の変換オペレータからできているかも知れません。

上に戻る

並行データフロー

Flinkでのプログラムは本質的に並行および分散です。実行中はストリーム は1つ以上のストリーム パーティションを持ち、それぞれのオペレータは1つのストリームパーティションあるいはオペレーターのサブタスクを持ちます。オペレータのサブタスクはお互いに独立していて、異なるスレッドあるいは異なるマシーンやコンテナ上でさえも実行されます。

オペレータサブタスクの数は特定のオペレータの並行度 です。ストリームの並行度は常にその生成オペレータの並行度です。同じプログラムの異なるオペレータは異なるレベルの並行度を持つかも知れません。

並行データフロー

ストリームはone-to-one (あるいは forwarding) パターン、あるいは redistributing パターンの中での二つのオペレータ間でデータを転送することができます。

  • One-to-one ストリーム (例えば、上の図でのSourcemap() 間のオペレータ) は要素のパーティショニングとオーダリングを保持します。このことはmap() オペレータのsubtask[1]がSourceオペレータのsubtask[1]によって生成された時と同じ順番の同じ要素を見るだろうことを意味します。

  • Redistributing ストリーム (map()keyBy/window間、およびkeyBy/windowsink間) はストリームのパーティショニングを変更します。各 オペレータのサブタスクは、選択された変換に依存して、データを異なるターゲットのサブタスクに送信します。例として keyBy() (キーのハッシュ化による再パーティション), broadcast() あるいは rebalance() (ランダム再分配)があります。redistributing 交換の場合、送信および受信タスクのそれぞれのペアについての要素間の順番のみが維持されます(たとえば、map()のサブタスク[1]とkeyBy/windowのサブタスク[2])。つまり、この例では、各キー内の順番は保持されますが、シンクに到着する異なるキーの集約結果内での順番については並行度により非決定性が導入されます。

上に戻る

ウィンドウ

集約イベント(例えば、カウント、合計)は、バッチ処理に比べてストリーム上では異なる働きをします。例えば、ストリームは一般的に無限なため、最初にストリーム内で全ての要素を数えることは不可能で、したがってカウントを返します。代わりに、ストリーム上の集約(カウント、合計など)は“count over the last 5 minutes” あるいは“sum of the last 100 elements”のようなwindowsによってスコープされます。

ウィンドウはtime driven (例: 各30秒毎) あるいは data driven (例: 各100要素毎)があり得ます。One typically distinguishes different types of windows, such as tumbling windows (no overlap), sliding windows (with overlap), and session windows (punctuated by a gap of inactivity).

時間とカウント ウィンドウ

このブログの投稿の中でもっと多くのウィンドウの例を見つけることができます。

上に戻る

時間

ストリーミングプログラムの中で(例えばウィンドウを定義するために)時間を参照する場合、時間の異なる表記を指示することができます。

  • イベントタイム は、イベントが生成された時間です。通常はイベントのタイムスタンプによって表現されます。例えば、センサーの生成あるいは生成サービスによってアタッチされたもの。Flinkはtimestamp assignersを使ってイベントのタイムスタンプにアクセスします。

  • Ingestion time はイベントがソースオペレータにおいてFlinkデータフローに入った時間です。

  • Processing Time は時間ベースのオペレーションを実施する各オペレータでのローカルの時間です。

イベントタイム、取り込み時間、処理時間

時間を扱う方法についての詳細はイベントタイム ドキュメントにあります。

上に戻る

ステートフル オペレーション

データフロー内の多くのオペレーションは単純に1つの個々のそのときのイベントを見ますが(例えば、イベントパーサー)、いくつかのオペレーションは多数のイベントを横断して情報を記録します(例えば、ウィンドウ オペレーション)。これらのオペレーションはステートフルと呼ばれます。

ステートフルのオペレーションは組み込みのキー/値ストアとみなすことができるものの中で維持されます。状態はステートフル オペレータによって読み込まれたストリームと一緒に厳密にパーティション化され分散されます。したがって、キー/値 状態へのアクセスはkeyBy() 関数の後のkeyed streams上でのみ可能で、現在のイベントキーの値にのみ限定されます。ストリームと状態のキーの割り当ては、トランザクションのオーバーヘッド無しにすべての状態の更新がローカルオペレーションであることを確実にします。この割り当てはFlinkが状態を再分配しストリームのパーティショニングを透過的に調整することも可能にします。

状態とパーティショニング

上に戻る

耐障害性のためのチェックポイント

Flinkはストリーム再生チェックポイントを使って耐障害性を実装します。チェックポイントは各オペレータに対応する状態と一緒に各入力ストリーム内の特定の場所に関係します。ストリーミング データフローは、オペレータの状態の回復およびチェックポイントの場所からのイベントの再生により、一貫性を維持(確実に一回の処理セマンティクス)しながらチェックポイントから再開することができます。

チェックポイントの間隔は、リカバリ時間(再生されなければならないイベントの数)を使う実行時の耐障害性のオーバーヘッドをトレードオフする手段です。

チェックポイント耐障害性の詳細は耐障害性のドキュメントにあります。

上に戻る

ストリーミングのバッチ

Flink はバッチプログラムをストリーミングプログラムの特別な場合として実行します。この時ストリームは制限(要素の数が有限)されます。DataSet は内部的にデータのストリームとして扱われます。上記の概念はしたがって少しの例外を除いてストリーミングプログラムに適用される方法と同じようにバッチプログラムに適用されます:

  • データセットAPI中のプログラムはチェックポイントを使いません。回復は完全にストリームを再現することで起こります。入力が制限されているため、それらが可能です。このことは回復のためのコストを押し上げますが、チェックポイントを回避するため一般的な処理を手軽にします。

  • データセットAPI内のステートフル オペレーションは、キー/値 インデックスでは無く、単純化されたインメモリ/アウトオブコアのデータ構造を使用します。

  • データセットAPIは特別な同期(スーパーステップ ベース)のイテレーションを導入します。これは制限されたストリーム上でのみ可能です。詳細はイテレーションのドキュメントを調べてください。

上に戻る

次のステップ

Flinkの 分散ランタイムの基本的な概念に続きます。

TOP
inserted by FC2 system