虚拟机调度器
1. Java宠物商店简介
宠物商店(JPetStore)最初是Sun公司基于Java EE平台开发的一个实现实例,它给出了一个完整的宠物商店实例。用户几乎不用修改就可以直接使用这个应用来经营自己的网上宠物商店。
1.1 环境准备
硬件设备:一台电脑,4G内存,操作系统是Windows 7。
环境搭建步骤:
1. 安装VMware Server;
2. 在VMware Server上新建一个虚拟机,操作系统是Windows XP;
3. 在Windows XP系统中安装JDK;
4. 在Windows XP系统中安装Tomcat;
5. 测试JDK、Tomcat是否正常安装。
下边给出所需软件的下载地址:
软件名称 |
说明 |
下载地址 |
Java宠物商店 |
本章示例应用 |
http://mybatis.google.com |
JDK |
Java工具包 |
http://java.sun.com |
Tomcat |
Java应用服务器 |
http://tomcat.apache.org |
VMware Server |
虚拟机服务器 |
http://www.vmware.com/products/server |
1.2 部署Java宠物商店
首先运行Tomcat
在浏览器中输入http://127.0.0.1:8080/manager/html回车
点击最下边的浏览,选择宠物商店的war文件,点击部署。
最后在浏览器中输入http://127.0.0.1:8080/mybatis-jpetstore-6.0.0进入宠物店首页面
此时,局域网内的用户也可以访问宠物商店,只需把IP地址改为服务器的地址。
2. 宠物商店访问速度测试
在完成应用程序的部署之后,需要进行测试,以检测程序是否能满足我们的要求。本文我们只对首页的访问速度进行测试。
本文使用的测试工具是JMeter。下载地址:http://jakarta.apache.org/jmeter/下载后进行安装。安装完成打开,首页如下图所示。
3. 针对测试结果改进应用
经过上面的测试,可以看到当同时有100个用户并发访问宠物商店时,平均225ms才能访问网站的首页。用户可能因为访问速度过慢而放弃访问。人们可以增强机器的性能,提高相应的速度。
由于使用虚拟机搭建运行环境,因此可以更改虚拟机的配置来提高虚拟机的性能。上边的测试,虚拟机的内存为128M,现在我们将内存改为512M。重新测试,可以看到平均访问时间为73ms。
提高应用程序的访问速度,除了提高服务器性能外,我们还可以增加服务器的数量,来分担访问量。但与此同时,部署应用程序所需要的计算资源也越来越多了,尤其是当访问量比较低时,仍要运行两台虚拟机就显得有些浪费资源(在云计算环境中,一般按照使用的计算资源量来收费,多使用虚拟机意味着花更多的金钱)。
如果应用程序可以在用户访问量增大时增加适当的计算资源,而在访问量减少时,释放多余的计算资源,那么就即达到了提高用户访问速度的要求,又节约了有限的资金。
4. 虚拟调度器的设计
根据上面的分析,有两方面的需求:
1. 监控用户访问量;
2. 根据用户的访问量增加或减少应用服务器的数量。
4.1 监控用户访问量
监控用户访问量有很多办法,比如设置网络技术期,监控流量。但造成用户访问变慢的直接原因往往是主机内存使用率及CPU使用率的上升。针对此情况,Java虚拟机提供了一个专门的监测工具JMX(Java Management Extensions,即Java管理扩展)。Java开发工具中的JConsole提供了图形化的监控界面。
4.2 增加或减少服务器数量
VMware Server提供了一套VMware VIX编程接口及相应的命令行程序操作,共开发人员编写程序使用。VIX编程接口只支持Perl和COM语言。但我们可以使用Java语言来实现控制虚拟机的数量,我们可以使用Java程序调用命令行。
虚拟机的开启和关闭命令如下。
vmrun –T server – u <User Name> -p XXX –hhttp://127.0.0.1:8333/sdk start “[vmwaredatastore] winxp/Windows XP.vmx”
vmrun –T server – u <User Name> -p XXX –hhttp://127.0.0.1:8333/sdk stop “[vmwaredatastore] winxp/Windows XP.vmx”
4.3 虚拟调度器的实现
代码如下:
JMXClient.java
package com.skater.cloud;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class JMXClient {
public JMXClient() {
super();
}
public static void main(String[] args) throws Exception {
String urlForJMX = "service:jmx:rmi:///jndi/rmi://10.1.58.64:1090/jmxrmi";
MBeanServerConnection jmxServerConnection = JMXConnectorFactory
.connect(new JMXServiceURL(urlForJMX), null)
.getMBeanServerConnection();
try {
String[] domains = jmxServerConnection.getDomains();
for (String domain : domains){
System.out.println(domain);
}
ObjectName memory = new ObjectName("java.lang:type=Memory");
CompositeDataSupport comp = (CompositeDataSupport)jmxServerConnection.getAttribute(memory, "HeapMemoryUsage");
double max = (Long)comp.get("max");
double used = (Long)comp.get("used");
System.out.println(used/max);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static double getMemoryUsage() {
String urlForJMX = "service:jmx:rmi:///jndi/rmi://10.1.58.64:1090/jmxrmi";
double memoryUsage = 0;
MBeanServerConnection jmxServerConnection = null;
try {
jmxServerConnection = JMXConnectorFactory
.connect(new JMXServiceURL(urlForJMX), null)
.getMBeanServerConnection();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
String[] domains = jmxServerConnection.getDomains();
for (String domain : domains){
System.out.println(domain);
}
ObjectName memory = new ObjectName("java.lang:type=Memory");
CompositeDataSupport comp = (CompositeDataSupport)jmxServerConnection.getAttribute(memory, "HeapMemoryUsage");
double max = (Long)comp.get("max");
double used = (Long)comp.get("used");
memoryUsage = used/max;
} catch (Exception ex) {
ex.printStackTrace();
}
return memoryUsage;
}
}
OperateVM.java
package com.skater.cloud.util;
//操作虚拟机
publicclass OperateVM {
publicstaticvoid startVM(String userName, String passwd, String url, String dataStore,String path, String VMName) {
ExecuteCommand.execute("vmrun -T server -u "+userName+" -p "+passwd+" -h "+url
+" start \"["+dataStore+"] "+ path +"/"+VMName+"\"");
}
publicstaticvoid stopVM(String userName, String passwd, String url, String dataStore,String path, String VMName) {
ExecuteCommand.execute("vmrun -T server -u "+userName+" -p "+passwd+" -h "+url
+" stop \"["+dataStore+"] "+ path +"/"+VMName+"\"");
}
}
ExecuteCommand.java
package com.skater.cloud.util;
import java.io.BufferedReader;
import java.io.InputStreamReader;
//执行命令行
public class ExecuteCommand {
public static void execute(String cmd) {
try {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(pr
.getInputStream()));
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line);
}
int exitVal = pr.waitFor();
System.out.println("Exited with error code " + exitVal);
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
}
VMScheduler.java
package com.skater.cloud;
import com.skater.cloud.util.OperateVM;//虚拟机调度器
publicclass VMScheduler {
publicstaticvoid main(String args[]) {
while (true){
double memoryUsage=0;
try {
memoryUsage = JMXClient.getMemoryUsage(); // 每隔5分钟查看一次内存使用情况
Thread.sleep(5*60*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(memoryUsage>0.2){
OperateVM.startVM("administrator",".", "https://127.0.0.1:8333/sdk","standard", "winxp2_1", "winxp2.vmx");
}else{
OperateVM.stopVM("administrator",".", "https://127.0.0.1:8333/sdk","standard", "winxp2_1", "winxp2.vmx");
}
}
}
}
代码编写完成,生成jar包。双击即可执行。