PySpark实际应用踩坑

PySpark踩坑记录

PySpark是Apache Spark支持python编写的工具,python简单实用,使用python操作spark做简单的数据分析处理也是一种选择。Cassandra是分布式NoSQL数据库系统,可以简单理解它和HBase和MongoDB类似。本文主要分享PySpark实际应用和通过PySpark操作Cassandra遇到的坑。

1. spark cassandra connector

首先,pyspark连接Cassandra的两种方法。

(1)一种是datastax connector,通用于各种语言,根据spark、cassandra版本选择connector版本,参考链接:
[https://github.com/datastax/spark-cassandra-connector]

pyspark添加connector,可以在提交任务中添加:

./bin/pyspark --packages com.datastax.spark:spark-cassandra-connector_2.11:2.4.2

也可以在python脚本中添加:

os.environ["PYSPARK_SUBMIT_ARGS"] = '--packages com.datastax.spark:spark-cassandra-connector_2.11:2.4.2

(2)另一种是适合pyspark的connector
[https://github.com/anguenot/pyspark-cassandra]

./bin/pyspark --packages anguenot/pyspark-cassandra:2.4.0

这一种方式支持rdd写入Cassandra,读取Cassandra表为rdd格式,前一种connector只支持pyspark的dataframe格式。

第二个connector的文档中的例子,比如:

import pyspark_cassandra

conf = SparkConf() \
	.setAppName("PySpark Cassandra Test") \
	.setMaster("spark://spark-master:7077") \
	.set("spark.cassandra.connection.host", "cas-1")

sc = CassandraSparkContext(conf=conf)

pyspark_cassandra不是直接安装在python的包,而是在–packages中的。所以,写代码时会报错,说找不到包,不过提交时不会有问题。

2. 配置spark master和worker节点的python环境

Python版本问题首先是一个坑
如果写代码用的python3,但是master和worker上默认python2,此时会报python运行的错误。对于用java和scala,spark-submit上传打好的jar包即可提交执行,因为driver和executor都是以JVM为载体来运行和执行任务。而对于PySpark,Spark是在外围包装一层Python API,借助Py4j实现Python和Java的交互。

因此,如果提交的脚本python版本是3,需要在master和worker节点安装python3,并在python脚本中配置节点的python路径:

os.environ["PYSPARK_PYTHON"] = '/bin/python3'
os.environ["PYSPARK_DRIVER_PYTHON"] = '/bin/python3'

此处的python路径,是master和worker节点的python路径,与上传spark任务的机器中的python路径无关。

3. PySpark操作Cassandra

(1)第一种是应用sparksql中的sparksession对象,创建spark dataset或spark dataframe。

样例如下:

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName(sys.argv[0])\
    .config("spark.cassandra.connection.host", "cassandra_host_ip").getOrCreate()
# 加载Cassandra数据到dataframe
df = spark.read.format("org.apache.spark.sql.cassandra")\
    .options(table="table_name", keyspace="keyspace_name").load()
# UDF
from pyspark.sql.functions import udf
class UdfSample(object):
 ......
udf1 = udf(lambda z: UdfSample(z)......, StringType())
# dataframe写入Cassandra
df.write.format("org.apache.spark.sql.cassandra")\
    .options(table="table_name ", keyspace="keyspace_name")\
    .mode('append').save()

Dataframe中特别多的会应用udf和lambda。对于自定义udf,序列化、反序列化、及通信IO性能损耗比较明显,而Spark sql中内置的udf会降低数据在executor jvm和python worker之间序列化反序列化、通信等损耗。
spark dataframe和pandas dataframe是两种不同的数据格式,虽然有方法实现两者相互转化,但是实用性不大,且浪费资源。
(2)第二种是spark rdd的方式
文档中没有给出定义列名的rdd的写入Cassandra表的方式,可以参考下面的例子:

rdd.saveToCassandra("keyspace", "table_name", columns=["column_1", "column_2", "column_3"])

4. crontab定时任务无法执行

使用spark-submit提交python脚本到spark集群,例如

./bin/spark-submit  --master spark://ip:port  ./python1.py

同样的命令手动输入运行没问题,但是在crontab上无法执行。

问题本质和crontab无关,这也是python环境的问题。如果在python脚本中加入打印sys.path的代码,会发现手动执行和crontab执行的sys.path中python路径不同。简单直接的方法是在提交命令中加入本地的python运行路径。

./bin/spark-submit 
--master spark://ip:port 
--conf spark.pyspark.python=/bin/python 
--conf spark.pyspark.driver.python=/bin/python 
./python1.py

5. pyspark依赖打包

对于较大的项目,会有多个文件互相依赖,需要把整个项目打包并提交spark任务。
打包过程:
使用zip命令,需要注意一点是zip会把路径也打包进去,所以打包前要进入项目路径。
zip -r /data/xxx/pyzip/sample.zip ./
然后提交spark任务时,引用打包好的项目
–py-files=’/data/xxx/pyzip/sample.zip’
注意:
如果任务中使用到的依赖脚本中,import的包在worker中没有,会报错。如果提交脚本的import的包在worker中没有,并且在spark过程中调用,也会报错,因为worker不认识。

总体来说

对于简单离线任务,可以使用PySpark快速部署提交,简单方便。但在大数据情景中,JVM和Python进程间频繁通信会导致性能损耗,尽量慎用PySpark。后续实际中遇到问题,也会继续补充。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值