Не удается подключиться к удаленному JMX

У меня есть приложение tomcat на удаленном хосте, и мне нужно подключить его с помощью JConsole. Приложение запускается с параметрами:

IP=`ifconfig eth0 | grep 'inet addr:' | cut -d ':' -f2 | cut -d ' ' -f1`

-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=$IP
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

Порт 9999 открыт, значение IP верное, проверил. Я могу получить к нему доступ по телнету (telnet <my_host> <my_port>). Нетстат:

netstat -a | grep LISTEN
tcp        0      0 *:9999                  *:*                     LISTEN 

Но я не могу подключить его через jconsole, я всегда получаю одну и ту же ошибку:

Connection Failed: Retry?

Но netstat -a показывает, что соединение ESTABLISHED

Пробовал разные адреса:

<my_host>:<my_port>

service:jmx:rmi://<my_host>:<my_port>/jndi/rmi://<my_host>:<my_port>/jmxrmi

service:jmx:rmi:///jndi/rmi://<my_host>:<my_port>/jmxrmi

Я также пытался добавить файлы .../conf/remote.users и .../remote.acl и прописать пути к этим файлам в свойствах -Dcom.sun.management.jmxremote.password.file и -Dcom.sun.management.jmxremote.access.file, но это не дало никакого эффекта.

Когда я развертываю это приложение на своем локальном компьютере, я могу подключиться к нему по адресу "localhost:9999".

Помогите кто-нибудь, в чем может быть проблема?


person Kirill    schedule 14.03.2016    source источник
comment
Сначала проверьте подключение с помощью команды telnet <my_host> <my_port>, если вы не можете подключиться, проверьте настройки брандмауэра между этими двумя машинами.   -  person Mahendra    schedule 14.03.2016
comment
Также повторите IP-адрес echo $IP после IP=ifconfig eth0 | grep 'inet addr:' | cut -d ':' -f2 | cut -d ' ' -f1, чтобы проверить действительное значение IP-адреса.   -  person Mahendra    schedule 14.03.2016
comment
Значение IP верное, я проверил, telnet <my_host> <my_port> работает нормально   -  person Kirill    schedule 14.03.2016
comment
Попробуйте проверить, что $IP, который вы используете, не транслируется каким-то образом в /etc/hosts машины во внутренний петлевой адрес?   -  person Avihoo Mamka    schedule 14.03.2016
comment
Нет, /etc/hosts не содержит <my_host>   -  person Kirill    schedule 14.03.2016


Ответы (3)


Если вы можете telnet <my_host> <my_port>, то проблема должна быть связана с брандмауэром, так как в JMX однократное рукопожатие выполняется на настроенном порту, т.е. затем назначается новый порт для дальнейшей связи, и, возможно, ваш брандмауэр не позволяет открыть новый порт.

Для перекрестной проверки просто попробуйте запустить ниже Java JMX Client, который попытается отобразить HeapMemoryUsage.

import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class JMXDemo {

    private static final String HOST = ""; // configure host <my_host> here
    private static final String PORT = ""; // configure port <my_port> here

    private static void testJMX() throws Exception {
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://" + HOST + "/jndi/rmi://" + HOST + ":" + PORT
                + "/jmxrmi");

        JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
        try {
            MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();

            ObjectName mbeanName = new ObjectName("java.lang:type=Memory");
            javax.management.openmbean.CompositeDataSupport obj = null;

            obj = (javax.management.openmbean.CompositeDataSupport) mbeanServerConnection.getAttribute(mbeanName,
                    "HeapMemoryUsage");
            Set<String> keySet = obj.getCompositeType().keySet();

            for (String key : keySet) {
                System.out.print(key + "=" + obj.get(key) + ", ");
            }
        } finally {
            jmxConnector.close();
        }
        System.out.println("\n==========================");
    }

    public static void main(String args[]) throws Exception {
        testJMX();
    }

}

Чтобы включить ведение журнала JMX, создайте файл logging.properties.

handlers= java.util.logging.ConsoleHandler
.level=ALL

java.util.logging.FileHandler.pattern = jmx.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

// Use FINER or FINEST for javax.management.remote.level - FINEST is
// very verbose...
//
javax.management.level=FINEST
javax.management.remote.level=FINEST

java.security.debug=all

Скомпилируйте код Java и запустите с помощью команды ниже

 java -Djava.util.logging.config.file=./logging.properties JMXDemo 

Это напечатает так много журналов на консоли, что вы можете найти «порт».

person Mahendra    schedule 14.03.2016
comment
Он заблокирован в JMXConnector jmxConnector = JMXConnectorFactory.connect(url); - person Kirill; 14.03.2016
comment
JMXConnector jmxConnector = JMXConnectorFactory.connect(url); бросает: Exception in thread "main" java.rmi.ConnectException: Connection refused to host: 192.168.123.32; nested exception is: java.net.ConnectException: Connection timed out - person Kirill; 14.03.2016
comment
Как я могу найти номер этого нового порта? - person Kirill; 14.03.2016
comment
Я пытаюсь это сделать. Для этого мы должны включить ведение журнала JMX, а также ведение журнала TCP - person Mahendra; 14.03.2016
comment
Ты прав! Это был брандмауэр. Это тестовая машина, и я могу просто выключить ее. - person Kirill; 14.03.2016
comment
Ваш пример очень помог в раскрытии моей проблемы. Я туннелировал порт JMX через SSH и предполагал, что порт RMI тоже будет туннелировать, но хост RMI, к которому он пытается подключиться, пытается обойти туннель SSH, который, конечно же, заблокирован. - person Jonathan Neufeld; 06.12.2017

Напишите простую программу на Java:

import java.util.*;
import java.io.*;

class testCode{
  public static void main(String args[]){
    System.out.println("just killing time...do not enter a value and kill me ");
    Scanner sc = new Scanner(System.in);
    sc.nextInt();
  }    
}

Скомпилируйте и запустите его со следующими параметрами:

java -Dcom.sun.management.jmxremote=true \
 -Dcom.sun.management.jmxremote.port=12345 \
 -Dcom.sun.management.jmxremote.authenticate=false \
 -Dcom.sun.management.jmxremote.ssl=false \
 -Djava.rmi.server.hostname=10.1.10.167 \
 testCode

Замените rmi.server.hostname на IP-адрес машины, на которой выполняется код Java, затем используйте jconsole для удаленного подключения к 10.1.10.167:12345. Идентификатор пользователя и пароль не требуются.

person Ajay Vijayasarathy    schedule 22.06.2017
comment
Большое спасибо! У меня несколько сетей, эта опция решила мою проблему: -Djava.rmi.server.hostname. - person hao; 20.10.2017

попробуйте все эти флаги:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 
-Djava.rmi.server.hostname=$IP

если значение Dcom.sun.management.jmxremote.local.only равно true, оно будет блокировать удаленные подключения.

person LiozM    schedule 26.03.2016