spark內存計算框架(1)

1. spark是什麼

  • Apache Spark™ is a unified analytics engine for large-scale data processing.

  • spark是針對於``大規模數據處理`的統一分析引擎

  • spark是在Hadoop基礎上的改進,是UC Berkeley AMP lab所開源的類Hadoop MapReduce的通用的並行計算框架,Spark基於map reduce算法實現的分佈式計算,擁有Hadoop MapReduce所具有的優點;

  • 但不同於MapReduce的是Job中間輸出和結果可以保存在內存中,從而不再需要讀寫HDFS,因此Spark能更好地適用於數據挖掘與機器學習等需要迭代的map reduce的算法

  • spark是基於內存計算框架,計算速度非常之快,但是它僅僅只是涉及到計算,並沒有涉及到數據的存儲,後期需要使用spark對接外部的數據源,比如hdfs

2. spark的四大特性

2.1 速度快

  • 運行速度提高100

  • Apache Spark使用最先進的DAG調度程序,查詢優化程序和物理執行引擎,實現批量和流式數據的高性能

  • spark比mapreduce快的2個主要原因 :

    • 1、基於內存

      • mapreduce任務後期再計算的時候,每一個job的輸出結果會落地到磁盤,後續有其他的job需要依賴於前面job的輸出結果,這個時候就需要進行大量的磁盤io操作。性能就比較低
      • spark任務後期再計算的時候,job的輸出結果可以保存在內存中,後續有其他的job需要依賴於前面job的輸出結果,這個時候就直接從內存中獲取得到,避免了磁盤io操作,性能比較高
      • spark程序在shuffle階段產生的數據都會落地到磁盤中
    • 2、進程與線程

      • mapreduce任務以進程的方式運行在yarn集羣中,比如程序中有100個MapTask,一個task就需要一個進程,這些task要運行就需要開啓100個進程。

      • spark任務以線程的方式運行在進程中,比如程序中有100個MapTask,後期一個task就對應一個線程,這裏就不在是進程,這些task需要運行,這裏可以極端一點:只需要開啓1個進程,在這個進程中啓動100個線程就可以了。進程中可以啓動很多個線程,而開啓一個進程與開啓一個線程需要的時間和調度代價是不一樣。 開啓一個進程需要的時間遠遠大於開啓一個線程。

2.2 易用性

  • 可以快速去編寫spark程序通過java/scala/python/R/SQL等不同語言

2.3 通用性

  • spark框架不在是一個簡單的框架,可以把spark理解成一個生態系統,它內部是包含了很多模塊,基於不同的應用場景可以選擇對應的模塊去使用
    • sparksql :通過sql去開發spark程序做一些離線分析
    • sparkStreaming : 主要是用來解決公司有實時計算的這種場景
    • Mlib :它封裝了一些機器學習的算法庫
    • Graphx :圖計算

2.4 兼容性

  • spark程序就是一個計算邏輯程序,這個任務要運行就需要計算資源(內存、cpu、磁盤),哪裏可以給當前這個任務提供計算資源,就可以把spark程序提交到哪裏去運行
    • standAlone
      • 它是spark自帶的獨立運行模式,整個任務的資源分配由spark集羣的老大Master負責
    • yarn
      • 可以把spark程序提交到yarn中運行,整個任務的資源分配由yarn中的老大ResourceManager負責
    • mesos
      • 它也是apache開源的一個類似於yarn的資源調度平臺

3. spark集羣架構

在這裏插入圖片描述

  • Driver

    • 它會執行客戶端寫好的main方法,它會構建一個名叫SparkContext對象
    • 該對象是所有spark程序的執行入口
  • Application

    • 就是一個spark的應用程序,它是包含了客戶端的代碼和任務運行的資源信息
  • ClusterManager

    • 它是給程序提供計算資源的外部服務
      • standAlone : 它是spark自帶的集羣模式,整個任務的資源分配由spark集羣的老大Master負責
      • yarn : 可以把spark程序提交到yarn中運行,整個任務的資源分配由yarn中的老大ResourceManager負責
      • mesos : 它也是apache開源的一個類似於yarn的資源調度平臺
  • Master

    • 它是整個spark集羣的主節點,負責任務資源的分配
  • Worker

    • 它是整個spark集羣的從節點,負責任務計算的節點
  • Executor

    • 它是一個進程,它會在worker節點啓動該進程(計算資源)
  • Task

    • spark任務是以task線程的方式運行在worker節點對應的executor進程中

4. spark集羣安裝部署

  • 事先搭建好zookeeper集羣
  • 1、下載安裝包

  • 2、規劃安裝目錄

    • /zsc/install
  • 3、上傳安裝包到服務器

  • 4、解壓安裝包到指定的安裝目錄

    • tar -zxvf spark-2.3.3-bin-hadoop2.7.tgz -C /zsc/install
  • 5、重命名解壓目錄

    • mv spark-2.3.3-bin-hadoop2.7 spark
  • 6、修改配置文件

    • 進入到spark的安裝目錄下對應的conf文件夾

      • vim spark-env.sh ( mv spark-env.sh.template spark-env.sh)

        #配置java的環境變量
        export JAVA_HOME=/zsc/install/jdk1.8.0_141
        #配置zk相關信息
        export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER  -Dspark.deploy.zookeeper.url=node01:2181,node02:2181,node03:2181  -Dspark.deploy.zookeeper.dir=/spark"
        
      • vim slaves ( mv slaves.template slaves)

        #指定spark集羣的worker節點
        node02
        node03
        
  • 7、分發安裝目錄到其他機器

    scp -r /zsc/install/spark node02:/zsc/install
    scp -r /zsc/install/spark node03:/zsc/install
    
  • 8、修改spark環境變量

    • vim /etc/profile

      export SPARK_HOME=/zsc/install/spark
      export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin
      
  • 9、分發spark環境變量到其他機器

    scp /etc/profile node02:/etc
    scp /etc/profile node03:/etc
    
  • 10、讓所有機器的spark環境變量生效

    • 在所有節點執行 source /etc/profile

5. spark集羣的啓動和停止

5.1 啓動

  • 1、先啓動zk
  • 2、啓動spark集羣
    • 可以在任意一臺服務器來執行(條件:需要任意2臺機器之間實現ssh免密登錄)
      • $SPARK_HOME/sbin/start-all.sh
      • 在哪裏啓動這個腳本,就在當前該機器啓動一個Master進程
      • 整個集羣的worker進程的啓動由slaves文件決定
    • 後期可以在其他機器單獨在啓動master
      • $SPARK_HOME/sbin/start-master.sh
  • 如何恢復到上一次活着master掛掉之前的狀態?

    • 在高可用模式下,整個spark集羣就有很多個master,其中只有一個master被zk選舉成活着的master,其他的多個master都處於standby,同時把整個spark集羣的元數據信息通過zk中節點進行保存
    • 後期如果活着的master掛掉。首先zk會感知到活着的master掛掉,下面開始在多個處於standby中的master進行選舉,再次產生一個活着的master,這個活着的master會讀取保存在zk節點中的spark集羣元數據信息,恢復到上一次master的狀態。整個過程在恢復的時候經歷過了很多個不同的階段,每個階段都需要一定時間,最終恢復到上個活着的master的轉態,整個恢復過程一般需要1-2分鐘
  • 在master的恢復階段對任務的影響?

    • 已經運行的任務是沒有任何影響 : 由於該任務正在運行,說明它已經拿到了計算資源,這個時候就不需要master

    • 對即將要提交的任務是有影響 : 由於該任務需要有計算資源,這個時候會找活着的master去申請計算資源,由於沒有一個活着的master,該任務是獲取不到計算資源,也就是任務無法運行

5.2 停止

  • 在處於active Master主節點執行

    • $SPARK_HOME/sbin/stop-all.sh
  • 在處於standBy Master主節點執行

    • $SPARK_HOME/sbin/stop-master.sh

6. spark集羣的web UI

  • 當啓動好spark集羣之後,可以訪問 : http://node01:8080
  • 我們可以通過web界面觀察到很多信息
    • 整個spark集羣的詳細信息
    • 整個spark集羣總的資源信息
    • 整個spark集羣已經使用的資源信息
    • 整個spark集羣還剩的資源信息
    • 整個spark集羣正在運行的任務信息
    • 整個spark集羣已經完成的任務信息
    • 等等

在這裏插入圖片描述

7. 初識spark程序

7.1 普通模式提交 (指定活着的master地址)

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node01:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.3.3.jar \
10


####參數說明
--class:指定包含main方法的主類
--master:指定spark集羣master地址
--executor-memory:指定任務在運行的時候需要的每一個executor內存大小
--total-executor-cores: 指定任務在運行的時候需要總的cpu核數

7.2 高可用模式提交 (集羣有很多個master)

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node01:7077,node02:7077,node03:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.3.3.jar \
10

# spark集羣中有很多個master,並不知道哪一個master是活着的master,即使你知道哪一個master是活着的master,它也有可能下一秒就掛掉,這裏就可以把所有master都羅列出來:
# --master spark://node01:7077,node02:7077,node03:7077
# 後期程序會輪訓整個master列表,最終找到活着的master,然後向它申請計算資源,最後運行程序

8. spark-shell使用

8.1 運行spark-shell --master local[N] 讀取本地文件進行單詞統計

  • –master local[N]

    • local 表示程序在本地進行計算,跟spark集羣目前沒有任何關係
    • N 它是一個正整數,表示使用N個線程參與任務計算
    • local[N] 表示本地採用N個線程計算任務
  • spark-shell --master local[2] : 默認會產生一個SparkSubmit進程

    sc.textFile("file:///home/hadoop/words.txt").flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>x+y).collect
    
    sc.textFile("file:///home/hadoop/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
    

8.2 運行spark-shell --master local[N] 讀取HDFS上文件進行單詞統計

  • spark整合HDFS

    • 在node01上修改配置文件
    • vim spark-env.sh
    export HADOOP_CONF_DIR=/zsc/install/hadoop-2.6.0-cdh5.14.2/etc/hadoop
    
    • 分發到其他節點
    scp spark-env.sh node02:/zsc/install/spark/conf
    scp spark-env.sh node03:/zsc/install/spark/conf
    
  • spark-shell --master local[2]

    sc.textFile("/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
    
    sc.textFile("hdfs://node01:8020/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
    

8.3 運行spark-shell 指定集羣中活着master 讀取HDFS上文件進行單詞統計

  • spark-shell --master spark://node01:7077 --executor-memory 1g --total-executor-cores 4

    • –master spark://node01:7077 : 指定活着的master地址
    • –executor-memory 1g : 指定每一個executor進程的內存大小
    • –total-executor-cores 4 : 指定總的executor進程cpu核數
    sc.textFile("hdfs://node01:8020/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
    
    //實現讀取hdfs上文件之後,需要把計算的結果保存到hdfs上
    sc.textFile("/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).saveAsTextFile("/out")
    

9. 使用IDEA開發spark程序

  • 構建maven工程,添加pom依賴

     <dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>2.3.3</version>
        </dependency>
    </dependencies>
    
    
     <build>
            <sourceDirectory>src/main/scala</sourceDirectory>
            <testSourceDirectory>src/test/scala</testSourceDirectory>
            <plugins>
                <plugin>
                    <groupId>net.alchim31.maven</groupId>
                    <artifactId>scala-maven-plugin</artifactId>
                    <version>3.2.2</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>testCompile</goal>
                            </goals>
                            <configuration>
                                <args>
                                    <arg>-dependencyfile</arg>
                                    <arg>${project.build.directory}/.scala_dependencies</arg>
                                </args>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>2.4.3</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <filters>
                                    <filter>
                                        <artifact>*:*</artifact>
                                        <excludes>
                                            <exclude>META-INF/*.SF</exclude>
                                            <exclude>META-INF/*.DSA</exclude>
                                            <exclude>META-INF/*.RSA</exclude>
                                        </excludes>
                                    </filter>
                                </filters>
                                <transformers>
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                        <mainClass></mainClass>
                                    </transformer>
                                </transformers>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
     </build>
    
  • 創建 src/main/scala 和 src/test/scala 目錄
    在這裏插入圖片描述

9.1 利用scala語言開發spark程序實現單詞統計–本地運行

package com.zsc

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

//todo: 利用scala語言開發spark程序實現單詞統計
object WordCount {
  def main(args: Array[String]): Unit = {
    //1、構建sparkConf對象 設置application名稱和master地址
    val sparkConf: SparkConf = new SparkConf().setAppName("WordCount").setMaster("local[2]")

    //2、構建sparkContext對象,該對象非常重要,它是所有spark程序的執行入口
    // 它內部會構建  DAGScheduler和 TaskScheduler 對象
    val sc = new SparkContext(sparkConf)

    //設置日誌輸出級別
    sc.setLogLevel("warn")

    //3、讀取數據文件
    val data: RDD[String] = sc.textFile("D:\\words.txt")

    //4、 切分每一行,獲取所有單詞
    val words: RDD[String] = data.flatMap(x=>x.split(" "))

    //5、每個單詞計爲1
    val wordAndOne: RDD[(String, Int)] = words.map(x => (x,1))

    //6、相同單詞出現的1累加
    val result: RDD[(String, Int)] = wordAndOne.reduceByKey((x,y)=>x+y)

    //按照單詞出現的次數降序排列  第二個參數默認是true表示升序,設置爲false表示降序
    val sortedRDD: RDD[(String, Int)] = result.sortBy( x=> x._2,false)

    //7、收集數據打印
    val finalResult: Array[(String, Int)] = sortedRDD.collect()
    finalResult.foreach(println)

    //8、關閉sc
    sc.stop()
  }
}

9.2 利用scala語言開發spark程序實現單詞統計–集羣運行

package com.zsc;
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

//todo: 利用scala語言開發spark程序實現單詞統計
object WordCountOnSpark {
  def main(args: Array[String]): Unit = {
    //1、構建sparkConf對象 設置application名稱
    val sparkConf: SparkConf = new SparkConf().setAppName("WordCountOnSpark")

    //2、構建sparkContext對象,該對象非常重要,它是所有spark程序的執行入口
    // 它內部會構建  DAGScheduler和 TaskScheduler 對象
    val sc = new SparkContext(sparkConf)

    //設置日誌輸出級別
    sc.setLogLevel("warn")

    //3、讀取數據文件
    val data: RDD[String] = sc.textFile(args(0))

    //4、 切分每一行,獲取所有單詞
    val words: RDD[String] = data.flatMap(x=>x.split(" "))

    //5、每個單詞計爲1
    val wordAndOne: RDD[(String, Int)] = words.map(x => (x,1))

    //6、相同單詞出現的1累加
    val result: RDD[(String, Int)] = wordAndOne.reduceByKey((x,y)=>x+y)

    //7、把計算結果保存在hdfs上
    result.saveAsTextFile(args(1))

    //8、關閉sc
    sc.stop()
  }
}
  • 打成jar包提交到集羣中運行
spark-submit \
--master spark://node01:7077,node02:7077 \
--class com.kaikeba.WordCountOnSpark \
--executor-memory 1g  \
--total-executor-cores 4 \
original-spark_class01-1.0-SNAPSHOT.jar \
/words.txt  /out

9.3 利用java語言開發spark程序實現單詞統計–本地運行

package com.zsc

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
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 scala.Tuple2;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

//todo: 利用java語言開發spark的單詞統計程序
public class JavaWordCount {
    public static void main(String[] args) {
        //1、創建SparkConf對象
        SparkConf sparkConf = new SparkConf().setAppName("JavaWordCount").setMaster("local[2]");

        //2、構建JavaSparkContext對象
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);

        //3、讀取數據文件
        JavaRDD<String> data = jsc.textFile("D:\\words.txt");

        //4、切分每一行獲取所有的單詞   scala:  data.flatMap(x=>x.split(" "))
        JavaRDD<String> wordsJavaRDD = data.flatMap(new FlatMapFunction<String, String>() {
            public Iterator<String> call(String line) throws Exception {
                String[] words = line.split(" ");
                return Arrays.asList(words).iterator();
            }
        });

        //5、每個單詞計爲1    scala:  wordsJavaRDD.map(x=>(x,1))
        JavaPairRDD<String, Integer> wordAndOne = wordsJavaRDD.mapToPair(new PairFunction<String, String, Integer>() {
            public Tuple2<String, Integer> call(String word) throws Exception {
                return new Tuple2<String, Integer>(word, 1);
            }
        });

        //6、相同單詞出現的1累加    scala:  wordAndOne.reduceByKey((x,y)=>x+y)
        JavaPairRDD<String, Integer> result = wordAndOne.reduceByKey(new Function2<Integer, Integer, Integer>() {
            public Integer call(Integer v1, Integer v2) throws Exception {
                return v1 + v2;
            }
        });

        //按照單詞出現的次數降序 (單詞,次數)  -->(次數,單詞).sortByKey----> (單詞,次數)
        JavaPairRDD<Integer, String> reverseJavaRDD = result.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
            public Tuple2<Integer, String> call(Tuple2<String, Integer> t) throws Exception {
                return new Tuple2<Integer, String>(t._2, t._1);
            }
        });

        JavaPairRDD<String, Integer> sortedRDD = reverseJavaRDD.sortByKey(false).mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
            public Tuple2<String, Integer> call(Tuple2<Integer, String> t) throws Exception {
                return new Tuple2<String, Integer>(t._2, t._1);
            }
        });

        //7、收集打印
        List<Tuple2<String, Integer>> finalResult = sortedRDD.collect();

        for (Tuple2<String, Integer> t : finalResult) {
            System.out.println("單詞:"+t._1 +"\t次數:"+t._2);
        }

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