【Spark篇】---SparkStream初始與應用

LHBlog發表於2018-02-09

 一、前述

SparkStreaming是流式處理框架,Spark API的擴充套件,支援可擴充套件、高吞吐量、容錯的實時資料流處理,實時資料的來源可以是:Kafka, Flume, Twitter, ZeroMQ或者TCP sockets,並且可以使用高階功能的複雜運算元來處理流資料。例如:map,reduce,join,window 。最終,處理後的資料可以存放在檔案系統,資料庫等,方便實時展現。

二、SparkStreaming與Storm的區別

1、Storm是純實時的流式處理框架,SparkStreaming是準實時的處理框架(微批處理)。因為微批處理,SparkStreaming的吞吐量比Storm要高。

2、Storm 的事務機制要比SparkStreaming的要完善。

3、Storm支援動態資源排程。(spark1.2開始和之後也支援)

4、SparkStreaming擅長複雜的業務處理,Storm不擅長複雜的業務處理,擅長簡單的彙總型計算。
三、Spark初始

 

 

  • receiver  task是7*24小時一直在執行,一直接受資料,將一段時間內接收來的資料儲存到batch中。假設batchInterval為5s,那麼會將接收來的資料每隔5秒封裝到一個batch中,batch沒有分散式計算特性,這一個batch的資料又被封裝到一個RDD中,RDD最終封裝到一個DStream中。

例如:假設batchInterval為5秒,每隔5秒通過SparkStreamin將得到一個DStream,在第6秒的時候計算這5秒的資料,假設執行任務的時間是3秒,那麼第6~9秒一邊在接收資料,一邊在計算任務,9~10秒只是在接收資料。然後在第11秒的時候重複上面的操作。

  • 如果job執行的時間大於batchInterval會有什麼樣的問題?

如果接受過來的資料設定的級別是僅記憶體,接收來的資料會越堆積越多,最後可能會導致OOM(如果設定StorageLevel包含disk, 則記憶體存放不下的資料會溢寫至disk, 加大延遲 

 

四、SparkStreaming程式碼

 

程式碼注意事項:

 

  • 啟動socket server 伺服器:nc –lk 9999
  • receiver模式下接受資料,local的模擬執行緒必須大於等於2一個執行緒用來receiver用來接受資料,另一個執行緒用來執行job。
  • Durations時間設定就是我們能接收的延遲度。這個需要根據叢集的資源情況以及任務的執行情況來調節。
  • 建立JavaStreamingContext有兩種方式(SparkConf,SparkContext)
  • 所有的程式碼邏輯完成後要有一個output operation類運算元觸發執行
  • JavaStreamingContext.start() Streaming框架啟動後不能再次新增業務邏輯。
  • JavaStreamingContext.stop() 無參的stop方法將SparkContext一同關閉,stop(false),不會關閉SparkContext,方便後面使用
  • JavaStreamingContext.stop()停止之後不能再呼叫start。
package com.spark.sparkstreaming;

import java.util.Arrays;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaPairDStream;
import org.apache.spark.streaming.api.java.JavaReceiverInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;

import scala.Tuple2;
/**
 * 1、local的模擬執行緒數必須大於等於2 因為一條執行緒被receiver(接受資料的執行緒)佔用,另外一個執行緒是job執行
 * 2、Durations時間的設定,就是我們能接受的延遲度,這個我們需要根據叢集的資源情況以及監控每一個job的執行時間來調節出最佳時間。
 * 3、 建立JavaStreamingContext有兩種方式 (sparkconf、sparkcontext)
 * 4、業務邏輯完成後,需要有一個output operator
 * 5、JavaStreamingContext.start()straming框架啟動之後是不能在次新增業務邏輯
 * 6、JavaStreamingContext.stop()無參的stop方法會將sparkContext一同關閉,stop(false) ,預設為true,會一同關閉
 * 7、JavaStreamingContext.stop()停止之後是不能在呼叫start   
 */

/**
 * foreachRDD  運算元注意:
 * 1.foreachRDD是DStream中output operator類運算元
 * 2.foreachRDD可以遍歷得到DStream中的RDD,可以在這個運算元內對RDD使用RDD的Transformation類運算元進行轉化,但是一定要使用rdd的Action類運算元觸發執行。
 * 3.foreachRDD可以得到DStream中的RDD,在這個運算元內RDD運算元外執行的程式碼是在Driver端執行的,RDD運算元內的程式碼是在Executor中執行。
 *
 */
public class WordCountOnline {
    @SuppressWarnings("deprecation")
    public static void main(String[] args) {
         
        SparkConf conf = new SparkConf().setMaster("local[2]").setAppName("WordCountOnline");
        /**
         * 在建立streaminContext的時候 設定batch Interval
         */
        JavaStreamingContext jsc = new JavaStreamingContext(conf, Durations.seconds(5));
//        JavaSparkContext sc = new JavaSparkContext(conf);
//        JavaStreamingContext jsc = new JavaStreamingContext(sc,Durations.seconds(5));//兩種辦法得到StreamingContext
//        JavaSparkContext sparkContext = jsc.sparkContext();
        
        JavaReceiverInputDStream<String> lines = jsc.socketTextStream("node04", 9999);//監控socket埠9999
        
        JavaDStream<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
            /**
             * 
             */
            private static final long serialVersionUID = 1L;

            @Override
            public Iterable<String> call(String s) {
                return Arrays.asList(s.split(" "));
            }
        });

        JavaPairDStream<String, Integer> ones = words.mapToPair(new PairFunction<String, String, Integer>() {
            /**
             * 
             */
            private static final long serialVersionUID = 1L;

            @Override
            public Tuple2<String, Integer> call(String s) {
                return new Tuple2<String, Integer>(s, 1);
            }
        });

        JavaPairDStream<String, Integer> counts = ones.reduceByKey(new Function2<Integer, Integer, Integer>() {
            /**
             * 
             */
            private static final long serialVersionUID = 1L;

            @Override
            public Integer call(Integer i1, Integer i2) {
                return i1 + i2;
            }
        });
         
        //outputoperator類的運算元   
         counts.print();
         /*counts.foreachRDD(new VoidFunction<JavaPairRDD<String,Integer>>() {

            *//**
             * 這裡寫的程式碼是在Driver端執行的
             *//*
            private static final long serialVersionUID = 1L;

            @Override
            public void call(JavaPairRDD<String, Integer> pairRDD) throws Exception {
                
                pairRDD.foreach(new VoidFunction<Tuple2<String,Integer>>() {

                    *//**
                     * 
                     *//*
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void call(Tuple2<String, Integer> tuple)
                            throws Exception {
                        System.out.println("tuple ---- "+tuple );
                    }
                });
            }
        });*/
         jsc.start();
         //等待spark程式被終止
         jsc.awaitTermination();
         jsc.stop(false);
    }
}

scala程式碼:

 

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Durations

object Operator_foreachRDD {
   def main(args: Array[String]): Unit = {
     val conf = new SparkConf()
     conf.setMaster("local[2]").setAppName("foreachRDD")
     val sc = new SparkContext(conf)
     val jsc = new StreamingContext(sc,Durations.seconds(5))
     
     val socketDStream = jsc.socketTextStream("node5", 9999)
     socketDStream.foreachRDD { rdd => {
       rdd.foreach { elem => {
         println(elem)
       } }
     }}
     
     jsc.start()
     jsc.awaitTermination()
     jsc.stop(false)
   }
}

 

 

 

相關文章