Zeppelin,于2016-5-18日从Apache孵化器项目毕业成为Apache*项目,采用Java(主要)+Scala+R+PythonR+Bash+JS混合开发,采用maven作为build工具。涉及的主要技术stack如下:
1) 前台:AngularJS、Node.JS、WebSocket、Grunt、Bower、Highlight.js、BootStrap3js
2) 后台:Jetty(embedding)、Thrift、Shiro(权限)、Apache common-exec、Jersey REST API。
具体技术占比:
zeppelin本质上是一个web应用程序,它以独立的jvm进程的方式来启动Interpreter(解释器),交互式(repl)执行各种语言的代码片段,并将结果以html代码片段的形式返回给前端UI。
1 Zeppelin的编译
编译环境:Oracle JDK7.x、maven3.x+、Node.js(npm)
Git源码地址:https://github.com/apache/zeppelin.git(注意不要再从如下旧的git地址更新了https://github.com/apache/incubator-zeppelin.git)
以下将${ZEPPELIN_HOME}指代git clone之后源码的根目录。使用如下maven命令编译并生成zeppelin的发布包:
mvn install -Pbuild-distr -Pspark-1.6 -Dspark.version=1.6.2 -Phadoop-2.7 -Dhadoop.version=2.7.2 [-Pr|-Psparkr] -Ppyspark -Dmaven.findbugs.enable=false -Drat.skip=true -Dcheckstyle.skip=true -Denforcer.skip=true -Dcobertura.skip=true -DskipTests -X
解释:
1) 执行install是为了将artifact安装到maven本地仓库,便于之后import到IDE进行调试。
2) -Pbuild-distr,表示启用build-distr这个maven profile是为了在zeppelin-distribution这个module中生成可分发包。
3) [-Pr|-Psparkr]需要注意,表示这2个profile只能启用一个,这2个profile编译出来的Interpreter会bind到相同的名字%r,造成冲突(参见zeppelin的mailinglist)。–Pr,表示启用r这个mavenprofile,会将${ZEPPELIN_HOME}/r作为一个module参与编译,编译完成得到sparkR Interpreter。运行zeppelin自带的R Tutorial这个Note,需要改Interpreter。-Pspark-1.6这个profile并不会使得sparkr这个Interpreter被编译打包,因为该Interpreter的编译在${ZEPPELIN_HOME}/zeppelin-spark/pom.xml中采用id=exclude-sparkr,activeByDefault=true的profile默认禁用掉了。如下:
常见错误解决:
如果在maven build过程中,出现enforcer、checkstyle、rat plugin相关的错误,可以分别使用这3个plugin的user property跳过该plguin的执行:-Denforcer.skip=true, -Dcheckstyle.skip=true 和-DskipRat=true
2 distribution结构分析
编译完成之后,会在zeppelin-distribution/target/目录下生成如下结构的分发包:
2.1 bin
bin目录存储了zeppelin的启停控制脚本:
各个脚本作用如下:
脚本 |
作用 |
zeppelin-daemon.sh |
提供以daemon形式启停 org.apache.zeppelin.server.ZeppelinServer 服务,并调用common.sh和function.sh设置env和classpath |
zeppelin.sh |
以foreground的形式启动ZeppelinServer |
Interpreter.sh |
采用单独进程启动 org.apache.zeppelin.interpreter.remote.RemoteInterpreterServer 服务,该脚本不会被其他脚本直接调用,实际是通过apache common-exec来调用的 |
common.sh |
设置zeppelin运行时需要的env和classpath,如果${ZEPPELIN_HOME}/conf/目录中存在zeppelin-env.sh,则会调用该脚本 |
function.sh |
一些公共基础函数 |
2.2 conf
配置文件 |
作用 |
shiro.ini |
供apache shiro框架使用的权限控制文件 |
zeppelin-env.sh |
供${ZEPPELIN_HOME}/bin/common.sh脚本调用,设置诸如:SPARK_HOME、HADOOP_CONF_DIR等zeppelin与外围环境集成的环境变量 |
zeppelin-site.xml.template |
zeppelin的配置模板,被注释掉的property是zeppelin的默认配置,可以rename成zeppelin-site.xml然后根据需要override |
2.3 interpreter
每个针对具体的某种语言实现的Interpreter,存放的是编译好的jar包,以及该interpreter的依赖,其中spark子目录的结构如下:
需要注意的是:如果定义了SPARK_HOME环境变量,该目录下的zeppelin-spark*.jar脚本将通过${SPARK_HOME}/bin/spark-submit到spark集群上去执行。
详情参见${ZEPPELIN_HOME}/bin/interpreter.sh脚本。
2.4 notebook
该目录是默认的notebook的持久化存储目录,zeppelin默认的notebook持久化实现类是org.apache.zeppelin.notebook.repo.VFSNotebookRepo,该实现会以zeppelin.notebook.dir配置参数指定的路径来存储notebook(默认是json格式)
<property>
<name>zeppelin.notebook.dir</name>
<value>notebook</value>
<description>path or URI for notebook persist</description>
</property>
由于该value指定的uri不带scheme,默认会在${ZEPPELIN_HOME}目录下创建notebook子目录用于存储各个notebook,以notebook的id为子目录名字。
3 zeppelin源码调试
1) 首先必须保证执行过mvn install,该命令保证所有的artifact均已安装到maven的本地仓库。
2) 以idea为例,安装maven和scala插件。然后import现有的maven的工程。
3) 新建Maven Debug Configuration,有2点需要注意:
a) working directory的设置必须到zeppelin-server,不能直接到zeppelin.git(我本机的${ZEPPELIN_HOME},zeppelin-server的上一级)。
b) 使用maven 的exec:javaplugin来执行,让maven管理classpath。
4) 打开org.apache.zeppelin.server.ZeppelinServer,在main之后设置断点即可启动调试。
4 源码结构分析
4.1 module组成
zeppelin的maven项目共有26个module,其中7个框架相关的module如下:
Module |
作用 |
开发语言 |
zeppelin-server |
项目的主入口,通过内嵌Jetty的方式提供Web UI和REST服务,并且提供了基本的权限验证服务 |
java |
zeppelin-zengine |
实现Notebook的持久化、检索 实现interpreter的自动加载,以及maven式的依赖自动加载 |
java |
zeppelin-interpreter |
为了支持多语言Notebook,抽象出了每种语言都要事先的Interpreter接口,包括:显示、调度、依赖以及和zeppelin-engine之间的Thirft通信协议 |
java |
zeppelin-web |
AngluarJS开发的web页面 |
Javascript(主要是AngularJS、Node.JS以及使用websocket) |
zeppelin-display |
实现向前台Angular元素绑定后台数据 |
scala |
zeppelin-spark-dependencies |
无具体功能,maven的最佳实践,将多个module都要依赖的公共类单独抽离出来,供其他module依赖。目前zeppelin-zinterpreter和zeppelin-spark这2个module依赖它 |
|
zeppelin-distribution |
为了将整个项目打包成发布版,而设置的module,打包格式见src/assembly/distribution.xml。 |
|
zeppelin的框架部分代码主要是以上几个module,余下19个module全部是为了支持各种语言的interpreter实现的module,如下:
Module |
作用 |
开发语言 |
zeppelin-spark |
实现Spark、PySpark、SparkR、SparkSql等Interpreter |
java+scala |
zeppelin-zinterpreter |
实现R Interpreter (PS:需要在${ZEPPELIN_HOME}/pom.xml中增加<module>r</module>) |
R+java+scala |
zeppelin-hive |
实现HiveQL Interpreter,需要hive client |
java |
zeppelin-hbase |
实现HBase Interpreter,需要hbase client,实际使用ruby脚本${HBASE_HOME}/bin/hirb.rb,来执行UI传入的脚本 |
java |
zeppelin-shell |
实现shell interpreter |
java |
zeppelin-file |
使用WebHDFS实现hdfs fs命令 |
java |
zeppelin-postgresql |
实现带自动补全功能的psql interpreter,使用jline实现自动补全 |
java |
zeppelin-jdbc |
实现通用的jdbc sql Interpreter |
java |
zeppelin-markdown |
实现MarkDown Interpreter |
java |
zeppelin-phoenix |
实现phoenixInterpreter |
java |
zeppelin-elasticsearch |
实现ES interpreter |
java |
zeppelin-canssandra |
实现canssandra Interpreter |
java+scala |
zeppelin-kylin |
实现支持kylin OLAP引擎的interpreter |
java |
zeppelin-angular |
实现支持angularJS引擎 |
java |
zeppelin-alluxio |
实现alluxio Interpreter,原tacyon |
java |
zeppelin-lens |
实现lens interpreter |
java |
zeppelin-ignite |
实现ignite Interpreter |
java |
zeppelin-flink |
实现flink interpreter |
java |
zeppelin-tajo |
实现tajo Interpreter |
java |
关于如何定制interpreter支持新语言,参见how to write a zeppelin interpreter。
4.2 module间依赖关系
Module之间的依赖关系如下: