Spark每日半小時(37)——Spark Streaming:(下)

DataFram和SQL操作

我們可以輕鬆地對流數據使用DataFrames和SQL操作。我們必須使用StreamingContext正在使用地SparkContext創建SparkSession。此外,必須如此,纔可以在驅動器故障時重新啓動。這是通過創建一個延遲實例化地SparkSession單實例來完成的。這在下示例中得以展示。

/** Java Bean class for converting RDD to DataFrame */
public class JavaRow implements java.io.Serializable {
  private String word;

  public String getWord() {
    return word;
  }

  public void setWord(String word) {
    this.word = word;
  }
}

...

/** DataFrame operations inside your streaming program */

JavaDStream<String> words = ... 

words.foreachRDD((rdd, time) -> {
  // Get the singleton instance of SparkSession
  SparkSession spark = SparkSession.builder().config(rdd.sparkContext().getConf()).getOrCreate();

  // Convert RDD[String] to RDD[case class] to DataFrame
  JavaRDD<JavaRow> rowRDD = rdd.map(word -> {
    JavaRow record = new JavaRow();
    record.setWord(word);
    return record;
  });
  DataFrame wordsDataFrame = spark.createDataFrame(rowRDD, JavaRow.class);

  // Creates a temporary view using the DataFrame
  wordsDataFrame.createOrReplaceTempView("words");

  // Do word count on table using SQL and print it
  DataFrame wordCountsDataFrame =
    spark.sql("select word, count(*) as total from words group by word");
  wordCountsDataFrame.show();
});

我們還可以對從不同線程(即,與正在運行的StreamingContext異步)的流數據上定義的表運行SQL查詢。只需要確保將StreamingContext設置爲記住足夠數量的流數據,以便查詢可以運行。否則,不知道任何異步SQL查詢的StreamingContext將在查詢完成之前刪除舊的流數據。例如,如果要查詢最後一批,但查詢可能需要5分鐘才能運行,則調用streamingContext.remember(Minutes(5))

MLlib操作

我們還可以輕鬆使用MLlib提供的機器學習算法。首先,有流媒體機器學習算法(例如流媒體線性迴歸,流媒體KMeans等),它們可以同時學習流數據以及將模型應用於流數據。除此之外,對於更大類的機器學習算法,我們可以離線學習學習模型(即使用歷史數據),然後在線將數據應用於流數據。

緩存/持久性

與RDD類似,DStreams還允許開發人員將流的數據保存在內存中。也就是說,persist()在DStream上使用該方法會自動將該DStream的每個RDD保留在內存中。如果DStream中的數據將被多次計算(例如,對相同數據進行多次操作),這將非常有用。對於像reduceByWindow、reduceByKeyAndWindow這樣的基於窗口操作和updateStateByKey這樣基於狀態的操作,這是隱含的。因此,基於窗口的操作生成的DStream會自動保留在內存中,而無需開發人員調用persist()。

對於通過網絡接收數據的輸入流(例如,Kafka,Flume,Socket等),默認持久性級別設置爲將數據複製到兩個節點以實現容錯。

請注意,與RDD不同,DStream的默認持久性級別會將數據序列化爲內存。

Checkpoint

流應用程序必須全天候運行,因此必須能夠適應與應用程序邏輯無關的故障(例如,系統故障,JVM崩潰等)。爲了實現這一點,Spark Streaming需要將足夠的信息檢查到容錯存儲系統,以便它可以從故障中恢復。檢查點有兩種類型的數據。

  • 元數據檢查點:將定義流式計算的信息保存到容錯存儲(如HDFS)。這用於從運行流應用程序的驅動程序的節點的故障中恢復。元數據包括:
    • 配置:用於創建流應用程序的配置。
    • DStream操作:定義流應用程序的DStream操作集。
    • 不完整的批次:其工作排隊但尚未完成的批次。
  • 數據檢查點:將生成的RDD保存到可靠的存儲。在一些跨多個批次組合數據的有狀態轉換中,這是必需的。在這種轉換中,生成的RDD依賴於先前批次的RDD,這導致依賴關係鏈的長度隨時間增加。爲了避免恢復時間的這種無限增加(與依賴鏈成比例),有狀態變換的中間RDD週期性地檢查點到可靠存儲(例如HDFS)以切點依賴鏈。

總而言之,元數據檢查點主要用於從驅動程序故障中恢復,而如果使用狀態轉換,即使對於基本功能也需要數據或RDD檢查點。

何時啓用checkpoint

必須爲具有以下任何要求地應用程序啓用檢查點:

  • 有狀態轉換的用法:如果在應用程序中使用了(updateStateByKey或reduceByKeyAndWindow使用反函數),則必須提供檢查點目錄以允許定期RDD檢查點。
  • 從運行應用程序的驅動程序的故障中恢復:元數據檢查點用於使用進度信息進行恢復。

請注意,可以在不啓用檢查點的情況下運行沒有上述有狀態轉換的簡單流應用程序。在這種情況下,驅動程序故障的恢復也將是部分的(某些已接收但未處理的數據可能會丟失)。這通常是可以接受的,並且許多以這種方式運行Spark Streaming應用程序。

如何配置checkpoint

可以通過在容錯,可靠的文件系統(例如,HDFS,S3等)中設置目錄來啓用檢查點,檢查點信息將保存到該文件系統中。這是通過使用完成的streamingContext.checkpoint(checkpointDirectory)。這將允許我們使用上述有狀態轉換。此外,如果要使應用程序從驅動程序故障中恢復,則應重寫流應用程序以使其具有以下行爲。

  • 當程序第一次啓動時,它將創建一個新的StreamingContext,設置所有流然後調用start()。
  • 當程序在失敗後重啓時,他將會從檢查點目錄中的檢查點數據重新創建StreamingContext。
// Create a factory object that can create and setup a new JavaStreamingContext
JavaStreamingContextFactory contextFactory = new JavaStreamingContextFactory() {
  @Override public JavaStreamingContext create() {
    JavaStreamingContext jssc = new JavaStreamingContext(...);  // new context
    JavaDStream<String> lines = jssc.socketTextStream(...);     // create DStreams
    ...
    jssc.checkpoint(checkpointDirectory);                       // set checkpoint directory
    return jssc;
  }
};

// Get JavaStreamingContext from checkpoint data or create a new one
JavaStreamingContext context = JavaStreamingContext.getOrCreate(checkpointDirectory, contextFactory);

// Do additional setup on context that needs to be done,
// irrespective of whether it is being started or restarted
context. ...

// Start the context
context.start();
context.awaitTermination();

如果checkpointDirectory存在,則將從檢查點數據重新創建上下文。如果目錄不存在(即第一次運行),則將contextFactory調用該函數以創建新上下文並設置DStream。

除了使用getOrCreate之外還需要確保驅動程序進程在失敗時自動重啓。這隻能通過用於運行應用程序的部署基礎結構來完成。

請注意,RDD的檢查點會導致節省可靠存儲的成本。這可能會導致RDD被檢查點的哪些批次的處理時間增加。因此,需要仔細設置檢查點的間隔。在小批量(例如1秒)時,每批次的檢查點可能會顯著降低操作吞吐量。相反,檢查點過於頻繁會導致譜系和任務大小增長,這可能會產生不利影響。對於需要RDD檢查點的有狀態轉換,默認間隔是批處理間隔的倍數,至少爲10秒。它可以通過使用dstream.checkpoint(checkpointInterval)來設置。通常,DStream的5-10個滑動間隔的檢查點間隔是一個很好的設置。

累加器,廣播變量和checkpoint

無法從Spark Streaming中的檢查點恢復累加器和廣播變量。如果啓用了檢查點並使用累加器或廣播變量,則必須爲累加器和廣播變量創建延遲實例化的單實例,以便在驅動程序重新啓動失敗後重新實例化它們。示例如下:

class JavaWordBlacklist {

  private static volatile Broadcast<List<String>> instance = null;

  public static Broadcast<List<String>> getInstance(JavaSparkContext jsc) {
    if (instance == null) {
      synchronized (JavaWordBlacklist.class) {
        if (instance == null) {
          List<String> wordBlacklist = Arrays.asList("a", "b", "c");
          instance = jsc.broadcast(wordBlacklist);
        }
      }
    }
    return instance;
  }
}

class JavaDroppedWordsCounter {

  private static volatile LongAccumulator instance = null;

  public static LongAccumulator getInstance(JavaSparkContext jsc) {
    if (instance == null) {
      synchronized (JavaDroppedWordsCounter.class) {
        if (instance == null) {
          instance = jsc.sc().longAccumulator("WordsInBlacklistCounter");
        }
      }
    }
    return instance;
  }
}

wordCounts.foreachRDD((rdd, time) -> {
  // Get or register the blacklist Broadcast
  Broadcast<List<String>> blacklist = JavaWordBlacklist.getInstance(new JavaSparkContext(rdd.context()));
  // Get or register the droppedWordsCounter Accumulator
  LongAccumulator droppedWordsCounter = JavaDroppedWordsCounter.getInstance(new JavaSparkContext(rdd.context()));
  // Use blacklist to drop words and use droppedWordsCounter to count them
  String counts = rdd.filter(wordCount -> {
    if (blacklist.value().contains(wordCount._1())) {
      droppedWordsCounter.add(wordCount._2());
      return false;
    } else {
      return true;
    }
  }).collect().toString();
  String output = "Counts at time " + time + " " + counts;
}

 

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