Spark - 筆記 3

The architecture of a Spark Application

  • 不可變的分佈式的對象集合:只包含對象引用,實際對象在集羣的節點上。
  • 彈性、容錯。
  • Transformations:operations都是增加新的RDD,original增加後不再修改。
    RDD with 3 partitions using hdfs

默認地,RRD使用hash算法做分區。
分區數依賴節點數和數據大小。

Spark uses different workers to load different partitions

RDD Creation

  • Parallelizing a collection: splits成分區,跨集羣distributes分區
  • Reading data from an external source
  • Transformation of an existing RDD
  • Streaming API

Transformations

從已經存在的RDD,增加新的RDD。比如,splitting、filtering、排序。
可以按順序執行幾個transformations。
coalesce

Actions

Action triggers the entire DAG (Directed Acyclic Graph) of transformations。
To trigger the computation, we run an action.
action指示Spark計算一系列transformations的結果。

兩種類型:

  • Driver:比如collect count等
  • Distributed:比如saveAsTextfile。

Actions可以:

  • 在控制檯查看結果
  • 使用相應的語言,將數據收集成native objects
  • 把數據寫到數據源

reduce

flightData2015 = spark\
    .read\
    .option("inferSchema", "true")\
    .option("header", "true")\
    .csv("/data/flight-data/csv/2015-summary.csv")

flightData2015.sort("count").explain()
== Physical Plan ==
*Sort [count#195 ASC NULLS FIRST], true, 0
+- Exchange rangepartitioning(count#195 ASC NULLS FIRST, 200)
    +- *FileScan csv [DEST_COUNTRY_NAME#193,ORIGIN_COUNTRY_NAME#194,count#195] ...

Reading, sorting, and collecting a DataFrame

Shuffling

爲repartitioning,而移動數據叫shuffling。
how a Spark Job is split into stages

如果

spark.conf.set("spark.sql.shuffle.partitions", "5")
flightData2015.sort("count").take(2)

The process of logical and physical DataFrame manipulation

shuffling越多,影響性能的stages就越多。

Narrow Dependencies

簡單的一對一transformation,比如filter、map、flatMap等,子RDD是一對一依賴於父RDD的。
數據在相同節點(父所在的節點)轉換。不會跨executors傳輸。

Narrow dependencies are in the same stage of the job execution.

Wide Dependencies

repartition或者redistribute數據,比如aggregateByKey、reduceByKey。

Wide dependencies introduce new stages in the job execution.

Broadcast variables

Broadcast variables are shared variables across all executors.

driver只能廣播它擁有的數據,而不能廣播使用引用的RDDs。
how broadcast works

Accumulators

Accumulators是跨executors的共享變量。

Lazy Evaluation

直到最後,才執行graph of computation instructions。

  • register any DataFrame as a table or view (a temporary table)
  • 使用pure SQL查詢
  • 沒有性能差異 between writing SQL queries or writing DataFrame code
  • 都編譯成相同的底層計劃

比如:

sqlWay = spark.sql("""
    SELECT DEST_COUNTRY_NAME, count(1)
    FROM flight_data_2015
    GROUP BY DEST_COUNTRY_NAME
    """)
sqlWay.explain()

dataFrameWay = flightData2015\
    .groupBy("DEST_COUNTRY_NAME")\
    .count()
    
dataFrameWay.explain()

的執行計劃都是

*HashAggregate(keys=[DEST_COUNTRY_NAME#182], functions=[count(1)])
+- Exchange hashpartitioning(DEST_COUNTRY_NAME#182, 5)
    +- *HashAggregate(keys=[DEST_COUNTRY_NAME#182], functions=[partial_count(1)])
        +- *FileScan csv [DEST_COUNTRY_NAME#182] ...

對於

maxSql = spark.sql("""
SELECT DEST_COUNTRY_NAME, sum(count) as destination_total
FROM flight_data_2015
GROUP BY DEST_COUNTRY_NAME
ORDER BY sum(count) DESC
LIMIT 5
""")

maxSql.show()

如果使用DataFrame

flightData2015
    .groupBy("DEST_COUNTRY_NAME")
    .sum("count")
    .withColumnRenamed("sum(count)", "destination_total")
    .sort(desc("destination_total"))
    .limit(5)
    .show()

程序的邏輯是
The entire DataFrame transformation flow

執行計劃是

TakeOrderedAndProject(limit=5, orderBy=[destination_total#16194L DESC], outpu...
+- *HashAggregate(keys=[DEST_COUNTRY_NAME#7323], functions=[sum(count#7325L)])
    +- Exchange hashpartitioning(DEST_COUNTRY_NAME#7323, 5)
        +- *HashAggregate(keys=[DEST_COUNTRY_NAME#7323], functions=[partial_sum...
            +- InMemoryTableScan [DEST_COUNTRY_NAME#7323, count#7325L]
                +- InMemoryRelation [DEST_COUNTRY_NAME#7323, ORIGIN_COUNTRY_NA...
                    +- *Scan csv [DEST_COUNTRY_NAME#7578,ORIGIN_COUNTRY_NAME...

DataFrames Versus Datasets

Datasets的類型,在編譯時確定。
而DataFrames的類型,在運行時確定。

Datasets只在基於JVM的語言中有效。
大多數情況下,你可能更喜歡使用DataFrames。它相當於Row類型的Datasets。
“Row”類型是專門爲內存計算而優化的內部表達(Catalyst格式),和JVM類型相比,GC成本也低。

partitioning scheme定義存儲位置(物理分佈)。

Columns

  • 簡單類型,比如integer或者string
  • complex type,比如數組或者map
  • 可以是null

Schemas定義列的名字和類型。

Structured API Execution

  • 寫DataFrame/Dataset/SQL代碼
  • 如果代碼有效,轉換成Logical Plan
  • 轉換成Physical Plan,優化
  • 在集羣內執行Physical Plan
    The Catalyst Optimizer

Logical Planning

logical planning process

logical plan只包含transformations,沒有executors和drivers。
結果傳給Catalyst Optimizer。

Physical Planning

logical plan該如何執行。
會根據cost model比較不同策略。返回一系列RDDs and transformations。
The physical planning process

Execution

runs all of this code over RDDs。
會在運行時進一步優化。生成native Java bytecode。

StructType:

  • name
  • type
  • 是否可空
  • metadata(可選的)

Columns and Expressions

Columns提供表達式功能的子集。
邏輯樹,比如(((col(“someCol”) + 5) * 200) - 6) < col(“otherCol”)

DataFrame Transformations

Different kinds of transformations

How Spark Performs Joins

要先理解兩個概念:

  • node-to-node communication strategy
  • per node computation strategy

有兩種不同的通信方式,shuffle join(all-to-all communication)或者broadcast join。
隨着基於成本的優化器和通信策略的改進,這些內部優化會隨着時間推移而變化。

Big table–to–big table

使用shuffle join
Joining two big tables

每個節點(worker nodes)告訴其他所有節點,而且他們跨節點共享數據。
如果數據沒分區好,通信會很昂貴。

Big table–to–small table

當表足夠小,可以加載到單個worker node的內存中。會把每個小的DataFrame複製到每個worker node。
A broadcast join

SQL接口支持連接的hints(註釋語法)。不過,這不是強制的,優化器可能選擇忽略他們。
可選項包括MAPJOIN、BROADCAST和BROADCASTJOIN。

SELECT /*+ MAPJOIN(graduateProgram) */ * FROM person JOIN graduateProgram
    ON person.graduate_program = graduateProgram.id

如果broadcast太大的數據,driver node可能會crash。

Little table–to–little table

最好讓Spark決定怎樣連接他們。

Broadcast Variables

跨集羣共享,不可變,沒有封裝在閉包中。
一般來說,在閉包中,使用引用訪問對象。但是,對於大對象,worker nodes可能要反序列化對象很多次。
如果在多個actions和jobs中訪問相同的對象,每個job都會重新發送給workers。

而Broadcast variables會在每個machine共享,而不用每次發送。
Broadcast variables

Broadcast Variables在我們觸發action的時候,纔會被髮送。通過value方法訪問值。

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