如何使用 JMX 连接到在 EC2 上运行的 Java 实例

2022-09-01 08:14:33

我们在连接到 Amazon 的 EC2 集群中运行的 Java 应用程序时遇到问题。我们肯定已经允许“JMX端口”(通常是RMI注册表端口)服务器端口(完成大部分工作)到相关实例的安全组。Jconsole连接,但似乎挂起,从不显示任何信息。

我们正在使用如下所示的内容运行Java:

java -server -jar foo.jar other parameters here > java.log 2>&1

我们尝试过:

  • 端口的 Telnet 连接,但不显示任何信息。
  • 我们可以在实例本身上运行,通过ssh使用remote-X11,它连接并显示信息。因此,JRE正在本地导出它。jconsole
  • 打开安全组中的所有端口。哎呀。
  • 用于确保流量不会流向其他端口。tcpdump
  • 在本地模拟它。我们始终可以使用相同的应用程序参数连接到本地 JRE 或运行在网络上其他位置的 JRE。

java -version输出:

OpenJDK Runtime Environment (IcedTea6 1.11.5) (amazon-53.1.11.5.47.amzn1-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

顺便说一句,我们正在使用我的Simple JMX软件包,它允许我们设置通常由RMI注册表半随机选择的RMI注册表和服务器端口。您也可以使用以下类似 JMX URI 的内容强制执行此操作:

service:jmx:rmi://localhost:" + serverPort + "/jndi/rmi://:" + registryPort + "/jmxrmi"

如今,我们对服务器和注册表使用相同的端口。在过去,我们用作注册表端口和服务器端口,以使安全组规则变得容易。您可以连接到注册表端口或您正在使用的任何 JMX 客户机。XX+1jconsole


答案 1

我们在连接到 Amazon 的 EC2 集群中运行的 Java 应用程序时遇到问题。

事实证明,问题在于缺少两个设置的组合。第一个强制 JRE 首选 ipv4 而不是 v6。这是必要的(我猜),因为我们试图通过v4地址连接到它:

-Djava.net.preferIPv4Stack=true

真正的阻碍因素是,JMX的工作原理是首先联系RMI端口,RMI端口使用主机名和端口进行响应,以便JMX客户端进行连接。如果没有其他设置,它将使用盒子的本地IP,这是远程客户端无法路由到的虚拟地址。我们需要添加以下设置,即服务器的外部主机名或 IP - 在本例中,它是服务器的弹性主机名。10.X.X.X

-Djava.rmi.server.hostname=ec2-107-X-X-X.compute-1.amazonaws.com

如果您尝试自动化 EC2 实例(以及为什么不这样做),诀窍是如何在运行时找到此地址。为此,您需要在我们的应用程序引导脚本中放入类似以下内容的内容:

# get our _external_ hostname
RMI_HOST=`wget -q -O - http://169.254.169.254/latest/meta-data/public-hostname`
...
java -server \
    -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=$RMI_HOST \
    -jar foo.jar other parameters here > java.log 2>&1

上述命令中的神秘 IP 提供了 EC2 实例可以请求的有关自身的信息。我感到失望的是,这不包括仅在经过身份验证的调用中可用的标记。169.254.169.254wget

我最初使用的是外部ipv4地址,但看起来JDK在启动时会尝试与服务器端口建立连接。如果它使用外部IP,那么这会减慢我们的应用程序启动时间,直到超时。公共主机名在本地解析为 10 个网络地址,并在外部解析为公共 ipv4。因此,应用程序现在启动很快,JMX 客户端仍然可以工作。呜呼!

希望这有助于其他人。今天花了我3个小时。

要强制 JMX 服务器在指定端口上启动服务器 RMI 注册表,以便您可以在 EC2 安全组中阻止它们,请参阅以下答案:

如何关闭在特定端口上运行的rmiregistry?

编辑:

我们刚刚再次出现此问题。似乎Java JMX代码正在对盒子的主机名进行一些主机名查找,并使用它们来尝试连接和验证JMX连接。

问题似乎是要求框的本地主机名应解析为框的本地 IP。例如,如果您有,那么如果您在 上进行 DNS 查找,则应访问 10-NET 虚拟地址。我们正在生成自己的文件,并且文件中缺少本地主机的主机名。这导致我们的应用程序在启动时暂停或根本无法启动。/etc/sysconfig/networkHOSTNAME=server1.foobar.comserver1.foobar.com/etc/hosts

最后

简化 JMX 创建的一种方法是使用我的 SimpleJMX 包


答案 2

根据第二个答案 为什么 JMX 连接到 Amazon EC2 失败?,这里的困难在于默认情况下,RMI 端口是随机选择的,客户端需要同时访问 JMX 和 RMI 端口。如果运行的是 jdk7u4 或更高版本,则可以通过应用属性指定 RMI 端口。使用以下 JMX 设置启动我的服务器对我有用:

不带身份验证:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.rmi.port=9998 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Djava.rmi.server.hostname=<public EC2 hostname>

使用身份验证:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.rmi.port=9998 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=true 
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Djava.rmi.server.hostname=<public EC2 hostname>

我还在 EC2 安全组中为我的实例打开了端口 9998-9999。


推荐