在BashOnWindows里运行Mobius(C# on Spark)

缘起

首先,我想说,这是一篇有点画风清奇的博文,将一个Linux-first的分布式系统软件Spark,与被一般偏见认为只能在Windows上运行的C#语言API,跑在Windows的原生Bash环境里。

先介绍Windows的原生Bash环境。Bash On Windows(也称为Windows Subsystem for Linux (WSL))是Win10一周年更新所带来的新特性,简单地说就是可以在Windows上native地运行bash的一些常用命令(如sed,awk之类),个人感觉是比虚拟机更贴近内核的东西。当然目前还是beta版,希望日后可以逐渐完善以取代Cygwin之类的软件。

C#是微软主导开发的一门语言,长时间以来在传统偏见认知中与Visual Studio以及Windows紧紧捆绑在一起。当然,其实.Net Framework也早开源了,而且还有mono这种致力于使.Net跨平台的开源项目。

Apache Spark是Apache基金会旗下的一个基于JVM的大数据计算系统框架,虽说是基于JVM的,但是与Hadoop生态圈的大多数软件一样,都是Linux-first的。

所以,这篇博文就是介绍如何将这三者结合在一起。当然,为了能在Spark上使用C# API,则需要引入另外一个开源项目Mobius。Mobius原名SparkCLR,顾名思义,就是在Apache Spark上提供C#的语言支持(C#的运行时就叫Common Language Runtime),该项目由微软主导开发,旨在Spark已有Scala、Java、Python、R语言API的基础上为.Net用户提供更多的选择,并提供一些更多的扩充。其主要实现思路是借助于PySpark,该项目的tech lead8月初在DataBricks发表了博文介绍了该项目,并介绍了部分细节。

准备好食材,现在就是做菜的工序啦,流程主要参照linux-instructions

快速上手

本节主要采用预编译的官方Release为例,所以无需在Linux上编译

预备安装软件

  1. JDK7 or above,在BashOnWindows里安装default-jdk即可,但是我在先前的版本里遇到了Java安装后,启动JVM进程会hang住的问题,Scala REPL甚至无法运行,有种方法是在windows inside preview里选择update,至少14901版本是可以正常运行JVM进程的。
  2. Mono 4.2 stable or above。Mono的安装参照Mono官方安装文档,安装完之后请确认一下mono --version的输出,保证版本是4.2以上。
  3. 环境变量SPARK_HOME,可以直接从官方下载Spark预编译版本并解压缩,设置环境变量SPARK_HOME指向该Spark目录。该环境变量为了提供Spark assembly jar路径。
  4. 环境变量SPARKCLR_HOME,从Mobius官方release页面下载,例如选择v1.6.200-PREVIEW-1,解压之后,设置环境变量SPARKCLR_HOME指向/path/to/spark-clr_2.10-1.6.200-PREVIEW-1/runtime目录,注意是runtime目录。

单机模式运行

*.exe文件在Linux能否直接运行在不同Linux发行版本下表现不同,安装mono后,在BashOnWindows中无法直接运行,但是在Debian8.5中可以直接运行。

为了运行*.exe文件,需要使用额外的脚本命令来启动,对于SparkClrPi程序,C#端的driver(也就是SparkClrPi.exe文件)需要额外的执行脚本。同样地,与JVM executor进行交互的CSharpWorker.exe也需要额外的执行脚本。

$SPARKCLR_HOME/../examples/Batch/pi/目录下创建SparkClrPi.sh.exe文件,文件内容可以参照Mobius的linux-prefix-script文档,参考内容如下,并确保该文件具有执行权限(chmod a+x SparkClrPi.sh.exe):

#!/bin/sh
exec mono $SPARKCLR_HOME/../examples/Batch/pi/SparkClrPi.exe "$@"  

同样地,在$SPARKCLR_HOME/../examples/Batch/pi/目录下创建CSharpWorker.sh.exe文件,并确保该文件具有执行权限,参考内容如下:

#!/bin/sh
exec mono $SPARKCLR_HOME/../examples/Batch/pi/CSharpWorker.exe "$@"  

此外,由于JVM executor启动CSharpWorker时默认会去寻找CSharpWorker.exe,所以还需要对SparkClrPi.exe.config进行修改,将默认注释掉的内容进行修改:

<!-- for Spark in ** local ** mode -->  
      <add key="CSharpWorkerPath" value="$SPARKCLR_HOME/../examples/Batch/pi/CSharpWorker.sh.exe"/>

为什么需要这么折腾完全就是因为在BashOnWindows默认情况下无法直接运行*.exe文件,所以嵌套了一层。然而在Debian8.5中,在安装mono后,可以直接运行*.exe文件。 大功告成后,直接运行如下脚本命令执行SparkClrPi计算Pi的数值,所使用的master地址默认是local[*]:

 $SPARKCLR_HOME/scripts/sparkclr-submit.sh --exe SparkClrPi.sh.exe $SPARKCLR_HOME/../examples/Batch/pi/ 1000

运行之后得到类似的输出即表明运行成功: SparkClrPi

需要注意的是,这里--exe对应于java中的--class,表示的是C# driver的exe文件名,而不是该文件的地址路径,请勿附上任何文件路径相关的参数。

附录

关于Mobius的设计文档可以参考源码项目中的文档目录

JVM端的driver(由spark-clr_2.10-1.6.200-PREVIEW-1.jar启动)与C#端的用户程序driver端的通信机制如下图:
JVM-CLR Mobius driver

至于JVM executor与C#端worker的通信原理可以参照下图: JVM-CLR Mobius worker