JMX自动监控Java应用 解决well-known file is not secure

JMX自动监控Java应用 解决well-known file is not secure

前言

最近在做一个监控的Agent组件开发工作,主要就是收集各种系统Metrics信息,然后上报给监控系统,以便进行监控和告警。目标就是要做到自动化:自动发现服务,动态探测服务,监控自动运维化,插件化等等。
在Java应用监控这一块,主要就是监控Java应用的JMX信息。为了能够自动发现Java应用,自动连接JMX,做了不少尝试。本文就是分享,其中的一个问题的解决,把问题的解决思想记录下来。

什么是well-known file is not secure

当我们要连接VM的时候,如JMX,jmap,jstack时,VM会检查/tmp/hsperfdata_$USER/$PID这样的一个文件,它会检查执行该命令的用户,是否和hsperfdata_$USER这个文件所属的用户一致,如果不一致,就会出现well-known file is not secure这个异常,并拒绝连接

怎样通过JMX连接Java应用并监控

JMX连接都是通过一个连接字符串,调用JMXConnectorFactory.connect()方法建立连接。一般而言,JMX的连接字符串有两种获取方法:

  • 第一种是手动指定形如service:jmx:rmi:///jndi/rmi://host:ip/jmxrmi的JMX Remote URL。
  • 第二种则是先使用VirtualMachine.list()方法得到本地的所有JMX信息,然后通过Attach得到相关Pid的com.sun.management.jmxremote.localConnectorAddress进行连接。

第一种方法,需要在java应用启动时,指定开启JMX Remote,如可添加如下参数

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=${JMXport} 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false

这种方法的好处就是没有well-known file is not secure这种问题,但是这样就需要手动配置连接信息,也就失去了标题所述的自动连接,自动监控。

第二种方法,能够实现自动探测本地的应用,无论应用是否有开启JMX Remote的功能,都是可以连接。但是缺点就是会存在well-known file is not secure异常,就是当目标Java应用和本程序启动的用户不一样时,就会出现这个异常。所以就需要结合两个方法一起使用。

怎样结合两者?

话不多说,开门见山。

两者结合的方案就是,先使用第二种方法进行本地的Java应用扫描,无论目标应用是不是同一个用户启动,都是可以获取得到,并且也能够获取到它的Pid。然后针对每个应用,先进行第二中方法的连接,如果连接失败,则代表该应用存在well-known file is not secure异常。然后,就可以根据该应用的Pid,使用 ps -aux | grep Pid的方式,获取到应用的启动命令,然后解析启动命令,获取启动命令中的com.sun.management.jmxremote.port参数值port,然后根据该port,使用本地的IP地址127.0.0.1自动构建JMX Remote URL连接。

当然,这其中如果应用启动时,设置了参数-Dcom.sun.management.jmxremote.authenticate=true,则代表该JMX有授权认证,需要登录名和密码才能连接。我的解决方法是解析/etc/profile文件,获取JAVA_HOME地址,然后解析JAVA_HOME/jre/lib/management/jmxremote.accessJAVA_HOME/jre/lib/management/jmxremote.password文件的内容获取用户名和密码。

但是,由于java对这两个文件有严格的用户权限控制:必须是运行该程序的用户才能进行读写,不然java应用会拒绝启动。所以即使是root用户启动,只要不是相同的用户,也无法访问这两个文件。
凡事总会有解决办法,我的方案就是对对应的配置文件进行拷贝到一个临时文件,并授权777(因为是监控,所以本程序基本上都是root身份运行),然后获取临时文件内容,解析获取用户名和密码,解析完了再删除临时文件。这样就可以获取到JMX Remote连接的授权用户和密码。

最后补充一下,如果目标应用没有开启JMX Remote Connect的功能而且启动的用户也不同,那么应该是无法使用JMX连接了,除非使用相同的用户,再启动一个进程进行连接。不过,正常而言,公司应该都会开启Java应用的JMX Remote功能。

不过,又有一个问题来了
如果Java是跑在Docker container上怎么办?怎样同时监控Docker容器和容器内的应用呢?有时间再分享这个的解决方案。

你可能感兴趣的:(JAVA,jmx,监控,运维)