簡體   English   中英

如何讓 JMX 綁定到特定接口?

[英]How to have JMX bind to a specific interface?

我目前正在使用com.sun.management.jmxremote.*屬性啟動我的 Java VM,以便我可以通過 JConsole 連接到它以進行管理和監視。 不幸的是,它會監聽機器上的所有接口(IP 地址)。

在我們的環境中,經常會出現一台機器上同時運行多個 Java VM 的情況。 雖然可以告訴 JMX 監聽不同的 TCP 端口(使用com.sun.management.jmxremote.port ),但最好讓 JMX 使用標准 JMX 端口並綁定到特定的 IP 地址(而不是所有地址)其中)。

這將使確定我們通過 JConsole 連接到哪個 VM 變得容易得多(因為每個 VM 實際上“擁有”自己的 IP 地址)。 有沒有人想出如何讓 JMX 監聽單個 IP 地址或主機名?

如果其他人會因為這個而失去神經...... 10年后,他們終於解決了!

由於 Java 8u102 -Dcom.sun.management.jmxremote.host綁定到所選 IP

見: https : //bugs.openjdk.java.net/browse/JDK-6425769

Fernando 已經提供了我的博客文章的鏈接:) ..這不是微不足道的。 您必須提供自己的 RMIServerSocketFactoryImpl 以在所需地址上創建套接字。

如果內部/外部接口是問題並且您具有本地訪問權限,則設置本地防火牆可能會更容易。

我沒有試過這個,但這可能會有所幫助。

這里的主要麻煩是沒有簡單的方法來指定 JMX 綁定到的主機 IP 地址,它總是綁定到所有接口。 'java.rmi.server.hostname' 屬性不起作用,我不想為同一主機上的所有不同實例選擇不同的端口。

此外,我不想創建自己的 RMIServerSocketFactory 並具有與之相關的所有復雜性,我正在對現有代碼進行簡單的修補。

我通過修補負責創建此服務器套接字的默認 JVM RMI 套接字工廠來解決此問題。 它現在支持新的“com.sun.management.jmxremote.host”屬性。

要使其工作,請將下面的 Java 代碼保存到名為 sun/rmi/transport/proxy/RMIDirectSocketFactory.java 的文件中。

從中編譯並創建 jmx_patch.jar 並將其放入 tomcat lib/ 文件夾中。

然后,您需要將以下行添加到 bin/setenv.sh:

類路徑=$類路徑:$CATALINA_HOME/lib/mx_patch.jar

在tomcat實例啟動時添加這個選項

-Dcom.sun.management.jmxremote.host=192.168.100.100"

這將僅將 JMX 服務綁定到地址 192.168.100.100。 其他 2 個隨機 RMI 偵聽端口仍將綁定到所有接口,但這很好,因為無論如何它們總是會選擇一個空閑端口。

您現在可以在單個主機上運行多個 tomcat 實例,並且所有默認端口都完好無損(例如,對於所有這些端口,JMX 為 8080)。

package sun.rmi.transport.proxy;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.server.RMISocketFactory;

public class RMIDirectSocketFactory extends RMISocketFactory {

    public Socket createSocket(String host, int port) throws IOException
    {
     return new Socket(host, port);
    }

   public ServerSocket createServerSocket(int port) throws IOException
   {
   String jmx_host = System.getProperty("com.sun.management.jmxremote.host");
   String jmx_port = System.getProperty("com.sun.management.jmxremote.port");

  // Allow JMX to bind to specific address
  if (jmx_host != null && jmx_port != null && port != 0 && integer.toString(port).equals(jmx_port)) {
    InetAddress[] inetAddresses = InetAddress.getAllByName(jmx_host);
    if (inetAddresses.length > 0) {
    return new ServerSocket(port, 50, inetAddresses[0]);
   }
}

 return new ServerSocket(port);
  }

}

當僅使用com.sun.management.jmxremote.host而不更改com.sun.management.jmxremote.ssl (默認為true )或com.sun.management.jmxremote.registry.ssl (默認為false )時,它仍將綁定到com.sun.management.jmxremote.port所有接口,並將僅將com.sun.management.jmxremote.host用於com.sun.management.jmxremote.rmi.port (默認為隨機端口)。 不知道為什么會這樣,它看起來像一個錯誤。 對於這些jmxremote.ssljmxremote.registry.ssl值的任何其他組合,它將為兩個端口正確使用給定的jmxremote.host

例如,與

  -Dcom.sun.management.jmxremote.authenticate=false
  -Dcom.sun.management.jmxremote.port=1234
  -Dcom.sun.management.jmxremote.host=interface1
  

它仍然會綁定到端口1234所有接口,並且只綁定到interface1的隨機jmxremote.rmi.port

請注意,JMX 客戶端首先連接到jmxremote.port ,這是一個 RMI 注冊中心,通過它接收實際的 JMX 服務器端口jmxremote.rmi.port ,因此客戶端仍然只能通過jmxremote.host接口。 然而,仍然不希望 RMI 注冊表監聽所有接口,因為當不同的 VM 以相同的jmxremote.port值啟動時,這將導致端口沖突,就像這個問題中的場景一樣。

您至少需要設置com.sun.management.jmxremote.{host,port,ssl} ,盡管com.sun.management.jmxremote.host沒有記錄在案,但它至少在 OpenJDK 1.8.0_312 中有效。

您(很可能)還需要設置java.rmi.server.hostname 請記住,JMX 客戶端首先連接到 jmxremot 主機和端口,然后從那里獲取 RMI 主機和端口,最后將通過 RMI 連接到該主機和端口,如果您沒有設置java.rmi.server.hostname jmx 客戶端將獲得的主機(ip)將沒有該端口的任何偵聽器(因為您只在 127.0.0.1 上偵聽)

這是一個有效的示例,而不是我還禁用了身份驗證並強制使用 IPv4:

/usr/lib/jvm/java-8-openjdk-amd64//bin/java \
-Dcom.sun.management.jmxremote.host=127.0.0.1  \
-Djava.rmi.server.hostname=127.0.0.1 \
-Dcom.sun.management.jmxremote.port=2222 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.registry.ssl=false  \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.net.preferIPv4Stack=true \
-jar your-uber.jar
  

來自 .netstat 的 output 確認端口 222 僅綁定到 127.0.0.1 而不是 0.0.0.0:

netstat -plnt|grep 2222
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:2222          0.0.0.0:*               LISTEN      15390/java

我剛試過

-Dcom.sun.management.jmxremote.host=

使用 openjdk 1.8,它運行良好。 它綁定到那個地址(根據 netstat)並且一切看起來都正確(並且有效)。

接受的答案很舊。 有一些跡象表明 Java 現在提供了一些選項來實現這一點。 比如我見過:

-Djava.rmi.server.hostname=<YOUR_IP>

...也...

-Dcom.sun.management.jmxremote.host=<YOUR_IP>

但是,至少在 jdk 1.7 下的我的系統上,這些似乎沒有任何影響 - JMX 連接器仍然綁定到 *. 更新的答案(具有特定的適用版本)將不勝感激。 應該很簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM