一文弄懂PySpark原理與實踐

Spark基本架構和原理

見另一個博文:https://blog.csdn.net/oTengYue/article/details/88405479

一、PySpark 的背後原理

架構圖:
在這裏插入圖片描述
其中白色部分是新增的Python進程,在Driver端,通過Py4j實現在Python中調用Java的方法,即將用戶寫的PySpark程序”映射”到JVM中,例如,用戶在PySpark中實例化一個Python的SparkContext對象,最終會在JVM中實例化Scala的SparkContext對象;在Executor端,則不需要藉助Py4j,因爲Executor端運行的Task邏輯是由Driver發過來的,那是序列化後的字節碼,雖然裏面可能包含有用戶定義的Python函數或Lambda表達式,Py4j並不能實現在Java裏調用Python的方法,爲了能在Executor端運行用戶定義的Python函數或Lambda表達式,則需要爲每個Task單獨啓一個Python進程,通過socket通信方式將Python函數或Lambda表達式發給Python進程執行。語言層面的交互總體流程如下圖所示,實線表示方法調用,虛線表示結果返回。
在這裏插入圖片描述
參考:
PySpark 的背後原理:http://sharkdtu.com/posts/pyspark-internal.html

二、文檔

Spark基礎知識筆記見另一篇博文:https://blog.csdn.net/oTengYue/article/details/88405479
PySpark官方文檔:https://spark.apache.org/docs/latest/api/python/index.html
pyspark編程指南(英文):https://www.datacamp.com/community/tutorials/apache-spark-python#PySpark
備忘清單:https://s3.amazonaws.com/assets.datacamp.com/blog_assets/PySpark_Cheat_Sheet_Python.pdf
在這裏插入圖片描述

三、pyspark讀寫dataframe

pyspark系列–pyspark讀寫dataframe:https://zhuanlan.zhihu.com/p/34901558
pyspark:dataframe與rdd的一點小事:https://www.jianshu.com/p/5e593510313b

四、通過spark-submit提交任務模板示例

spark-submit提交方式官網:http://spark.apache.org/docs/latest/submitting-applications.html

spark-submit \
    --master yarn \
    --deploy-mode client \
    --num-executors 10 \
    --executor-memory 10g \
    --executor-cores 8 \
    --driver-memory 10g \
    --conf spark.pyspark.python=python2.7 \
    --conf spark.pyspark.driver.python=python2.7 \
    --py-files depend.zip \
    demo.py 2019-03-05

說明:
1、depend.zip是demo.py的依賴包,注:depend.zip不包含demo.py
2、demo.py中可以直接使用import depend.xx.xxfrom depend.xx.xx import xx類似語句引入依賴包
3、上述示例中的2019-03-05是傳給demo.py的參數
參考:
Pyspark spark-submit 集羣提交任務以及引入虛擬環境依賴包攻略:https://www.cnblogs.com/piperck/p/10121097.html

五、代碼示例

1、WordCount詞頻分析

wordcount.py

# -*- coding: utf-8 -*-
import sys
import os
import datetime
from pyspark import SparkConf,SparkContext
sc = SparkConf().setAppName("wordcount")
spark = SparkContext(conf=sc)
text_file = spark.textFile("hdfs://shw/pyspark")
word_cnt_rdd = text_file.flatMap(lambda line : line.split(' ')).map(lambda word : (word, 1)).reduceByKey(lambda x, y: x + y)
word_cnt_rdd.saveAsTextFile('hdfs://shw/wc') 

提交命令:
spark-submit --master yarn --deploy-mode client --num-executors 10 --executor-memory 10g --executor-cores 8 --driver-memory 10g --conf spark.pyspark.python=python2.7 wordcount.py

2、使用PySpark語言開發操作Hive

場景:
1、使用pySpark語言開發操作Hive。
注:使用spark.sql(sql)函數執行hive sql每次只能執行一條,需要執行多個sql請分多次調用,且sql語句最後不能包含分號。
2、使用spark-submit提交腳本。
拓展:如果需要一次提交執行多條sql的可以考慮使用spark-sql命令,(使用總結以後再補充吧)

hive_test.py

# -*- coding: utf-8 -*-
from pyspark import SparkConf
from pyspark.sql import SparkSession
import sys,traceback
from pyspark import StorageLevel
import datetime
import uuid
def process(spark,calc_date):
    sql = """ 
        CREATE EXTERNAL TABLE IF NOT EXISTS app.app_shw_test(
            id bigint COMMENT 'ID', 
            name string COMMENT '名稱'
        )
        COMMENT '測試表'
        PARTITIONED BY (dt string)
        STORED AS ORC
        LOCATION '/user/shw/app_shw_test'
        tblproperties ('orc.compress'='SNAPPY')
    """
    spark.sql(sql)
    sql = """ 
        select 
            id,
            name,
            '{calc_date}' dt
        from
            xx_test
        where 
            dt = '{calc_date}'
        group by 
            id,
            name
    """.format(calc_date = calc_date)
    df = spark.sql(sql)
    df.write.mode("append").insertInto('app_shw_test', overwrite=True)
def createSparkSession(appName):
    conf = SparkConf().setAppName(appName)
    conf.set("spark.rdd.compress", "true")
    conf.set("spark.broadcast.compress", "true")
    conf.set("hive.exec.dynamic.partition", "true")
    conf.set("hive.exec.dynamic.partition.mode", "nonstrict")
    conf.set("hive.exec.max.dynamic.partitions", "100000")
    conf.set("hive.exec.max.dynamic.partitions.pernode", "100000")
    conf.set("hive.auto.convert.join", "true")
    conf.set("mapred.max.split.size", "256000000") # 每個Map最大輸入大小
    conf.set("mapred.min.split.size.per.node", "100000000") # 一個節點上split的至少的大小
    conf.set("mapred.min.split.size.per.rack", "100000000") # 一個交換機下split的至少的大小
    conf.set("hive.input.format", "org.apache.hadoop.hive.ql.io.CombineHiveInputFormat") # 執行Map前進行小文件合併
    conf.set("hive.merge.mapfiles", "true") # 在Map-only的任務結束時合併小文件
    conf.set("hive.merge.mapredfiles", "true") # 在Map-Reduce的任務結束時合併小文件
    conf.set("hive.merge.size.per.task", "256*1000*1000") # 合併文件的大小
    conf.set("hive.merge.smallfiles.avgsize", "16000000") # 當輸出文件的平均大小小於該值時,啓動一個獨立的map-reduce任務進行文件merge
    conf.set("spark.sql.shuffle.partitions", "500") # 設置shuffle分區數
    conf.set("spark.driver.maxResultSize", "5g")
    conf.set("hive.merge.sparkfiles", "true")
    conf.set("spark.sql.hive.mergeFiles", "true")
    spark = SparkSession.builder.config(conf=conf).enableHiveSupport().getOrCreate()
    return spark
def main():
    calc_date = sys.argv[1]
    appName = "spark_hive_task-" + str(uuid.uuid1())
    spark = createSparkSession(appName=appName)
    try:
        process(spark,calc_date)
    except Exception as ex:
        traceback.print_exc()
    finally:
        spark.stop()
if __name__ == "__main__":
    main()

提交命令:
spark-submit --master yarn --deploy-mode client --num-executors 10 --executor-memory 10g --executor-cores 8 --driver-memory 10g --conf spark.pyspark.python=python2.7 hive_test.py 2019-03-11

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