需求是: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();
}