Apache Flink v1.9(應用開發-Flink DataStream API編程指南-概述)

目錄

容錯

控制延遲

本地執行環境

收集數據源

迭代器數據接收器


Flink中的DataStream程序是實現數據流轉換的常規程序(例如,過濾,更新狀態,定義窗口,聚合)。最初從各種源(例如,消息隊列,套接字流,文件)創建數據流。結果通過接收器返回,接收器可以將數據寫入文件或者執行標準輸出(例如命令行終端)。Flink程序可以在各種環境中運行,獨立運行或嵌入其他程序中。執行器可以在本地JVM中運行,也可以在多個計算機節點的集羣上運行。

有關Flink API 基本概念的介紹,請參閱基本概念

爲了創建您自己的Flink DataStream程序,我們鼓勵您從Flink程序的解剖開始, 逐步添加您自己的 流轉換。其餘部分充當其他操作和高級功能的參考。

示例程序

以下程序是流窗口字數統計應用程序的完整工作示例,它在5秒窗口中對來自Web套接字的單詞進行計數。您可以複製並粘貼代碼以在本地運行它。

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;

public class WindowWordCount {

    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        DataStream<Tuple2<String, Integer>> dataStream = env
                .socketTextStream("localhost", 9999)
                .flatMap(new Splitter())
                .keyBy(0)
                .timeWindow(Time.seconds(5))
                .sum(1);

        dataStream.print();

        env.execute("Window WordCount");
    }

    public static class Splitter implements FlatMapFunction<String, Tuple2<String, Integer>> {
        @Override
        public void flatMap(String sentence, Collector<Tuple2<String, Integer>> out) throws Exception {
            for (String word: sentence.split(" ")) {
                out.collect(new Tuple2<String, Integer>(word, 1));
            }
        }
    }

}

要運行示例程序,首先從終端使用netcat啓動輸入流:

nc -lk 9999

只需鍵入一些單詞就可以返回一個新單詞。這些將是字數統計程序的輸入。如果要查看大於1的計數,請在5秒內反覆鍵入相同的單詞(如果不能快速輸入,則將窗口大小從5秒增加☺)。

數據源

源是您的程序從中讀取輸入的位置。您可以使用以下方法將源附加到您的程序StreamExecutionEnvironment.addSource(sourceFunction)。Flink附帶了許多預先實現的源函數,但您可以通過實現SourceFunction 非並行源,或通過實現ParallelSourceFunction接口或擴展 RichParallelSourceFunctionfor parallel源來編寫自己的自定義源。

有幾個預定義的流源可從以下位置訪問StreamExecutionEnvironment

基於文件的:

  • readTextFile(path)TextInputFormat逐行讀取文本文件,即符合規範的文件,並將它們作爲字符串返回。

  • readFile(fileInputFormat, path) - 按指定的文件輸入格式指定讀取(一次)文件。

  • readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo) - 這是前兩個內部調用的方法。它根據給定的輸入格式的文件路徑讀取文件。根據提供的watchType,此源可以定期監視(每intervalms)新數據(FileProcessingMode.PROCESS_CONTINUOUSLY)的路徑,或者一次性處理完當前路徑中的數據並退出(FileProcessingMode.PROCESS_ONCE)。使用pathFilter,用戶可以進一步排除正在處理的文件。

    實現:

    在底層實現中,Flink將文件讀取過程分爲兩個子任務,即目錄監控和數據讀取。這些子任務中的每一個都由單獨的實體實現。監視由單個非並行(並行性= 1)的任務實現,而讀取由並行運行的多個task執行。後者的並行性等於job並行性。單個監視任務的作用是掃描目錄(定期或僅一次,具體取決於watchType),找到要處理的文件,將它們分成切片,並將這些切片分配給下游讀者。下游讀者是指那些將閱讀實際數據的人。每個分割僅由一個讀取器讀取,而讀取器可以逐個讀取多個分割。

    重要筆記:

    1. 如果watchType設置爲FileProcessingMode.PROCESS_CONTINUOUSLY,則在修改文件時,將完全重新處理其內容。這可以打破“完全一次”的語義,因爲在文件末尾附加數據將導致其所有內容被重新處理。

    2. 如果watchType設置爲FileProcessingMode.PROCESS_ONCE,則源會掃描路徑一次並退出,而不等待讀者完成讀取文件內容。當然讀者將繼續閱讀,直到讀取所有文件內容。在該點之後關閉源將導致不再有檢查點。這可能會導致節點故障後恢復速度變慢,因爲作業將從上一個檢查點恢復讀取。

基於套接字的:

  • socketTextStream - 從套接字讀取。元素可以用分隔符分隔。

基於集合:

  • fromCollection(Collection) - 從Java Java.util.Collection創建數據流。集合中的所有元素必須屬於同一類型。

  • fromCollection(Iterator, Class) - 從迭代器創建數據流。該類指定迭代器返回的元素的數據類型。

  • fromElements(T ...) - 從給定的序列化對象創建數據流。所有對象必須屬於同一類型。

  • fromParallelCollection(SplittableIterator, Class) - 並行地從迭代器創建數據流。該類指定迭代器返回的元素的數據類型。

  • generateSequence(from, to) - 並行生成給定間隔中的數字序列。

自定義:

  • addSource - 附加新的源功能。例如,要從Apache Kafka讀取,您可以使用 addSource(new FlinkKafkaConsumer08<>(...))。請參閱連接器以獲取更多詳情

DataStream轉換

有關可用流轉換的概述,請參閱運算符

數據接收器使用DataStream並將它們轉發到文件,套接字,外部系統或打印它們。Flink帶有各種內置輸出格式,這些格式封裝在DataStreams上的操作後面:

  • writeAsText()TextOutputFormat- 按字符串順序寫入元素。通過調用每個元素的toString()方法獲得字符串。

  • writeAsCsv(...)CsvOutputFormat- 將元組寫爲逗號分隔值文件。行和字段分隔符是可配置的。每個字段的值來自對象的toString()方法。

  • print()printToErr() - 在標準輸出/標準錯誤流上打印每個元素的toString()值。可選地,可以提供前綴(msg),其前綴爲輸出。這有助於區分不同的打印調用。如果並行度大於1,則輸出也將以生成輸出的任務的標識符爲前綴。

  • writeUsingOutputFormat()FileOutputFormat- 自定義文件輸出的方法和基類。支持自定義對象到字節的轉換。

  • writeToSocket - 根據a將元素寫入套接字 SerializationSchema

  • addSink - 調用自定義接收器功能。Flink捆綁了其他系統(如Apache Kafka)的連接器,這些系統實現爲接收器功能。

請注意,write*()方法DataStream主要用於調試目的。他們沒有參與Flink的檢查點,這意味着這些函數通常具有至少一次的語義。刷新到目標系統的數據取決於OutputFormat的實現。這意味着並非所有發送到OutputFormat的元素都會立即顯示在目標系統中。此外,在失敗的情況下,這些記錄可能會丟失。

爲了可靠,準確地將流傳送到文件系統,請使用flink-connector-filesystem。此外,通過該.addSink(...)方法的自定義實現可以參與Flink的精確一次語義檢查點。

迭代

迭代流程序實現階躍函數並將其嵌入到IterativeStream。由於DataStream程序可能永遠不會完成,因此沒有最大迭代次數。相反,您需要指定流的哪個部分反饋到迭代,哪個部分使用split轉換或轉發到下游filter。在這裏,我們展示了使用過濾器的示例。首先,我們定義一個IterativeStream

IterativeStream<Integer> iteration = input.iterate();

然後,我們使用一系列轉換指定將在循環內執行的邏輯(這裏是一個簡單的map轉換)

DataStream<Integer> iterationBody = iteration.map(/* this is executed many times */);

要關閉迭代並定義迭代尾部,請調用closeWith(feedbackStream)方法IterativeStream。賦予closeWith函數的DataStream 將反饋給迭代頭。常見的模式是使用過濾器來分離反饋的流的一部分和向前傳播的流的一部分。這些濾波器可以例如定義“終止”邏輯,其中允許元件向下遊傳播而不是反饋。

iteration.closeWith(iterationBody.filter(/* one part of the stream */));
DataStream<Integer> output = iterationBody.filter(/* some other part of the stream */);

例如,這裏是從一系列整數中連續減去1直到它們達到零的程序:

DataStream<Long> someIntegers = env.generateSequence(0, 1000);

IterativeStream<Long> iteration = someIntegers.iterate();

DataStream<Long> minusOne = iteration.map(new MapFunction<Long, Long>() {
  @Override
  public Long map(Long value) throws Exception {
    return value - 1 ;
  }
});

DataStream<Long> stillGreaterThanZero = minusOne.filter(new FilterFunction<Long>() {
  @Override
  public boolean filter(Long value) throws Exception {
    return (value > 0);
  }
});

iteration.closeWith(stillGreaterThanZero);

DataStream<Long> lessThanZero = minusOne.filter(new FilterFunction<Long>() {
  @Override
  public boolean filter(Long value) throws Exception {
    return (value <= 0);
  }
});

執行參數

StreamExecutionEnvironment包含ExecutionConfig允許爲運行時設置工作的具體配置值。

有關大多數參數的說明,請參閱執行配置。這些參數特別適用於DataStream API:

  • setAutoWatermarkInterval(long milliseconds):設置自動水印發射的間隔。您可以使用獲取當前值long getAutoWatermarkInterval()

容錯

State&Checkpointing描述瞭如何啓用和配置Flink的檢查點機制。

控制延遲

默認情況下,元素不會逐個傳輸到網絡上(這會導致不必要的網絡流量),但會被緩衝。可以在Flink配置文件中設置緩衝區的大小(實際在計算機之間傳輸)。雖然此方法有利於優化吞吐量,但當傳入流速度不夠快時,可能會導致延遲問題。要控制吞吐量和延遲,您可以env.setBufferTimeout(timeoutMillis)在執行環境(或單個運算符)上使用來設置緩衝區填充的最長等待時間。在此之後,即使緩衝區未滿,也會自動發送緩衝區。此超時的默認值爲100毫秒。

用法:

LocalStreamEnvironment env = StreamExecutionEnvironment.createLocalEnvironment(); 

env.setBufferTimeout(timeoutMillis); 

env.generateSequence(1,10).map(new MyMapper()).setBufferTimeout(timeoutMillis);

爲了最大化吞吐量,設置setBufferTimeout(-1)哪個將刪除超時和緩衝區只有在它們已滿時纔會被刷新。要最小化延遲,請將超時設置爲接近0的值(例如5或10 ms)。應避免緩衝區超時爲0,因爲它可能導致嚴重的性能下降。

調試

在分佈式集羣中運行流式程序之前,最好確保實現的算法按預期工作。因此,實施數據分析程序通常是檢查結果,調試和改進的增量過程。

Flink通過支持IDE內的本地調試,測試數據的注入和結果數據的收集,提供了簡化數據分析程序開發過程的功能。本節提供了一些如何簡化Flink程序開發的提示。

本地執行環境

 LocalStreamEnvironment在創建它的同一JVM進程中啓動Flink系統。如果從IDE啓動LocalEnvironment,則可以在代碼中設置斷點並輕鬆調試程序。

創建LocalEnvironment並使用如下:

final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment(); 

DataStream<String> lines = env.addSource(/* some source */); 
// build your program 

env.execute();

收集數據源

Flink提供了特殊的數據源,這些數據源由Java集合支持,以方便測試。一旦程序經過測試,源和接收器可以很容易地被讀取/寫入外部系統的源和接收器替換。

集合數據源可以如下使用:

final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();

// Create a DataStream from a list of elements
DataStream<Integer> myInts = env.fromElements(1, 2, 3, 4, 5);

// Create a DataStream from any Java collection
List<Tuple2<String, Integer>> data = ...
DataStream<Tuple2<String, Integer>> myTuples = env.fromCollection(data);

// Create a DataStream from an Iterator
Iterator<Long> longIt = ...
DataStream<Long> myLongs = env.fromCollection(longIt, Long.class);

注意:目前,集合數據源要求實現數據類型和迭代器 Serializable。此外,收集數據源不能並行執行(並行度= 1)。

 

迭代器數據接收器

Flink還提供了一個接收器來收集DataStream結果,以便進行測試和調試。它可以像這樣實現:

​​​​​​​import org.apache.flink.streaming.experimental.DataStreamUtils 

DataStream<Tuple2<String, Integer>> myResult = ... Iterator<Tuple2<String, Integer>> myOutput = DataStreamUtils.collect(myResult)

注意: flink-streaming-contrib模塊已從Flink 1.5.0中刪除。它的課程已被移入flink-streaming-javaflink-streaming-scala

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章