[Zeppelin] 如何配置、使用和调试local模式的Spark解释器

背景

之前我们分别安装过Zeppelin和Spark,在本文和下一篇文章里我们学习如何通过Zeppelin来使用Spark解释器,这篇文章介绍local模式,下一篇文章介绍启用了Kerberos认证的on Yarn模式,这篇文章介绍local模式,但local模式的很多配置和问题在其它模式都可能遇到,所以即使使用其它模式的Spark,也可以参考本文。

注意:本文是在Zeppelin和Spark都已经安装好的基础上进行的,如果还没有安装,请查看往期文章:
如何安装启动Zeppelin
如何安装Spark和使用spark-shell

配置Spark解释器

  1. 修改Zeppelin的配置文件,在Zeppelin的目录下编辑 conf/zeppelin-env.sh

    export SPARK_HOME=/Users/iamabug/spark-2.4.4-bin-hadoop2.7
    # 将SPARK_HOME环境变量设置为Spark的安装目录,根据实际路径修改
    

    修改后保存,然后重启Zeppelin:

    bin/zeppelin-daemon.sh restart
    

    注意(如果仅仅是学习体验Zeppelin可以忽略这一段):章剑锋Jeff在文章:如何在Apache Zeppelin中玩转Spark (1)中给出了三种配置Spark解释器的方法,其它两种都比修改 zeppelin-env.sh 这种灵活,所以不建议用这种方式来配置Spark,这种观点当然是对的,但凡事都需要tradeoff,在很多实际情况中,维护配置Zeppelin和Spark的人员和真正使用Zeppelin和Spark的人员不是同一拨人,即一拨人提供Zeppelin给另外一拨人用,这种情况下使用方不了解也不关心配置细节,只要有的用就好,所以在业务初期阶段,提供一个固定的统一的Spark解释器配置也不失为一种选择,毕竟不灵活的好处是复杂度低,维护成本也低,可以等到使用方有更个性化的需求时再进行分别定制也不迟,有这个需求的同学请参考Jeff的文章进行配置。

  2. 重启后,在浏览器中打开Zeppelin的页面,我的地址是 http://localhost:8181,点击右上角的 anonymous ,会出现一个下拉菜单:

    [Zeppelin] 如何配置、使用和调试local模式的Spark解释器_第1张图片
    image

    选择 Interpreter,在新页面的搜索框输入 spark

    [Zeppelin] 如何配置、使用和调试local模式的Spark解释器_第2张图片
    image

    点击 edit 按钮,可以对Zeppelin中运行的Spark解释器进行配置,比如将 master 的默认值 local[*] 改为 local[2](*表示使用所有可用的CPU,2表示只使用两个核),然后点击左下角的 Save 按钮,然后在弹出的确认重启对话框中点击 OK,重启完毕后回到主页,下面来创建一个Zeppelin的Notebook使用我们刚才配置的Spark解释器。

使用Spark解释器

  1. 在主页上点击 Create new note,并在弹出的对话框中输入Notebook的名字,Default Interpreter 不用修改,然后点击 Create

    [Zeppelin] 如何配置、使用和调试local模式的Spark解释器_第3张图片
    image
  2. 之后会出现一个新的页面用来写代码,效果和 spark-shell 很像,只不过每行代码前需要 %spark%spark.pyspark 这样的标记,表示这行代码是scala还是python,spark解释器总共支持五种子解释器:

    • %spark
    • %spark.pyspark
    • %spark.r
    • %spark.sql
    • %spark.dep

    下面用 %spark.pyspark 写几行代码试试:

%spark.pyspark
arr = [1, 2, 3, 4, 5]
# 这里sc是Zeppelin替我们初始化好的SparkContext对象
r = sc.parallelize(arr)

​ 然后点击代码右侧的运行按钮或者使用快捷键 Shift + Enter 运行这两行代码,结果报错了:

java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator.defaultNumHeapArena()I
    at org.apache.spark.network.util.NettyUtils.createPooledByteBufAllocator(NettyUtils.java:113)
    at org.apache.spark.network.client.TransportClientFactory.(TransportClientFactory.java:106)
    at org.apache.spark.network.TransportContext.createClientFactory(TransportContext.java:99)
    at org.apache.spark.rpc.netty.NettyRpcEnv.(NettyRpcEnv.scala:71)
    at org.apache.spark.rpc.netty.NettyRpcEnvFactory.create(NettyRpcEnv.scala:461)
    at org.apache.spark.rpc.RpcEnv$.create(RpcEnv.scala:57)
    at org.apache.spark.SparkEnv$.create(SparkEnv.scala:249)
    at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:175)
    at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:257)
    at org.apache.spark.SparkContext.(SparkContext.scala:424)
    at org.apache.spark.SparkContext$.getOrCreate(SparkContext.scala:2520)
    at org.apache.spark.sql.SparkSession$Builder$$anonfun$7.apply(SparkSession.scala:935)
    at org.apache.spark.sql.SparkSession$Builder$$anonfun$7.apply(SparkSession.scala:926)
    at scala.Option.getOrElse(Option.scala:121)
    at org.apache.spark.sql.SparkSession$Builder.getOrCreate(SparkSession.scala:926)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.zeppelin.spark.BaseSparkScalaInterpreter.spark2CreateContext(BaseSparkScalaInterpreter.scala:263)
    at org.apache.zeppelin.spark.BaseSparkScalaInterpreter.createSparkContext(BaseSparkScalaInterpreter.scala:182)
    at org.apache.zeppelin.spark.SparkScala211Interpreter.open(SparkScala211Interpreter.scala:90)
    at org.apache.zeppelin.spark.NewSparkInterpreter.open(NewSparkInterpreter.java:102)
    at org.apache.zeppelin.spark.SparkInterpreter.open(SparkInterpreter.java:62)
    at org.apache.zeppelin.interpreter.LazyOpenInterpreter.open(LazyOpenInterpreter.java:69)
    at org.apache.zeppelin.interpreter.remote.RemoteInterpreterServer$InterpretJob.jobRun(RemoteInterpreterServer.java:616)
    at org.apache.zeppelin.scheduler.Job.run(Job.java:188)
    at org.apache.zeppelin.scheduler.FIFOScheduler$1.run(FIFOScheduler.java:140)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

TroubleShooting

netty包版本冲突

针对上面的问题,在谷歌中搜索”Zeppelin java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator.defaultNumHeapArena()“,第一个答案是 https://stackoverflow.com/questions/50388919/spark-2-3-java-lang-nosuchmethoderror-io-netty-buffer-pooledbytebufallocator-me,其它的答案也给出了相同的解决方法:用Spark的netty包替换Zeppelin的netty包,先查看一下Spark和Zeppelin各自Netty包的版本:

# 在SPARK安装目录下执行
$ ls jars | grep netty
netty-3.9.9.Final.jar
netty-all-4.1.17.Final.jar
# 在Zeppelin安装目录执行
$ ls lib | grep netty
netty-all-4.0.23.Final.jar

可以看到Spark的netty-all包版本是 4.1.17,Zeppelin是 4.0.23,进行替换:

# 在Zeppelin安装目录执行
$ rm lib/netty-all-4.0.23.Final.jar
$ cp ~/spark-2.4.4-bin-hadoop2.7/jars/netty-all-4.1.17.Final.jar lib/

然后点击Notebook页面右上角的齿轮按钮:

image

在弹出的菜单中,点击spark前面的重启按钮:

image

在弹出的确认重启对话框中点击 OK,重启完成后点击 Save,再重启执行最初的两行代码。

注意:重启spark解释器这个方法在很多时候会用到,比如更改配置、Spark任务异常等等,因为不需要重启整个Zeppelin,所以较为方便。

果然,不报netty包的错了,换了一个新的错:

 Traceback (most recent call last):
  File "/var/folders/44/m0s6g_9j2rb51525lwdry8gr0000gn/T/zeppelin_pyspark-5784757143185993706.py", line 20, in 
    from py4j.java_gateway import java_import, JavaGateway, GatewayClient
zipimport.ZipImportError: can't decompress data; zlib not available

zlib库不可用

在谷歌里搜索“zipimport.ZipImportError: can't decompress data; zlib not available”,原因似乎是编译python的时候没有将包含zlib,因此需要安装zlib后并重新编译python,这个作为一个备选方案,因为我的系统里同时装了python2和python3,所以我先按照前文修改 master 的方式修改了spark解释器的 zeppelin.pyspark.python,将它改为了 python3,重启解释器后再运行代码,发现错误又变了:

Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.readRDDFromFile.
: java.lang.ExceptionInInitializerError
    at org.apache.spark.SparkContext.withScope(SparkContext.scala:699)
    at org.apache.spark.SparkContext.parallelize(SparkContext.scala:716)
    at org.apache.spark.api.python.PythonRDD$.readRDDFromInputStream(PythonRDD.scala:195)
    at org.apache.spark.api.python.PythonRDD$.readRDDFromFile(PythonRDD.scala:175)
    at org.apache.spark.api.python.PythonRDD.readRDDFromFile(PythonRDD.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
    at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
    at py4j.Gateway.invoke(Gateway.java:282)
    at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
    at py4j.commands.CallCommand.execute(CallCommand.java:79)
    at py4j.GatewayConnection.run(GatewayConnection.java:238)
    at java.lang.Thread.run(Thread.java:748)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Incompatible Jackson version: 2.8.11-1
    at com.fasterxml.jackson.module.scala.JacksonModule$class.setupModule(JacksonModule.scala:64)
    at com.fasterxml.jackson.module.scala.DefaultScalaModule.setupModule(DefaultScalaModule.scala:19)
    at com.fasterxml.jackson.databind.ObjectMapper.registerModule(ObjectMapper.java:747)
    at org.apache.spark.rdd.RDDOperationScope$.(RDDOperationScope.scala:82)
    at org.apache.spark.rdd.RDDOperationScope$.(RDDOperationScope.scala)
    ... 16 more

所以下面解决这个错误,不过注意,如果替换为python3之后仍然有 zlib 错误的话,可能是需要重新编译或安装包含 zlib 库的python版本。

jackson-databind包版本冲突

上面的报错提示的很清晰,版本不兼容,和之前一样,查看一下Spark和Zeppelin各自的jackson包版本:

# 在SPARK安装目录下执行
$ ls jars | grep jackson-databind
jackson-databind-2.6.7.1.jar
# 在Zeppelin安装目录执行
$ ls lib | grep jackson
jackson-databind-2.8.11.1.jar

果然版本不同,和之前一样,用Spark的包替换Zeppelin的:

# 在Zeppelin安装目录执行
$ rm lib/jackson-databind-2.8.11.1.jar
$ cp ~/spark-2.4.4-bin-hadoop2.7/jars/netty-all-4.1.17.Final.jar lib/

重启解释器,终于没有报错:

image

总结

这篇文章里我们学习如何在Zeppelin中配置Spark解释器,并在尝试使用Spark解释器的过程中解决了一下问题,得到的经验有:

  • 有些Spark的配置在后台的配置文件和浏览器页面中都可以配置,根据对灵活性的需求进行选择;
  • Zeppelin和Spark经常有JAR包版本不一致的问题,用Spark的JAR包替换Zeppelin的JAR包可以解决,但不确定是否合理,以及有没有更好的解决方式;
  • 重启解释器在Zeppelin中是很常用的操作;

欢迎交流讨论,吐槽建议。

勤学似春起之苗,不见其增,日有所长
辍学如磨刀之石,不见其损,日有所亏
关注【大数据学徒】,用技术干货助你日有所长
PS:每鸽一天发100元红包,进群可致富

[Zeppelin] 如何配置、使用和调试local模式的Spark解释器_第4张图片
大数据学徒

你可能感兴趣的:([Zeppelin] 如何配置、使用和调试local模式的Spark解释器)