需求是:tomcat的java进程经常100%占用CPU,此时servlet也停止响应了,业务逻辑除了问题。
希望有一个在PC上跑的监控程序,能够在tomcat 100%占用cpu的时候杀死。同时tomcat自动重启。
过程:tomcat自动重启是通过脚本实现 start_tomcat.sh :
下一步就是要检测tomcat的进程的PID。命令是:test.sh
拿到CPU占用情况:
ps -p PID -o %cpu,%mem,cmd
这条命令是在java环境中执行 RunTime.exec:
.这篇博客的重点在于:
原本在bash下面执行的ps 命令,如果想通过java执行并且获得ps输出,需要以 exec(new String[]{"/bin/sh","-c","正常控制台执行的命令"}) 这种形式才可以。
参考【http://huajianhsiu.iteye.com/blog/1772775】,可能是多重重定向导致的错误。这个方法是可以通用的。
下面是监控源码
----------------------------------------------
public class Monitor {
/**
* @param args
*/
public static void main(String[] args) {
try {
double last =0;
while(true)
{
TimeUnit.SECONDS.sleep(10);
String pid =getPID();
if(pid==null||pid.trim().length()==0)
{
continue;
}
System.out.println(pid);
String info =getCPU(pid);
System.out.println(info);
double cur =Double.parseDouble(info);
if(last>80&&cur>80)
{
Kill();
}
else {
last=cur;
}
}
} catch (Exception e) {
}
}
public static void Kill ( ) throws Exception
{
String pid =getPID();
if(pid==null||pid.trim().length()==0)
return ;
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { "/bin/sh","-c", "kill -9 "+pid});
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
}
public static String getPID() throws Exception
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { "/bin/sh","-c", "/home/apps/test.sh"});
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));
// read the output from the command
StringBuilder sb =new StringBuilder();
String s = null;
while ((s = stdInput.readLine()) != null) {
sb.append(s.trim());
}
return sb.toString().trim();
}
public static String getCPU(String pid) throws Exception
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] {"/bin/sh","-c","ps -p "+pid+" -o %cpu,%mem,cmd"});
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
// read the output from the command
StringBuilder sb =new StringBuilder();
String s = null;
while ((s = stdInput.readLine()) != null) {
sb.append(s);
}
String []cp =sb.toString().split(" ");
return cp[3];
}
}
-----------------------------------------------------------------------------------------------------------------------------
2015年11月17日10:33:05修正:经过晚上的测试,发现上述的getCPU函数并不能准确描述当前系统的CPU占用情况。
后来在阿里云里面采取了这个命令:top -bn2|grep 'Cpu(s)'|awk '{print $8}'|awk -F'%' '{print $1}'|tail -n1
取到的值为空闲状况;若这个值低于20,则认为cpu忙,10s检测一次,若连续2次都低于20,则进行重启tomcat. 修改如下。
public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static SimpleDateFormat sdf2 =new SimpleDateFormat("yyyy-MM-dd-HHmmss");
public static void main(String[] args)
{
try
{
double last = 0.0D;
for (;;)
{
TimeUnit.SECONDS.sleep(10L);
String info = getCPU();
System.out.println(sdf.format(new Date()) + "|" + info);
double cur = Double.parseDouble(info);
if ((last < 20.0D) && (cur < 20.0D)) {
Kill();
} else {
last = cur;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void Kill()
throws Exception
{
String pid = getPID();
if ((pid == null) || (pid.trim().length() == 0)) {
return;
}
Jstack(pid);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { "/bin/sh", "-c", "kill -9 " + pid });
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
}
public static void Jstack(String pid) throws Exception
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { "/bin/sh", "-c", " jstack " + pid+" > /home/apps/"+sdf2.format(new Date())+".log" });
}
public static String getPID()
throws Exception
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { "/bin/sh", "-c", "/home/apps/test.sh" });
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
StringBuilder sb = new StringBuilder();
String s = null;
while ((s = stdInput.readLine()) != null) {
sb.append(s.trim());
}
return sb.toString().trim();
}
public static String getCPU()
throws Exception
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(new String[] { "/bin/sh", "-c", "top -bn2|grep 'Cpu(s)'|awk '{print $8}'|awk -F'%' '{print $1}'|tail -n1" });
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
StringBuilder sb = new StringBuilder();
String s = null;
while ((s = stdInput.readLine()) != null) {
sb.append(s);
}
return sb.toString().trim();
}