Spark知識點總結

1.什麼spark?
spark是基於內存計算的通用大數據並行計算框架,是一個快速、通用可擴展的大數據分析引擎。它給出了大一統的軟件開發棧,適用於不同場合的分佈式場景,如批處理、迭代算法、交互式查詢、流處理、機器學習和圖計算。
2.spark生態有哪些?
SparkCore:spark的核心計算 主要Rdd
SparkSQL:提供了類sql方式操作結構化半結構化數據。對歷史數據進行交互式查詢。(即席查詢:用戶根據自己的需求,自定義查詢)

SparkStreaming:提供了近乎實時的流式數據處理,與storm相比有更高的吞吐量。(實時計算 目前實時計算框架有哪些? storm、sparkstreaming、flink)

SparkMl:提供了常見的機器學習算法庫,包括分類、迴歸、聚類、協同工過濾(個性推薦:用戶畫像)等,還提供模型評估、數據處理等額外功能,使得機器學習能夠更加方便的在分佈式大數據環境下,快速的對數據進行處理形成模型後提供在線服務。

Graphx:用來操作圖的程序庫,可以進行並行的圖計算。支持各種常見的圖算法,包括page rank、Triangle Counting等。
3.spark的提交流程?
在這裏插入圖片描述
4.spark的提交方式?有什麼區別?

  • client模式:
    在這裏插入圖片描述
  • cluster模式:
    在這裏插入圖片描述
    client模式與cluster模式的區別:
  1. 啓動集羣nodeManager向ResourceManager彙報資源。

  2. RS掌握了集羣資源。

  3. 客戶端提交application。

  4. 客戶端向ResourceManager申請啓動ApplicationMaster。

  5. ResourceManager收到請求之後隨即找到一臺NodeManager結點啓動ApplicationMaster。

  6. ApplicationMaster啓動之後向ResourceManager申請資源用於啓動Executor。

  7. ResourceManager將申請到的Executor的節點NodeManager返回給ApplicationMaster。

  8. ApplicationMaster連接NodeManager啓動Executor。

  9. Executor啓動字後反向註冊給ApplicationMaster

  10. ApplicationMaster發送task到Executor執行並監控task執行回收結果。
    注意:
    client模式提交任務,會在客戶端看到task的執行情況和結果,當在客戶端提交多個application時,每個application都會啓動自己的Driver,Driver與集羣Worker有大量的通信,會造成客戶端網卡流量激增問題。這種模式適用於程序測試。不適用於生產環境。

    模式提交任務,Driver會在急羣衆隨機一臺Worker上啓動,如果提交多個application時,那麼每個application的Driver會分散到集羣的Worker節點,相當於將client模式的客戶端網卡流量激增問題分散到集羣中。這種模式適用於生產環境。

    因爲cluster模式,隨機分散在Worker節點上創建Driver,由Driver來發送任務到Worker。所以打包的程序任務必須在分散的Worker節點對應的目錄下都存在。

5.spark算子?(隨口20個)
見本博客兩章Transformation算子&Action算子、控制算子

點擊查看->《Treansformation算子&Action算子》
點擊查看->《控制算子》

6.什麼是寬依賴 窄依賴?
Spark中RDD的高效與DAG(有向無環圖)有很大的關係,在DAG調度中需要對計算的過程劃分Stage,劃分的依據就是RDD之間的依賴關係。RDD之間的依賴關係分爲兩種,寬依賴(wide dependency/shuffle dependency)和窄依賴(narrow dependency)。
左邊爲窄依賴,右邊爲寬依賴
(左邊爲窄依賴,右邊爲寬依賴)

  • 窄依賴:
    窄依賴就是指父RDD的每個分區只被一個子RDD分區使用,子RDD分區通常只對應常數個父RDD分區,如下圖所示【其中每個小方塊代表一個RDD Partition】

    窄依賴有分爲兩種:
    一種是一對一的依賴,即OneToOneDependency
    還有一個是範圍的依賴,即RangeDependency,它僅僅被org.apache.spark.rdd.UnionRDD使用。UnionRDD是把多個RDD合成一個RDD,這些RDD是被拼接而成,即每個parent RDD的Partition的相對順序不會變,只不過每個parent RDD在UnionRDD中的Partition的起始位置不同

  • 寬依賴:
    寬依賴就是指父RDD的每個分區都有可能被多個子RDD分區使用,子RDD分區通常對應父RDD所有分區,如下圖所示【其中每個小方塊代表一個RDD Partition】

窄依賴的函數有:
map, filter, union, join(父RDD是hash-partitioned ), mapPartitions, mapValues
寬依賴的函數有:
groupByKey, join(父RDD不是hash-partitioned ), partitionBy

7.spark shuffle?
點擊查看->《spark shuffle》

和mr shuffle:從map端的輸出到reduce 的輸入,慢的主要原因是有數據落地,磁盤IO
spark三種,優化前(HashShuffle),優化1(優化後的HashShuffle),優化2(SortShuffle) 主要是中間臨時小文件的優化

8.spark優化?(隨口說出10條以上)
點擊查看->《Spark優化要點(開發)》

==9.shuffle類算子有哪些? ==

  • 去重類算子
def distinct()

def distinct(numPartitions: Int)
  • 聚合類算子
def reduceByKey(func: (V, V) => V, numPartitions: Int): RDD[(K, V)]

def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)]

def groupBy[K](f: T => K, p: Partitioner):RDD[(K, Iterable[V])]

def groupByKey(partitioner: Partitioner):RDD[(K, Iterable[V])]

def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner): RDD[(K, U)]

def aggregateByKey[U: ClassTag](zeroValue: U, numPartitions: Int): RDD[(K, U)]

def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C): RDD[(K, C)]

def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C, numPartitions: Int): RDD[(K, C)]

def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C, partitioner: Partitioner, mapSideCombine: Boolean =true, serializer: Serializer =null): RDD[(K, C)]
  • 排序類算子
def sortByKey(ascending: Boolean =true, numPartitions: Int = self.partitions.length): RDD[(K, V)]

def sortBy[K](f: (T) => K, ascending: Boolean =true, numPartitions: Int =this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]
  • 重分區類算子
def coalesce(numPartitions: Int, shuffle: Boolean =false, partitionCoalescer: Option[PartitionCoalescer] = Option.empty)

def repartition(numPartitions: Int)(implicit ord: Ordering[T] =null)
  • 集合或者表操作類算子
def intersection(other: RDD[T]): RDD[T]

def intersection(other: RDD[T], partitioner: Partitioner)(implicit ord: Ordering[T] =null): RDD[T]

def intersection(other: RDD[T], numPartitions: Int): RDD[T]

def subtract(other: RDD[T], numPartitions: Int): RDD[T]

def subtract(other: RDD[T], p: Partitioner)(implicit ord: Ordering[T] =null): RDD[T]

def subtractByKey[W: ClassTag](other: RDD[(K, W)]): RDD[(K, V)]

def subtractByKey[W: ClassTag](other: RDD[(K, W)], numPartitions: Int): RDD[(K, V)]

def subtractByKey[W: ClassTag](other: RDD[(K, W)], p: Partitioner): RDD[(K, V)]

def join[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, W))]

def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]

def join[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, W))]

def leftOuterJoin[W](other: RDD[(K, W)]): RDD[(K, (V, Option[W]))]

10.reducebykey和groupbykey 的區別?
先看下源碼:

/**
 * Merge the values for each key using an associative reduce function. This will also perform
 * the merging locally on each mapper before sending results to a reducer, similarly to a
 * "combiner" in MapReduce. Output will be hash-partitioned with the existing partitioner/
 * parallelism level.
 */
def reduceByKey(func: (V, V) => V): RDD[(K, V)] = {
  reduceByKey(defaultPartitioner(self), func)
}


/**
 * Group the values for each key in the RDD into a single sequence. Allows controlling the
 * partitioning of the resulting key-value pair RDD by passing a Partitioner.
 * The ordering of elements within each group is not guaranteed, and may even differ
 * each time the resulting RDD is evaluated.
 *
 * Note: This operation may be very expensive. If you are grouping in order to perform an
 * aggregation (such as a sum or average) over each key, using [[PairRDDFunctions.aggregateByKey]]
 * or [[PairRDDFunctions.reduceByKey]] will provide much better performance.
 *
 * Note: As currently implemented, groupByKey must be able to hold all the key-value pairs for any
 * key in memory. If a key has too many values, it can result in an [[OutOfMemoryError]].
 */
def groupByKey(partitioner: Partitioner): RDD[(K, Iterable[V])] = {
  // groupByKey shouldn't use map side combine because map side combine does not
  // reduce the amount of data shuffled and requires all map side data be inserted
  // into a hash table, leading to more objects in the old gen.
  val createCombiner = (v: V) => CompactBuffer(v)
  val mergeValue = (buf: CompactBuffer[V], v: V) => buf += v
  val mergeCombiners = (c1: CompactBuffer[V], c2: CompactBuffer[V]) => c1 ++= c2
  val bufs = combineByKey[CompactBuffer[V]](
    createCombiner, mergeValue, mergeCombiners, partitioner, mapSideCombine=false)
  bufs.asInstanceOf[RDD[(K, Iterable[V])]]
}

通過源碼可以看出
reduceByKey:reduceByKey會在結果發送至reducer之前會對每個mapper在本地進行merge,有點類似於在MapReduce中的combiner。這樣做的好處在於,在map端進行一次reduce之後,數據量會大幅度減小,從而減小傳輸,保證reduce端能夠更快的進行結果計算。

groupByKey:groupByKey會對每一個RDD中的value值進行聚合形成一個序列(Iterator),此操作發生在reduce端,所以勢必會將所有的數據通過網絡進行傳輸,造成不必要的浪費。同時如果數據量十分大,可能還會造成OutOfMemoryError。

通過以上對比可以發現在進行大量數據的reduce操作時候建議使用reduceByKey。不僅可以提高速度,還是可以防止使用groupByKey造成的內存溢出問題。

11.spark的序列化
主要從以下三個方面解釋Spark 應用中序列化問題 。
1、Java序列化含義?
2、Spark代碼爲什麼需要序列化?
3、如何解決Spark序列化問題?

1、Java序列化含義?
Spark是基於JVM運行的進行,其序列化必然遵守Java的序列化規則。

序列化就是指將一個對象轉化爲二進制的byte流(注意,不是bit流),然後以文件的方式進行保存或通過網絡傳輸,等待被反序列化讀取出來。序列化常被用於數據存取和通信過程中。

對於java應用實現序列化一般方法:

class實現序列化操作是讓class 實現Serializable接口,但實現該接口不保證該class一定可以序列化,因爲序列化必須保證該class引用的所有屬性可以序列化。

這裏需要明白,static和transient修飾的變量不會被序列化,這也是解決序列化問題的方法之一,讓不能序列化的引用用static和transient來修飾。(static修飾的是類的狀態,而不是對象狀態,所以不存在序列化問題。transient修飾的變量,是不會被序列化到文件中,在被反序列化後,transient變量的值被設爲初始值,如int是0,對象是null)

此外還可以實現readObject()方法和writeObject()方法來自定義實現序列化。

2、Spark的transformation操作爲什麼需要序列化?
Spark是分佈式執行引擎,其核心抽象是彈性分佈式數據集RDD,其代表了分佈在不同節點的數據。Spark的計算是在executor上分佈式執行的,故用戶開發的關於RDD的map,flatMap,reduceByKey等transformation 操作(閉包)有如下執行過程:

1. 代碼中對象在driver本地序列化 
2. 對象序列化後傳輸到遠程executor節點 
3. 遠程executor節點反序列化對象 
4. 最終遠程節點執行 

故對象在執行中需要序列化通過網絡傳輸,則必須經過序列化過程。

3、如何解決Spark序列化問題?
如果出現NotSerializableException報錯,可以在spark-default.xml文件中加入如下參數來開啓SerializationDebugger功能類,從而可以在日誌中打印出序列化出問題的類和屬性信息。

spark.executor.extraJavaOptions  -Dsun.io.serialization.extendedDebugInfo=true
spark.driver.extraJavaOption -Dsun.io.serialization.extendedDebugInfo=true

對於scala語言開發,解決序列化問題主要如下幾點:

1、在Object中聲明對象 (每個class對應有一個Object)
2、如果在閉包中使用SparkContext或者SqlContext,建議使用SparkContext.get() and SQLContext.getActiveOrCreate()
3、使用statictransient修飾不可序列化的屬性從而避免序列化。 
	注:scala語言中,class的Object

對於java語言開發,對於不可序列化對象,如果本身不需要存儲或傳輸,則可使用static或trarnsient修飾;如果需要存儲傳輸,則實現writeObject()/readObject()使用自定義序列化方法。

此外注意
對於Spark Streaming作業,注意哪些操作在driver,哪些操作在executor。因爲在driver端(foreachRDD)實例化的對象,很可能不能在foreach中運行,因爲對象不能從driver序列化傳遞到executor端(有些對象有TCP鏈接,一定不可以序列化)。
所以這裏一般在foreachPartitions或foreach算子中來實例化對象,這樣對象在executor端實例化,沒有從driver傳輸到executor的過程。

dstream.foreachRDD { rdd =>
  val where1 = "on the driver"
    rdd.foreach { record =>
      val where2 = "on different executors"
    }
  }
}

12.spark submit 有哪些參數

在spark命令行輸入

./bin/spark-submit --help

可以看到spark-submit的所用參數如下:

Usage: spark-submit [options] <app jar | python file | R file> [app arguments]
Usage: spark-submit --kill [submission ID] --master [spark://...]
Usage: spark-submit --status [submission ID] --master [spark://...]
Usage: spark-submit run-example [options] example-class [example args]
 
Options:
  --master MASTER_URL         spark://host:port, mesos://host:port, yarn,
                              k8s://https://host:port, or local (Default: local[*]).
  --deploy-mode DEPLOY_MODE   Whether to launch the driver program locally ("client") or
                              on one of the worker machines inside the cluster ("cluster")
                              (Default: client).
  --class CLASS_NAME          Your application's main class (for Java / Scala apps).
  --name NAME                 A name of your application.
  --jars JARS                 Comma-separated list of jars to include on the driver
                              and executor classpaths.
  --packages                  Comma-separated list of maven coordinates of jars to include
                              on the driver and executor classpaths. Will search the local
                              maven repo, then maven central and any additional remote
                              repositories given by --repositories. The format for the
                              coordinates should be groupId:artifactId:version.
  --exclude-packages          Comma-separated list of groupId:artifactId, to exclude while
                              resolving the dependencies provided in --packages to avoid
                              dependency conflicts.
  --repositories              Comma-separated list of additional remote repositories to
                              search for the maven coordinates given with --packages.
  --py-files PY_FILES         Comma-separated list of .zip, .egg, or .py files to place
                              on the PYTHONPATH for Python apps.
  --files FILES               Comma-separated list of files to be placed in the working
                              directory of each executor. File paths of these files
                              in executors can be accessed via SparkFiles.get(fileName).
  --conf PROP=VALUE           Arbitrary Spark configuration property.
  --properties-file FILE      Path to a file from which to load extra properties. If not
                              specified, this will look for conf/spark-defaults.conf.
  --driver-memory MEM         Memory for driver (e.g. 1000M, 2G) (Default: 1024M).
  --driver-java-options       Extra Java options to pass to the driver.
  --driver-library-path       Extra library path entries to pass to the driver.
  --driver-class-path         Extra class path entries to pass to the driver. Note that
                              jars added with --jars are automatically included in the
                              classpath.
  --executor-memory MEM       Memory per executor (e.g. 1000M, 2G) (Default: 1G).
  --proxy-user NAME           User to impersonate when submitting the application.
                              This argument does not work with --principal / --keytab.
  --help, -h                  Show this help message and exit.
  --verbose, -v               Print additional debug output.
  --version,                  Print the version of current Spark.
 Cluster deploy mode only:
  --driver-cores NUM          Number of cores used by the driver, only in cluster mode
                              (Default: 1).
 Spark standalone or Mesos with cluster deploy mode only:
  --supervise                 If given, restarts the driver on failure.
  --kill SUBMISSION_ID        If given, kills the driver specified.
  --status SUBMISSION_ID      If given, requests the status of the driver specified.
 Spark standalone and Mesos only:
  --total-executor-cores NUM  Total cores for all executors.
 Spark standalone and YARN only:
  --executor-cores NUM        Number of cores per executor. (Default: 1 in YARN mode,
                              or all available cores on the worker in standalone mode)
 YARN-only:
  --queue QUEUE_NAME          The YARN queue to submit to (Default: "default").
  --num-executors NUM         Number of executors to launch (Default: 2).
                              If dynamic allocation is enabled, the initial number of
                              executors will be at least NUM.
  --archives ARCHIVES         Comma separated list of archives to be extracted into the
                              working directory of each executor.
  --principal PRINCIPAL       Principal to be used to login to KDC, while running on
                              secure HDFS.
  --keytab KEYTAB             The full path to the file that contains the keytab for the
                              principal specified above. This keytab will be copied to
                              the node running the Application Master via the Secure
                              Distributed Cache, for renewing the login tickets and the
                              delegation tokens periodically.

相關意義如下:

參數名 參數說明
–master master 的地址,提交任務到哪裏執行,例如 spark://host:port, yarn, local
–deploy-mode 在本地 (client) 啓動 driver 或在 cluster 上啓動,默認是 client
–class 應用程序的主類,僅針對 java 或 scala 應用
–name 應用程序的名稱
–jars 用逗號分隔的本地 jar 包,設置後,這些 jar 將包含在 driver 和 executor 的 classpath 下
–packages 包含在driver 和executor 的 classpath 中的 jar 的 maven 座標
–exclude-packages 爲了避免衝突 而指定不包含的 package
–repositories 遠程 repository
–conf PROP=VALUE 指定 spark 配置屬性的值,例如 -conf spark.executor.extraJavaOptions="-XX:MaxPermSize=256m"
–properties-file 加載的配置文件,默認爲 conf/spark-defaults.conf
–driver-memory Driver內存,默認 1G
–driver-java-options 傳給 driver 的額外的 Java 選項
–driver-library-path 傳給 driver 的額外的庫路徑
–driver-class-path 傳給 driver 的額外的類路徑
–driver-cores Driver 的核數,默認是1。在 yarn 或者 standalone 下使用
–executor-memory 每個 executor 的內存,默認是1G
–total-executor-cores 所有 executor 總共的核數。僅僅在 mesos 或者 standalone 下使用
–num-executors 啓動的 executor 數量。默認爲2。在 yarn 下使用
–executor-core 每個 executor 的核數。在yarn或者standalone下使用

示例:
Run on a Spark standalone cluster in client deploy mode(standalone client模式)

./bin/spark-submit \

  --class org.apache.spark.examples.SparkPi \

  --master spark://207.184.161.138:7077 \

  --executor-memory 20G \

  --total-executor-cores 100 \

  /path/to/examples.jar \

  1000

Run on a YARN cluster(YARN cluster模式)

export HADOOP_CONF_DIR=XXX

./bin/spark-submit \

  --class org.apache.spark.examples.SparkPi \

  --master yarn \

  --deploy-mode cluster \  # can be client for client mode

  --executor-memory 20G \

  --num-executors 50 \

  /path/to/examples.jar \

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