Spark集群配置(4):其他填坑杂项

前言

本文是《Spark集群配置》的第四篇。主要讲解使用Spark集群时的一些小坑。其他的几篇传送门:

. Spark集群配置(1):基础配置
. Spark集群配置(2):安装Hadoop
. Spark集群配置(3):安装Spark

hadoop native lib 问题

在使用Hadoop和Spark时,有时候会出现这样一条警告:

1
WARN org.apache.hadoop.util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-Java classes where applicable.

原因是你安装的Hadoop编译位数和你的系统位数不一致(准确的说是和JDK位数不一致)。因为官方发布的Hadoop版本都是在32位的机器上编译的,因此如果你的机器是64位就会出现这个警告。但是如果你是32位的系统,则不会出现这个警告。
如果你使用Spark的功能很简单,又不在乎这个警告,可以不用管它。不会影响基础功能的使用。
如果想解决这个问题,就需要自己亲自编译响应版本的Hadoop源码。但是需要指出的是,Linux上编译软件很复杂,因此你很可能在编译时遇到各种各样奇怪的问题。因此希望你能够做足准备后才编译。即使一路顺畅一般编译也需要几个小时(视电脑配置而定)。

我是在64位系统上安装的hadoop-2.7.3.tar.gz。因此自己将代码编译了一遍。自己编译的结果和官方发布的差别只在于hadoop/lib/native这个文件夹。因此如果你使用的是hadoop-2.7.3.tar.gz,则可以直接在这里下载native.zip,然后在所有机器上按照下面的命令来将其替换到官方包中。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ unzip native.zip
# 删除自带的native文件夹
$ rm -rf /usr/hadoop/lib/native/
# 并将我们的native文件夹复制替换到/usr/hadoop/lib/中
$ mv native/ /usr/hadoop/lib/
# 为libhadoop.so.1.0.0文件创建一个软连接libhadoop.so
$ ln -s /usr/hadoop/lib/native/libhadoop.so.1.0.0 /usr/hadoop/lib/native/libhadoop.so
# 为libhdfs.so.0.0.0文件创建一个软连接libhdfs.so
$ ln -s /usr/hadoop/lib/native/libhdfs.so.0.0.0 /usr/hadoop/lib/native/libhdfs.so

然后在环境变量(/etc/profile)中添加:

1
2
3
4
# 指明我们要使用的Native包的位置
export HADOOP_COMMON_LIB_NATIVE_DIR="$HADOOP_HOME/lib/native"
export JAVA_LIBRARY_PATH="$HADOOP_HOME/lib/native"

接着再在spark/conf/spark-env.sh中添加下面的内容就完成了配置。

1
export LD_LIBRARY_PATH=${JAVA_LIBRARY_PATH}

安装findspark

有的时候,我们需要在Jupyter中加载spark的Kernel。如果单纯的通过设置Jupyter将会异常的复杂。反正我中途放弃了。
偶然的一次机会,我在stackoverflow发现了一个简单的取巧的办法,就是安装一个Python第三方包findspark

1
$ pip install findspark

然后在python中执行以下命令:

1
2
3
4
5
import findspark
findspark.init()
import pyspark
sc = pyspark.SparkContext(appName="myAppName")

开始愉快的在Jupyter中加载本机配置好的Spark环境了。

PYTHONHASHSEED问题

如果你使用的是Python3+,并且在Spark集群上使用distinct()reduceByKey(),和join()这几个函数时,就会触发下面的异常:

1
Exception: Randomness of hash of string should be disabled via PYTHONHASHSEED

原因大致意思是说,python创建遍历对象对象时会对每个对象进行随机哈希创建索引。然而在一个集群上,每个节点计算时对某一个变量创建的索引值不同,会导致数据索引冲突。因此需要设置PYTHONHASHSEED来固定随机种子,保证索引一致。我说的不一定对,这里有个详细的解释:《Python 3 on Spark - Return of the PYTHONHASHSEED》

上面的文章里给的方法是直接修改环境变量,很方便,但是会使得以后运行Python时其哈希索引的随机种子都固定了,感觉不好。因此推荐下面的方法:

修改一个spark的配置文件:spark/conf/spark-defaults.conf,这个文件是由源文件spark-defaults.conf.template生成的,复制并重命名:

1
$ cp /usr/spark/conf/spark-defaults.conf.template /usr/spark/conf/spark-defaults.conf

spark-defaults.conf中添加以下内容就OK了

1
2
# 注意:这里必须是0,不可以是其他值
spark.executorEnv.PYTHONHASHSEED=0

好了,这个系列到这里就结束了,讲的还是很基础的配置,很多常见的用法还没说到,如果以后有机会就在写点其他的吧。感谢你的阅读。