FLINKソースコード解析 - 簡単なプログラムFLINKの分析

この記事では、最初に見出しに登場FLINKプログラムが実行されますか?FLINKは、ソースコードを簡単な手順を分析すると、歓迎の注目の見出し番号と、より乾燥のための「ビッグデータと人工知能」(マイクロ文字の検索bigdata_ai_tech)のマイクロチャネルパブリック番号を、私はまた、注意歓迎CSDNのブログを

カバーthis've前にローカル環境をセットアップする方法とどのようにFLINK FLINKアプリケーション作成すると、どのようFLINKソース構築する方法この資料の例では、日常的な手順FLINKが何であるかを解決するためにSocketWindowWordCountの公式を使用し、それぞれの基本的な手順のを。

サンプルプログラム

public class SocketWindowWordCount {
    public static void main(String[] args) throws Exception {
        // the host and the port to connect to
        final String hostname;
        final int port;
        try {
            final ParameterTool params = ParameterTool.fromArgs(args);
            hostname = params.has("hostname") ? params.get("hostname") : "localhost";
            port = params.getInt("port");
        } catch (Exception e) {
            System.err.println("No port specified. Please run 'SocketWindowWordCount " +
                    "--hostname <hostname> --port <port>', where hostname (localhost by default) " +
                    "and port is the address of the text server");
            System.err.println("To start a simple text server, run 'netcat -l <port>' and " +
                    "type the input text into the command line");
            return;
        }
        // get the execution environment
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // get input data by connecting to the socket
        DataStream<String> text = env.socketTextStream(hostname, port, "\n");
        // parse the data, group it, window it, and aggregate the counts
        DataStream<WordWithCount> windowCounts = text
                .flatMap(new FlatMapFunction<String, WordWithCount>() {
                    @Override
                    public void flatMap(String value, Collector<WordWithCount> out) {
                        for (String word : value.split("\\s")) {
                            out.collect(new WordWithCount(word, 1L));
                        }
                    }
                })
                .keyBy("word")
                .timeWindow(Time.seconds(5))

                .reduce(new ReduceFunction<WordWithCount>() {
                    @Override
                    public WordWithCount reduce(WordWithCount a, WordWithCount b) {
                        return new WordWithCount(a.word, a.count + b.count);
                    }
                });
        // print the results with a single thread, rather than in parallel
        windowCounts.print().setParallelism(1);
        env.execute("Socket Window WordCount");
    }
    // ------------------------------------------------------------------------
    /**
     * Data type for words with count.
     */
    public static class WordWithCount {
        public String word;
        public long count;
        public WordWithCount() {}
        public WordWithCount(String word, long count) {
            this.word = word;
            this.count = count;
        }
        @Override
        public String toString() {
            return word + " : " + count;
        }
    }
}

これは、上記の公式ウェブサイトでSocketWindowWordCountプログラム例は、最初のホストのコマンドラインとポートのソケット接続を取得し、その後、実行環境、ソケット接続から読み出されたデータ、解析およびデータ変換、最終的な出力データを取得します。
各手順は、以下のFLINKを数全体にわたって実質的に同一の部品が含まれています。

  1. 実行環境を手に入れよう、
  2. ロード/初期データを作成し、
  3. このデータの変換を指定し、
  4. 配置計算結果のために指定されました、
  5. トリガーの実行

FLINK実行環境

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

FLINKプログラムは、このコードから開始され、このコード行は、実行環境を返すプログラムの現在の実行コンテキストを表します。プログラムは、独立した呼び出された場合、このメソッドは戻りますcreateLocalEnvironment()ローカル実行環境が作成されますLocalStreamEnvironmentそのソースコードで見ることができます。

//代码目录:org/apache/flink/streaming/api/environment/StreamExecutionEnvironment.java
public static StreamExecutionEnvironment getExecutionEnvironment() {
    if (contextEnvironmentFactory != null) {
        return contextEnvironmentFactory.createExecutionEnvironment();
    }
    ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
    if (env instanceof ContextEnvironment) {
        return new StreamContextEnvironment((ContextEnvironment) env);
    } else if (env instanceof OptimizerPlanEnvironment || env instanceof PreviewPlanEnvironment) {
        return new StreamPlanEnvironment(env);
    } else {
        return createLocalEnvironment();
    }
}

入力データの取得

DataStream<String> text = env.socketTextStream(hostname, port, "\n");

ソケットからこの例のソースデータは、この構成では、ソケット、復号システムのデフォルトの文字セットで受信した文字列から受信した無制限の文字列を含み、指定されたソケットのソケット接続を作成し、新しいデータ・ストリームを作成します。 。ソケット接続がクローズされた場合、データの読み取りがすぐに終了します。ソースを見て、見つけることができ、実際にソケットの設定を指定することにより、そこに構築されたSocketTextStreamFunction例を、その後、データの安定した流れは、内部の入力ソケット接続から読み取られたデータ・ストリームを作成します。

//代码目录:org/apache/flink/streaming/api/environment/StreamExecutionEnvironment.java
@PublicEvolving
public DataStreamSource<String> socketTextStream(String hostname, int port, String delimiter, long maxRetry) {
    return addSource(new SocketTextStreamFunction(hostname, port, delimiter, maxRetry),
            "Socket Stream");
}

SocketTextStreamFunction次のようにクラス階層は以下のとおりです。
SocketTextStreamFunctionのクラス図

それが分かるようにサブクラスは、すべてのストリームデータソースの基本的なインタフェースFLINKあります。これは次のように定義されます。SocketTextStreamFunctionSourceFunctionSourceFunctionSourceFunction

//代码目录:org/apache/flink/streaming/api/functions/source/SourceFunction.java
@Public
public interface SourceFunction<T> extends Function, Serializable {
    void run(SourceContext<T> ctx) throws Exception;
    void cancel();
    @Public
    interface SourceContext<T> {
        void collect(T element);
        @PublicEvolving
        void collectWithTimestamp(T element, long timestamp);
        @PublicEvolving
        void emitWatermark(Watermark mark);
        @PublicEvolving
        void markAsTemporarilyIdle();
        Object getCheckpointLock();
        void close();
    }
}

SourceFunction定義runcancel二つの方法およびSourceContext内部インターフェース。

  • データ取得ロジックのため、およびデータは、CTXを渡されたパラメータから下流ノードに転送することができる:(SourceContex)を実行します。
  • キャンセル():ループ終了を引き起こす可能性があり、通常はrunメソッドでは、メソッドをキャンセルし、データを生成するために、連続したループがあるだろう、データソースをキャンセルします。
  • SourceContext:機能および可能な透かしインタフェース、戻り型ソース発生素子を出射する光源素子。

理解SourceFunctionこのインタフェース、およびその後を見てSocketTextStreamFunction具体的な実装(主にrun法)、ロジックは、非常に明確であるが連続的に指定したホスト名とポートからデータを読み込み、Enterキーを押して文字列に改行区切り文字を入力します。 、その後、ダウンストリームにデータを転送します。今すぐに戻って方法、それを呼び出すことによって返すインスタンスを。例を考え変数があるなぜソースの戻り値の型で入力し、それを?これは、親クラス、以下のクラス図は、Java多型の機能を反映して、見ることができます。StreamExecutionEnvironmentsocketTextStreamaddSourceDataStreamSourcetextDataStreamDataStreamSourceDataStreamDataStreamSource
DataStreamSourceのクラス図

データフローの操作

以下のために、上記DataStreamSourceに取得するにはflatMapkeyBytimeWindowreduceスイッチング動作。

DataStream<WordWithCount> windowCounts = text
        .flatMap(new FlatMapFunction<String, WordWithCount>() {
            @Override
            public void flatMap(String value, Collector<WordWithCount> out) {
                for (String word : value.split("\\s")) {
                    out.collect(new WordWithCount(word, 1L));
                }
            }
        })
        .keyBy("word")
        .timeWindow(Time.seconds(5))
        .reduce(new ReduceFunction<WordWithCount>() {
            @Override
            public WordWithCount reduce(WordWithCount a, WordWithCount b) {
                return new WordWithCount(a.word, a.count + b.count);
            }
        });

DataStreamSourceデータフローのトップに取得するには、このロジックは、作られたflatMapkeyBytimeWindowreduce4つの変換動作、については以下の言ったflatMap3人の他の読者が自分の外観を理解するためにソースコードを表示しようとすることができ、変換、変換動作。

見てflatMap、次のようにソースコードは、それに近づきます。

//代码目录:org/apache/flink/streaming/api/datastream/DataStream.java
public <R> SingleOutputStreamOperator<R> flatMap(FlatMapFunction<T, R> flatMapper) {
    TypeInformation<R> outType = TypeExtractor.getFlatMapReturnTypes(clean(flatMapper),
            getType(), Utils.getCallLocationName(), true);
    return transform("Flat Map", outType, new StreamFlatMap<>(clean(flatMapper)));
}

反射取得するには、まず、二つのことがないflatMap第二は、オペレータが生成され、出力演算子のタイプを。FLINKフロー計算は、プロセスの最終的な出力ストリームチェーンオペレータの送信にプロセスからの入力データ・ストリームの中核概念です。論理演算子に処理されたデータの各。上記のコードの最後の行transformの効果は、メソッドを返すことであるSingleOutputStreamOperator継承、Datastreamクラス及び対流を操作しやすいいくつかのヘルパーメソッドを定義します。戻る前に、transformこの方法はまた、実行環境に登録します。この下にはのFLINKストリーミングデータフローへのマッピングプログラムの概略図です。
FLINK基本的なプログラミングモデル

結果出力

windowCounts.print().setParallelism(1);

各ソースFLINK手順は終了に沈み開始されるprint方法は、標準出力ストリームシンクの計算結果です。様々なコネクタの実際の開発では、通常、カスタムの公式サイトやコネクタなどカフカ、HBaseの、ファイルシステムとしてデータシンク指定されたエリアに計算結果によって提供、Elasticsearchが好きです。ここでsetParallelism、この受信機のために設けられた並列度であり、値がゼロよりも大きくなければなりません。

プログラムの実行

env.execute("Socket Window WordCount");

FLINKリモートモードとローカルモードは2つの実行モードがあり、二つのモードは、ここでローカルモードで解決するには、少し異なっています。見てexecute、次のように、メソッドのソースコード:

//代码目录:org/apache/flink/streaming/api/environment/LocalStreamEnvironment.java
@Override
public JobExecutionResult execute(String jobName) throws Exception {
    // transform the streaming program into a JobGraph
    StreamGraph streamGraph = getStreamGraph();
    streamGraph.setJobName(jobName);
    JobGraph jobGraph = streamGraph.getJobGraph();
    jobGraph.setAllowQueuedScheduling(true);
    Configuration configuration = new Configuration();
    configuration.addAll(jobGraph.getJobConfiguration());
    configuration.setString(TaskManagerOptions.MANAGED_MEMORY_SIZE, "0");
    // add (and override) the settings with what the user defined
    configuration.addAll(this.configuration);
    if (!configuration.contains(RestOptions.BIND_PORT)) {
        configuration.setString(RestOptions.BIND_PORT, "0");
    }
    int numSlotsPerTaskManager = configuration.getInteger(TaskManagerOptions.NUM_TASK_SLOTS, jobGraph.getMaximumParallelism());
    MiniClusterConfiguration cfg = new MiniClusterConfiguration.Builder()
        .setConfiguration(configuration)
        .setNumSlotsPerTaskManager(numSlotsPerTaskManager)
        .build();
    if (LOG.isInfoEnabled()) {
        LOG.info("Running job on local embedded Flink mini cluster");
    }
    MiniCluster miniCluster = new MiniCluster(cfg);
    try {
        miniCluster.start();
        configuration.setInteger(RestOptions.PORT, miniCluster.getRestAddress().get().getPort());
        return miniCluster.executeJobBlocking(jobGraph);
    }
    finally {
        transformations.clear();
        miniCluster.close();
    }
}

この方法は、3つの部分からなる:、ストリームJobGraphを変換するユーザ定義(又はカバー)の内容を追加するためのプログラムが提供され、そしてタスクを実行miniClusterを開始します。JobGraphについて一時的にすぐ隣、以下のミッションについてはこちらを言って、話すことはありませんreturn miniCluster.executeJobBlocking(jobGraph);、次のように、ソース行を:

//代码目录:org/apache/flink/runtime/minicluster/MiniCluster.java
@Override
public JobExecutionResult executeJobBlocking(JobGraph job) throws JobExecutionException, InterruptedException {
    checkNotNull(job, "job is null");
    final CompletableFuture<JobSubmissionResult> submissionFuture = submitJob(job);
    final CompletableFuture<JobResult> jobResultFuture = submissionFuture.thenCompose(
        (JobSubmissionResult ignored) -> requestJobResult(job.getJobID()));
    final JobResult jobResult;
    try {
        jobResult = jobResultFuture.get();
    } catch (ExecutionException e) {
        throw new JobExecutionException(job.getJobID(), "Could not retrieve JobResult.", ExceptionUtils.stripExecutionException(e);
    }
    try {
        return jobResult.toJobExecutionResult(Thread.currentThread().getContextClassLoader());
    } catch (IOException | ClassNotFoundException e) {
        throw new JobExecutionException(job.getJobID(), e);
    }
}

このコードのコアロジックがすることですfinal CompletableFuture<JobSubmissionResult> submissionFuture = submitJob(job);呼び出すMiniClusterクラスのsubmitJobメソッドを、この方法を見てみましょう。

//代码目录:org/apache/flink/runtime/minicluster/MiniCluster.java
public CompletableFuture<JobSubmissionResult> submitJob(JobGraph jobGraph) {
    final CompletableFuture<DispatcherGateway> dispatcherGatewayFuture = getDispatcherGatewayFuture();
    // we have to allow queued scheduling in Flip-6 mode because we need to request slots
    // from the ResourceManager
    jobGraph.setAllowQueuedScheduling(true);
    final CompletableFuture<InetSocketAddress> blobServerAddressFuture = createBlobServerAddress(dispatcherGatewayFuture);
    final CompletableFuture<Void> jarUploadFuture = uploadAndSetJobFiles(blobServerAddressFuture, jobGraph);
    final CompletableFuture<Acknowledge> acknowledgeCompletableFuture = jarUploadFuture
        .thenCombine(
            dispatcherGatewayFuture,
            (Void ack, DispatcherGateway dispatcherGateway) -> dispatcherGateway.submitJob(jobGraph, rpcTimeout))
        .thenCompose(Function.identity());
    return acknowledgeCompletableFuture.thenApply(
        (Acknowledge ignored) -> new JobSubmissionResult(jobGraph.getJobID()));
}

ここにあるDispatcherジョブ投入を受信するための責任を負うコンポーネント、彼らは、ジョブを実行したときにホスト障害、それらを復元するためにJobManagersを生成し、永続的です。Dispatcherローカル環境の下で始まっ2つの実装、ありますMiniDispatcherクラスタ環境で起動するには、StandaloneDispatcher以下は、クラスの構成図です。
図MiniDispatcherクラス構造。

ここでは、だDispatcher打ち上げJobManagerRunner手数料をJobManagerRunnerジョブの開始にJobMaster次のように対応するコードは以下のとおりです。

//代码目录:org/apache/flink/runtime/jobmaster/JobManagerRunner.java
private CompletableFuture<Void> verifyJobSchedulingStatusAndStartJobManager(UUID leaderSessionId) {
    final CompletableFuture<JobSchedulingStatus> jobSchedulingStatusFuture = getJobSchedulingStatus();
    return jobSchedulingStatusFuture.thenCompose(
        jobSchedulingStatus -> {
            if (jobSchedulingStatus == JobSchedulingStatus.DONE) {
                return jobAlreadyDone();
            } else {
                return startJobMaster(leaderSessionId);
            }
        });
}

JobMasterネストされた方法の一連の呼び出しの後、最終的には論理の次の部分を実行します。

//代码目录:org/apache/flink/runtime/jobmaster/JobMaster.java
private void scheduleExecutionGraph() {
    checkState(jobStatusListener == null);
    // register self as job status change listener
    jobStatusListener = new JobManagerJobStatusListener();
    executionGraph.registerJobStatusListener(jobStatusListener);
    try {
        executionGraph.scheduleForExecution();
    }
    catch (Throwable t) {
        executionGraph.failGlobal(t);
    }
}

ここでexecutionGraph.scheduleForExecution();呼ばれるExecutionGraph起動方法。FLINKの構造を考慮すると、ExecutionGraph実際のが行われる場合、実際の実装のプロセスに提出するためにここに、一つのタスクからまでのように、それが終わって、その後、ローカル環境では、以下のプロセスの実装を検討し、次のとおりです。

  1. クライアント実行execute方法;
  2. MiniClusterタスクのほとんどを完了した後、直接にタスクを委任MiniDispatcher
  3. Dispatcherジョブを受信した後、インスタンス化JobManagerRunner、そしてあなたは、このインスタンスでジョブを開始。
  4. JobManagerRunner仕事に次JobMasterに対処します。
  5. JobMaster使用してExecutionGraphマップ全体を開始するために実行する方法を、全体のタスクが起動されます。

おすすめ

転載: www.cnblogs.com/cjblogs/p/10978975.html
おすすめ