sparkR在spark2.0里面,RDD后端代码位于org.apache.spark.rdd中,R语言相关的位于org.apache.spark.api.r中。

从入口开始,./bin/sparkR里面只有四句话,调用的是这个

exec "$SPARK_HOME"/bin/spark-submit sparkr-shell-main "$@"

spark-submit里面是个一句话的shell脚本

exec "$SPARK_HOME"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"

好了,入口是org.apache.spark.deploy.SparkSubmit这个类,该类中的main方法中调用具体方法

case SparkSubmitAction.SUBMIT => submit(appArgs)

/**

* Submit the application using the provided parameters.
 *

* This runs in two steps. First, we prepare the launch environment by setting up

* the appropriate classpath, system properties, and application arguments for

* running the child main class based on the cluster manager and the deploy mode.

* Second, we use this launch environment to invoke the main method of the child
 * main class.

*/

private def submit(args: SparkSubmitArguments): Unit = {

submit方法准备classpath、系统属性、运行参数,然后按照这些调用下面的方法运行

runMain(childArgs, childClasspath, sysProps, childMainClass, args.verbose)

该方法主要两步,第一步调用下面方法进行准备

val (childArgs, childClasspath, sysProps, childMainClass) = prepareSubmitEnvironment(args)

第二部会调用

runMain(childArgs, childClasspath, sysProps, childMainClass, args.verbose)

进行执行。

在第一步中将sparkR的R相关代码打包成zip文件,然后设置将要运行的主类

如果是SPARKR-SHELL则调用org.apache.spark.api.r.RBackend

如果是纯粹client模式,则调用org.apache.spark.deploy.RRunner,其调用形式如下,例如

Usage: RRunner <main R file> [app arguments]
sun.java.command=com.aliyun.odps.cupid.runtime.Main --class org.apache.spark.deploy.RRunner --primary-r-file testOdpsRdd.R --arg testOdpsRdd.R


RBackend基于netty用来在R和java之间的通讯

Runner里面会调用启动RBackend,然后启动processBuilder去执行R脚本,也就是这句话:

new ProcessBuilder(Seq(rCommand, rFileNormalized) ++ otherArgs)

如何让spark worker识别sparkR代码呢?在R语言中变量R_PROFILE_USER ,用来初始化R运行环境,sparkR相关代码被打包提交到计算集群以后,在计算节点上面首先设置这个数值指向到初始化脚本${SPARK_HOME}/sparkr/SparkR/profile/general.R,这个脚本中识别路径,并且把解压后sparkR的代码安装到当前R环境中。下面是其代码

.First <- function() {
packageDir <- Sys.getenv("SPARKR_PACKAGE_DIR")
.libPaths(c(packageDir, .libPaths()))
Sys.setenv(NOAWT=1)
}

下面的代码来自于prepareSubmitEnvironment

// In YARN mode for an R app, add the SparkR package archive to archives

// that can be distributed with the job

if (args.isR && clusterManager == YARN) {

val rPackagePath = RUtils.localSparkRPackagePath

if (rPackagePath.isEmpty) {

printErrorAndExit("SPARK_HOME does not exist for R application in YARN mode.")

}

val rPackageFile =
 RPackageUtils.zipRLibraries(new File(rPackagePath.get), SPARKR_PACKAGE_ARCHIVE)

if (!rPackageFile.exists()) {

printErrorAndExit(s"$SPARKR_PACKAGE_ARCHIVE does not exist for R application in YARN mode.")

}

val localURI = Utils.resolveURI(rPackageFile.getAbsolutePath)


// Assigns a symbol link name "sparkr" to the shipped package.

args.archives = mergeFileLists(args.archives, localURI.toString + "#sparkr")

}


// If we're running a R app, set the main class to our specific R runner 
if (args.isR && deployMode == CLIENT) {

if (args.primaryResource == SPARKR_SHELL) {

args.mainClass = "org.apache.spark.api.r.RBackend"

 } else {

// If a R file is provided, add it to the child arguments and list of files to deploy.
 // Usage: RRunner <main R file> [app arguments]

args.mainClass = "org.apache.spark.deploy.RRunner"

args.childArgs = ArrayBuffer(args.primaryResource) ++ args.childArgs
 args.files = mergeFileLists(args.files, args.primaryResource)

}

}


if (isYarnCluster && args.isR) {

// In yarn-cluster mode for a R app, add primary resource to files

// that can be distributed with the job

args.files = mergeFileLists(args.files, args.primaryResource)

}

对于普通scala/java作业,standalone情况下直接调用下面类

// In legacy standalone cluster mode, use Client as a wrapper around the user 
class
childMainClass = "org.apache.spark.deploy.Client"

在client模式下直接提交用户应用主类运行,这里的主类如果是SPARKR_SHELL的话就是org.apache.spark.api.r.RBackend

直接提交文件执行则调用org.apache.spark.deploy.RRunner


// In client mode, launch the application main class directly

// In addition, add the main application jar and any added jars (if any) to the classpath

if (deployMode == CLIENT) {

 childMainClass = args.mainClass

if (isUserJar(args.primaryResource)) {

childClasspath += args.primaryResource

}
 if (args.jars != null) {
childClasspath ++= args.jars.split(",")
}
 if (args.childArgs != null) {
childArgs ++= args.childArgs
}

}

在yarnCluster模式调度情况下,使用org.apache.spark.deploy.yarn.Client

这个类包装用户的类进行提交

// In yarn-cluster mode, use yarn.Client as a wrapper around the user class

if (isYarnCluster) {

 childMainClass = "org.apache.spark.deploy.yarn.Client"

 if (args.isPython) {

 childArgs += ("--primary-py-file", args.primaryResource)

if (args.pyFiles != null) {

 childArgs += ("--py-files", args.pyFiles)

}

childArgs += ("--class", "org.apache.spark.deploy.PythonRunner")

} else if (args.isR) {

 val mainFile = new Path(args.primaryResource).getName

childArgs += ("--primary-r-file", mainFile)

childArgs += ("--class", "org.apache.spark.deploy.RRunner")

} else {

if (args.primaryResource != SPARK_INTERNAL) {

 childArgs += ("--jar", args.primaryResource)

}

childArgs += ("--class", args.mainClass)

}
 if (args.childArgs != null) {

 args.childArgs.foreach { arg => childArgs += ("--arg", arg)
}

 }

}

org.apache.spark.deploy.yarn.Client

Py调用spark过程,在python/pyspark/context.py下面存在

class SparkContext(object)

其中的_jvm成员作为py4j的调用存在,其初始化

233 if not SparkContext._gateway:
234 SparkContext._gateway=gateway or launch_gateway()
235 SparkContext._jvm=SparkContext._gateway.jvm

其调用后端方法

207         # Create a temporary directory inside spark.local.dir:
208 local_dir = self._jvm.org.apache.spark.util.Utils.getLocalDir(self._jsc.sc().conf())
209 self._temp_dir = \
210 self._jvm.org.apache.spark.util.Utils.createTempDir(local_dir, "pyspark") \
211 .getAbsolutePath()

sparkR原理的更多相关文章

  1. 奇异值分解(SVD)原理与在降维中的应用

    奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...

  2. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  3. 线性判别分析LDA原理总结

    在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...

  4. [原] KVM 虚拟化原理探究(1)— overview

    KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...

  5. H5单页面手势滑屏切换原理

    H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...

  6. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  7. python自动化测试(2)-自动化基本技术原理

    python自动化测试(2) 自动化基本技术原理 1   概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...

  8. CRC、反码求和校验 原理分析

    3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...

  9. 菜鸟学Struts2——Struts工作原理

    在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...

随机推荐

  1. JavaScript/jQuery选择器简介

    DOM提供的选择器 选择器是帮助我们选择页面元素的工具,在网站制作中常常会涉及到某个元素的改变,通过选择器提取这些元素可以很轻易的实现(DOM术语把所说的“元素”称作是“节点”).JavaScript ...

  2. Android View的绘制机制流程深入详解(一)

    本系列文章主要着重深入介绍Android View的绘制机制及流程,第一篇主要介绍并分析LayoutInflater的原理, 从而理解setContentView的加载原理.对于LayoutInfla ...

  3. Java安全防御学习笔记V1.0

    Java安全防御学习笔记V1.0http://www.docin.com/p-766808938.html

  4. 我的第二篇--nginx安装问题之路径问题

    这几天还是一直在搭建nginx,并且要在nginx的基础之上配置naxsi(WAF防火墙)并使它生效,但是随之而来的问题也会有很多,也许因为我是个新手,所以遇到的问题要多,不解的问题也要很多,不知道又 ...

  5. Ubuntu 14.04 & ant: Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-7-openjdk-i386/lib/tools.jar

    当我在vagrant + ubuntu 14.04,jenkins ant执行项目的build.xml时,提示: [workspace] $ ant -file build.xml Unable to ...

  6. CSS 基本知识

    1.CSS 简介 CSS 指层叠样式表 (Cascading Style Sheets),是一种用来表现 HTML 文档样式的语言,样式定义如何显示 HTML 元素,是能够真正做到网页表现与结构分离的 ...

  7. 通过样式调整input 中password text默认长度

    原文出处 <input >标签内的type分别为password和text时其默认长度和宽度不一致,而在做登陆框时往往需要将它们的长度和宽度设置一致.如下的方法可以通过css控制使其一致: ...

  8. 【转】spring - ioc和aop

    [转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...

  9. 接口和抽象类:Interface、abstract _【转】

    一.接口 接口是C#中很常见的工具,概念什么的就不说了,这里讲几个值得注意的小地方: 1.接口内部只能有函数.属性和事件的声明: interface IParent { void Show(); st ...

  10. Activiti源码分析(框架、核心类。。。)

    http://jiangwenfeng762.iteye.com/blog/1338553 Activiti是业界很流行的java工作流引擎,关于Activiti与JBPM5的关系和如何选择不是本文要 ...