pyspark实现:关于python的算法程序,如何做成分布式处理,并解决环境的冲突等问题的记录

 

 

背景:

一个切词、一个自然语言处理

原算法程序情况:

切词程序.py :每次读取数据,需要从数仓把数据文件拉取出来,然后手动导给算法同学处理 , 然后算法同学本地笔记本跑数据,得到切词数据

自然语言处理.py :  依赖上一个切词程序的结果数据,然后做情感分析。得到结果后,在手动导入数仓

 

问题:

1)、程序不自动化,每次都需要手动导入原始数据、并将结果手动导入数仓

2)、效率不高,因为不是分布式,程序执行效率非常低

3)、公司的调度平台是实体机,是不允许安装任何第三方python包的(因为要考虑兼容问题、新增机器没有这个依赖包等问题)

 

第一期解决方案:利用hadoop-streaming的方式将脚本自动化

首先介绍hadoop-streaming的格式:

1):官网链接 http://hadoop.apache.org/docs/r2.7.2/hadoop-streaming/HadoopStreaming.html

大概的格式:

hadoop jar hadoop-streaming-2.7.2.jar \
                -archives 'hdfs://hadoop-nn1.example.com/user/me/samples/cachefile/cachedir.jar' \
                -D mapreduce.job.maps=1 \
                -D mapreduce.job.reduces=1 \
                -D mapreduce.job.name="Experiment" \
                -input "/user/me/samples/cachefile/input.txt" \
                -output "/user/me/samples/cachefile/out" \
                -mapper "xargs cat" \
                -reducer "cat"
-archives:就是一些大的包(可以是文件包、可以是jar),提前上传到HDFS,然后通过这个archives指定,hadoop会帮你自动加载并解压
通过yarn的日志也能够观察到,hadoop会自动下载archives指定的文件,并解压:
比如:

 

 ps. 我上面放的是spark的日志,但其实和mr一样的日志情况

-input 和 -output 就是正常数据的输入和输出

-mapper和-reduce 就是mr的两阶段处理数据过程

2):解决调度平台不让安装任何第三方依赖包,但脚本还要在调度平台执行的问题

网上有很多种方案,我选择的是虚拟环境:https://docs.python.org/zh-cn/3/library/venv.html

但是值得注意的是:一定要在【同环境】下来创建虚拟环境。

比如:一般公司的内部执行机器,是不允许连接外网的。但是做虚拟环境,还必须要上网下载东西;

那么一定要在可以上网的同环境(Linux)去下载好虚拟环境需要的依赖包,然后将虚拟环境压缩好,导入到HDFS(我当时就因为在mac上做虚拟环境,导入到HDFS上,发现怎么用都不对)

这样技术选型是hadoop-streaming。采用虚拟环境准备好,然后开始使用脚本:

 

hadoop jar /usr/XXX/3.1.4.0-315/hadoop-mapreduce/hadoop-streaming-3.1.1.3.1.4.0-315.jar \
     -D mapreduce.job.reduces=1 \
     -D stream.non.zero.exit.is.failure=true \
     -archives "hdfs://bdp/XXX/dms/nlp/venv.tar.gz#venv" \
     -input "/user/XXX/tmp_nlp3/2021-08-15/part-00000" \
     -output "/user/XXX/tmp_nlp3/908" \
     -mapper "cat" \
     -reducer 'venv/venv/bin/python ./sentiment_predict_dist.py' \
     -file ./sentiment_predict_dist.py \
     -file ./albert_config.json \
     -file ./model.ckpt-best.data-00000-of-00001 \
     -file ./vocab_chinese.txt \
     -file ./model.ckpt-best.index \
     -file ./model.ckpt-best.meta \
     -file ./key_sentence_202103.txt \
     -file ./inverse.txt \
     -file ./negative_regex.txt \
     -file ./negative.txt \
     -file ./positive_regex.txt \
     -file ./positive.txt \
     -file ./very.txt \
     -file ./words_add.txt \
     -file ./words_del.txt \
     -file ./best_model.weights

 

注意:-archives指定了虚拟环的压缩包,并且后面有个#,这个是软连接,

比如:-archives "hdfs://bdp/XXX/dms/nlp/venv.tar.gz#venv"

hadoop会将venv.tar.gz这个包下载下来,并解压; 因为添加了#venv 所以解压后的路径实际是:venv/venv/....

比如我要使用python3 ,那么解压后的路径是:venv/venv/bin/python3

 

以上方式虽然解决了python的nlp脚本能够跑在调度平台的问题了。但是还有两个非常严重的问题:

1、因为采用的是hadoop-streaming 也就是mr的方式,所以效率极其差!

细心的同学可以发现,我的执行脚本有个:-mapper "cat" 

这是因为python版本的hadoop-streaming在接收数据这里,要采用 sys.stdin 这样的方式来接收数据,也就是一条一条处理,3万条文本数据,居然花费了1.2小时才处理完

 

2、因为采用的是hadoop-streaming方式,采用的是-input 去读取文件,这样会导致,如果数仓的表是多分区的、多分桶的,甚至多个小文件的情况;

那么此时这个hadoop-streaming就非常不适用了。因为你要反复的更改-input路径,才能把一张表完全跑完。而且你想3万条数据就耗费1.2小时。如果是多分区多分桶的大表。时间上会慢的怀疑人生

 

第二期解决方案:利用pyspark+虚拟环境

采用pyspark的初衷就是为了解决上面的问题,同时还能加大处理并行度、更好的shuffle处理等优势

1)、虚拟环境跟上面讲的操作是一样的

2)、代码改成pyspark模式

pyspark需要注意的是,在处理UDAF和UDTF的支持并不友好,你甚至发现其实pyspark压根不支持,所以要想很多弯道超车的方案,比如(先把字段合并,在拆分等,按照UDF的方式来处理UDTF和UDAF)

然后脚本大概是:

 spark-submit \
 --deploy-mode cluster \
 --master yarn \
 --driver-memory 5g \
 --num-executors 20 \
 --executor-memory 4g \
 --executor-cores 10 \
 --name nlp \
 --archives hdfs://bdp/user/dms/nlp/venv.tar.gz#venv \
 --conf spark.pyspark.driver.python=./venv/venv/bin/python3 \
 --conf spark.pyspark.python=./venv/venv/bin/python3 \
 --files 需要的文件

这样使用pyspark,让程序得以优化:

1、可以直接读写数仓的表了

2、代码更加可维护了,因为是sql,非常方便

3、性能提升了至少10倍,原来需要1.2小时,现在只需要9分钟

 

posted @ 2021-08-24 11:38  niutao  阅读(995)  评论(0编辑  收藏  举报