背景
需要增加熔断功能,但是之前写的是linux系统,在Aix系统中失效了,需要重新写。
原来的linux用的是/proc/meminfo、/proc/stat这两个文件进行监控的,但是Aix中没有这两个文件。
而且top命令也是不支持的,所以只能重写
思路一:topas
在linux中有top命令,在Aix中与之对应的是topas命令
topas命令详解:https://blog.csdn.net/qq_21909121/article/details/80997663
原来使用BufferedReader写的,如下
try {
String[] cmds = {"/bin/sh", "-c",
"topas"};
p = Runtime.getRuntime().exec(cmds);
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
log.debug("line [%s]",line)
}
} catch (Exception e) {
log.error("Exception [%s]",e);
}
但是在写的过程中发现,走到某一次log.debug("line [%s]",line)
没有下文了,就连下面的catch中的内容也不走了,整个线程被阻塞住了,后来一行一行的删代码,最终定位到是line = br.readLine()
的事,上网查阅资料发现readLIne是阻塞的,具体可以上网查阅相关资料。如果没有读到/r 或者 /n ,也没有设置超时时间就会一直阻塞在那里,也不会抛出异常。因为阻塞了所以我也看不到每一行到底是什么也不知道为什么阻塞了,解决办法也有,就是需要设置一个超时时间,超过时间关闭流之类的,但是我这里必须读topas里面的内容,超时了你就给我关闭,那我还怎么读取数据?还怎么熔断啊?
想到可不可以让p.getInputStream()不通过readline读出来呢?通过read读取呢?但是通过read貌似要写到一个txt等文本中,这不是加大了熔断的开销吗?不要客户的代码还没熔断呢,我们的监控程序消耗了人家一大半内存给熔断了。于是乎可以将输出流转换成String:https://www.cnblogs.com/MyTiMo/p/10998525.html
InputStream inputStream = p.getInputStream();
byte[] bytes = new byte[2048];
int n = -1;
while ((n = inputStream.read(bytes, 0, bytes.length)) != -1) {
//转换成字符串
String str = new String(bytes, 0, n, "UTF-8");
log.debug("str ==> [%s]", str);
} //写入相关文件
当我写成这样的时候,发现线程还是阻塞了,而且诡异的是日志中的这个str是一直刷新的我的天,还是第一次见。所以要想办法让它不刷新,在linux中有一个办法就是通过top -b -n 1
这种方式,-n是在页面结束之前刷新几次的意思https://my.oschina.net/u/125259/blog/310216,但是在topas中没有这个参数具体可以通过topas -h看具体的支持参数,通过查阅ibm的官网发现https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/t_commands/topas.html
这里有一个面板冻结的功能,需要用到topas的子命令,即到达topas的显示界面之后按空格键,但是通过java调用子命令这种,我没有找到很好的方法。所以放弃了topas这种方式。
关于topas内存的比率:.topas 内存百分比=%COMP %NOMCOMP)
%Comp:计算型内存占用比率。
%Noncomp:非计算型内存占用的比率。
http://blog.itpub.net/29702473/viewspace-1189289/
关于topas cpu的比率:User
虽然最终没有选择topas这种方式,但是这里的比率对于下面的另一种方法的准确性有参考价值。
思路二:svmon vmstat
网上一种思路:aix计算内存占用比例(但是我没有用,感觉最后计算的和上面topas有2个点的误差呢。)
http://www.talkwithtrend.com/Article/32445
主机cpu占比:
vmstat 1 5 (每秒钟一次,一共五次)
https://www.iteye.com/blog/czmmiao-1156878
https://blog.csdn.net/zhaojian1988/article/details/8919722
主机memory占比:
svmon
https://blog.csdn.net/icescream6/article/details/45665209
其他关于svmon的相关资料自行查阅
AIX的SVMON命令详解(原创)https://www.iteye.com/blog/czmmiao-1153499
最后的解决方案
主机cpu占比:java调用:vmstat 1 1| tail -n 7 | head -n 7|awk ‘{print $16}’
主机memory占比:java调用:svmon -G|grep memory|grep -v grep|awk ‘{print $2 " " $3}’
完整代码
在判断操作系统的地方添加:
if ((getSystemOsName().indexOf("linux") >= 0)||(getSystemOsName().indexOf("aix") >= 0))
/*
*得到系统剩余cpu的比率 ForAix
* @description:
* @author: Leesin.Dong
* @date: 2019-12-31 16:29
* @param
* @return: double
*/
public double getSysCpuPercentForAix() {
log.info("--------------------------------begin collection cpu");
// double cpu = getPercentForAix("CPU");
Double cpu = Double.valueOf(0);
Double cpuidel = Double.valueOf(0);
Process p = null;
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
String[] cmds = {"/bin/sh", "-c",
"vmstat 1 1| tail -n 7 | head -n 7|awk '{print $16}'"};
p = Runtime.getRuntime().exec(cmds);
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
cpuidel = Double.valueOf(line);
cpu = 100 - cpuidel;
}
} catch (Exception e) {
log.error("Exception [%s]",e);
} finally {
try {
if (br != null) {
br.close();
}
if (p != null) {
p.destroy();
}
} catch (Exception e) {
log.error("Exception [%s]",e);
}
}
log.debug("cpu idel out [%s]", sb);
log.info("--------------------------------cpu%s", cpu);
return cpu;
}
/*
*得到系统剩余内存的比率 ForAix
* @description:
* @author: Leesin.Dong
* @date: 2019-12-31 16:29
* @param
* @return: double
*/
public double getSysMemPercentForAix() {
log.info("--------------------------------begin collection memory");
Double disk = Double.valueOf(0);
Process p = null;
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
String[] cmds = {"/bin/sh", "-c",
"svmon -G|grep memory|grep -v grep|awk '{print $2 \" \" $3}'"};
p = Runtime.getRuntime().exec(cmds);
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
double percent = Double.valueOf(line.split("\\s ")[1]) / Double.valueOf(line.split("\\s ")[0]);
disk = percent;
}
} catch (Exception e) {
log.error("Exception [%s]",e);
} finally {
try {
if (br != null) {
br.close();
}
if (p != null) {
p.destroy();
}
} catch (Exception e) {
log.error("Exception [%s]",e);
}
}
log.debug("mem related out [%s]", sb);
log.info("--------------------------------mem%s", disk * 100);
return disk * 100;
}
收获
readLine阻塞
将output转化为string
https://www.cnblogs.com/MyTiMo/p/10998525.html
InputStream不能设置输入的流字符集,默认文件什么格式就输入什么,但是可以通过输出流的设置修改为一样的。https://www.cnblogs.com/pxb2018/p/10738758.html
BufferedReader可以设置输入的流的字符集
IBM官网提示:https://www.ibm.com/developerworks/cn/aix/library/au-aixoptimization-memtun2/index.html
AIX内存性能优化和监视:https://blog.51cto.com/xiaocao13140/1942370
AIX topas命令详解https://blog.csdn.net/qq_21909121/article/details/80997663