学习java的程序员应该都了解,在oracle的jdk中,我们每次运行一个java application都会创建一个jvm的进程,可能我们只是一个简单的程序,但是fork jvm已经花费了我们大部分时间,这就有点得不偿失,因此就出现了我们现在的NailGun 以及IBM的J9 jdk的multiple tenants的特性。都是在当前已经启动的jvm进程上,运行我们的java程序,节省时间。
下面我重点介绍一下NailGun的安装和原理,IBM的J9大家可以去下载自己试试。
NailGun的安装和运行
首先简单介绍一下nailgun,nailgun是一套客户端,协议和服务端,使你可以通过执行对应的命令,在服务端的jvm上运行你的程序,而不用在本地起jvm进程。
下载nailgun,主页是:http://martiansoftware.com/nailgun/,在github上有他们的开源项目自己可以去下载。
下载之后,解压得到如下文件:
可以看到里面有pom文件,看到pom文件中module如下:
用Maven进行管理,因此我们需要首先安装maven,安装maven之后,我们进入nailgun的解压目录,并执行mvn clean install 命令,安装nailgun的server和example,如下图所示:
安装成功后,出现build successfully ,并且在nailgun-server和nailgun-examples会生成一个target文件夹,里面会有许多jar包,是我们运行java程序需要的,如下图:
到此我们server和example已经安装完成了,接下来我们需要安装client,同样到nailgun的解压目录下,运行make && sudo make install 命令,安装client,如下图所示:
提示:
1. windows下可能会提示没有make命令(如果你下载cygwin时候没有包括的话),这时候需要下载一个make命令,网址:http://www.equation.com/servlet/equation.cmd?fa=make 将下载下来的make.exe 放到cygwin的目录下,就可以在windows下使用make命令了。
2. 同时提示没有sudo命令的话,有两种解决方案:
2-1. 将sudo改成runas,runas是windows下类似sudo的命令
2-2. 在要使用sudo命令的文件下面,新建一个sudo.js文件,并将下面的代码,写入该文件中,这样就可以在该目录下使用sudo命令(其实代码里面也是封装了runas命令)
var command = WScript.Arguments.Item(0);
var argument = "";
for (var i = 0; i < WScript.Arguments.Count(); ++i){
argument += WScript.Arguments.Item(i) + " ";
}
try{
var shellapp = new ActiveXObject("Shell.Application");
shellapp.ShellExecute(command, argument, null, "runas", 1);
}catch(e){
WScript.Echo("Something wrong: " + e.description + " By http://www.alexblair.org");
}
参考网址:
http://stackoverflow.com/questions/9652720/how-to-run-sudo-command-in-windows
http://www.alexblair.org/user-alexblair-post-1046.html
再次运行我们的client安装命令 在windows要多加一步make ng.exe
在目录下生成了一个ng.exe文件。
到此我们nailgun的server和client都安装完毕,下面就进行测试。
启动nailgun server的服务,如下图:(首先将nailgun-server 下的target目录下的nailgun-server-0.9.2-SNAPSHOT.jar 加入到classpath中,否则会报错:找不到或无法加载主类 com.martiansoftware.nailgun.NGServer)
服务已经启动了,在端口号2113。(这里的端口号,可以自己设置)。自己写了一段简单的代码,进行测试。如下:
package com.nailgun.test;
/**
* Created by TaoZhi on 14-10-29.
*/
public class HelloNailGun {
public static void main(String []args){
System.out.println("Hello NailGun");
}
}
运行我们的class 文件。如果出现了class not found 错误
ng ng-cp 指定找class文件的路径,类似java中的cp命令。就不会报class not found 错误。
在server端,我们可以看到,没当我们run一次,都会有一个连接到服务端,如下图所示:
可以用ng ng-stop关闭服务
启动服务可以指定地址和端口,如下图:
在此引用NailGun官网的实验数据,说明nailgun的效率。第一条是在标准的java运行程序,第二条是在nailgun上面运行java程序
可以看出nailgun的时间效率非常好!在Linux下安装和Windows基本一致,甚至更简单。大家可以自己试试。
NailGun的原理
上面已经介绍了nailgun的安装以及简单的测试运行,那么nailgun是一个怎么样的原理呢?其实原理很简单:当你在服务端起一个jvm的时候,一旦有客户端连接到这个服务端,这个jvm会被客户端的所有java程序共享的,也就是说当你在客户端通过ng 命令运行一个java程序的时候,会将客户端运行的环境变量、命令行和其他一些数据,通过TCP发送到NailGun Server,将你的客户端的输入(stdin)定向到server上,同时将server的输出(stdout)和错误(stderr)定向到client,达到运行程序的目的。更加详细的原理介绍,请参照NailGun的官网介绍:http://martiansoftware.com/nailgun/background.html
NailGun的不足
1.有class缓存,对于已经加载的class,再次修改之后,运行的还是原来的class。我们将输出修改为“Hello NailGun again”
并没有输出我们之后修改的 Hello NailGun again,而是之前的Hello NailGun,必须要重启server(可能有其他办法,暂时未知,如果有清除缓存的功能,就好了),然后再次运行。
2.数据的隔离做的不好,因为可能同时有多个client的java程序在运行,对于数据的隔离做的不好,容易造成错误。如:
写一个简单的例子,Constants类里面有一个类变量,DataTest1中,读出来,进行加1操作,然后睡眠30s,此时运行DataTest2,看看输出来的Constants类的变量时多少?
package com.nailgun.test;
/**
* Created by TaoZhi on 14-10-29.
*/
public class Constants {
public static int nailGunNum=10;
}
package com.nailgun.test;
/**
* Created by TaoZhi on 14-10-29.
*/
public class DataTest1{
public static void main(String []args){
System.out.println(Constants.nailGunNum);
Constants.nailGunNum++;
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Constants.nailGunNum);
}
}
package com.nailgun.test;
/**
* Created by TaoZhi on 14-10-29.
*/
public class DataTest2 {
public static void main(String[] args) {
System.out.println(Constants.nailGunNum);
}
}
可以看到,标准的jvm已经做了很好的数据隔离,在DataTest2中读到的变量值为10,但是在nailgun下确实如下结果
由此可以看出,nailgun的数据隔离性做的确实不够好,还有许多需要完善的地方,否则很容易在程序中造成错误。