Открывает ли Java 6 порт по умолчанию для удаленных соединений JMX?
Мой конкретный вопрос связан с JMX, который используется в JDK 1.6: если я запускаю процесс Java с использованием JRE 1.6 с
com.sun.management.jmxremote
в командной строке, использует ли Java порт по умолчанию для удаленных соединений JMX?
Backstory: В настоящее время я пытаюсь разработать процедуру предоставления клиенту, которая позволит им подключаться к одному из наших процессов через JMX с удаленной машины. Целью является упрощение их удаленной отладки ситуации, возникающей на консоли отображения в реальном времени. Из-за их соглашения об уровне обслуживания они сильно мотивированы для сбора как можно большего количества данных, и, если ситуация выглядит слишком сложной для исправления быстро, перезапустите консоль дисплея и позвольте ей подключиться к серверной стороне.
Мне известно, что я могу запустить jconsole для процессов JDK 1.6 и jvisualvm для процессов post-JDK 1.6.7 с физическим доступом к консоли. Однако из-за операционных требований и проблем с людьми мы настоятельно рекомендуем захватить данные, которые нам нужны удаленно, и запустить их снова.
РЕДАКТИРОВАТЬ: Мне известно свойство порта командной строки
com.sun.management.jmxremote.port=portNum
Вопрос, на который я пытаюсь ответить, - если вы не устанавливаете это свойство в командной строке, делает ли Java другой порт для удаленного мониторинга? Если да, то как вы могли бы определить, что это может быть?
Ответы
Ответ 1
Документация предполагает, что агент JMX использует локальный порт - что-то недостижимое извне машины - если вы не указали следующее свойство:
com.sun.management.jmxremote.port=portNum
Это по соображениям безопасности, а также по причине, данной г-ном Картофелем Голом. Таким образом, похоже, что Java 6 не открывает удаленный доступ по умолчанию для JMX.
EDIT: Добавлено после того, как OP добавила ответ с дополнительной информацией.
Другой вариант, который у вас есть, - это создать локальный прокси-сервер, который прослушивает все локальные соединения JMX и экспортирует эту информацию. Таким образом, вам не нужно иметь такую магическую конфигурацию для каждого экземпляра JVM на сервере. Вместо этого локальный прокси-сервер может подключаться ко всем JVM через JMX, а затем как-то разоблачать эту информацию удаленно. Я не уверен, как вы это реализуете, но что-то вроде этого может быть меньше, чем то, что вам нужно было сделать, чтобы разоблачить все ваши JVM удаленно через JMX.
Ответ 2
AFAIK,
Ниже приведены возможности подключения клиентского процесса JMX (приложения управления, например jconsole, jmxterm, mc4j, jvmstat, jmxmonitor, jps,...) к процессу сервера JMX ( агент).
Предполагается, что протокол, соединяющий JMX-клиент и JMX-сервер, является "Java RMI" (он же "RMI-JRMP" ). Это должно быть значение по умолчанию. Можно настроить другие протоколы, в частности "RMI-IIOP" и "JMXMP". Возможны специальные протоколы: проект MX4J, например, предоставляет SOAP/HTTP и различные протоколы сериализации по протоколу HTTP.
Подробнее о конфигурации см. Sun/Oracle docs.
Также посмотрите файл jre/lib/management/management.properties
в вашем дистрибутиве JDK.
Итак, возможности:
Случай 0: JVM запускается без какой-либо конкретной конфигурации
До Java 6: JVM не ведет себя как сервер JMX. Любая программа, которая запускается внутри JVM, может программно использовать JVM MBeanServer и использовать ее для проведения интересных обменов данными между потоками или для мониторинга JVM, но невозможно управление извне процесса JVM.
Так как Java 6: даже если это явно не настроено, можно получить доступ к JMX-функциям JVM локально (с той же машины), как описано в "Случай 1".
Случай 1: JVM запускается с -Dcom.sun.management.jmxremote
JVM настроен на работу как локальный (только для одного) JMX-сервер.
В этом случае (и в принципе только для Sun/Oracle JVM) клиент JMX может подключаться к серверу JMX через файлы с отображением памяти, найденные в /tmp/hsperfdata_[user]
. Об этом говорится в документации Sun и называется "локальный мониторинг" (а также Attach API). Он не работает в файловых системах FAT, так как разрешения там не могут быть установлены правильно. См. эту запись в блоге.
Sun рекомендует запускать jconsole
на машине, отдельно от сервера JMX, поскольку jconsole
, по-видимому, является ресурсоемкой, поэтому этот "локальный мониторинг" не обязательно является хорошей идеей.
Локальный мониторинг, однако, довольно безопасен, он доступен только локально и легко управляется с разрешениями файловой системы.
Случай 2: Сервер JMX запускается с -Dcom.sun.management.jmxremote.port=[rmiregistryport]
JVM настроен на работу в качестве сервера JMX, прослушивающего несколько портов TCP.
Порт, указанный в командной строке, будет выделен JVM, и там будет доступен реестр RMI. В реестре размещается коннектор с именем "jmxrmi". Он указывает на второй, случайно распределенный TCP-порт ( "эфемерный" порт), на котором прослушивается сервер RMI JMX и через который происходит фактический обмен данными.
Локальный, как описано в "Случай 1", всегда включен в "Случай 2".
Сервер JMX по умолчанию прослушивает все интерфейсы, поэтому вы можете подключиться к нему (и управлять им), локально подключившись к 127.0.0.1:[rmiregistryport], а также дистанционно подключиться к [любому внешнему IP-адресу]: [некоторые порт] удаленно.
Это означает, что вы должны смотреть на последствия безопасности. Вы можете заставить JVM прослушивать 127.0.0.1:[rmiregistryport], только установив -Dcom.sun.management.jmxremote.local.only=true
.
Очень жаль, что нельзя указать, где будет выделен эфемерный порт - он всегда выбирается случайным образом при запуске. Это может означать, что ваш брандмауэр должен стать швейцарским сыном проклятых! Тем не менее, обходные пути. В частности, Apache Tomcat устанавливает эфемерный порт сервера JMX RMI через его JMX Remote Lifecycle Listener. Код для выполнения этой маленькой магии можно найти на org.apache.catalina.mbeans.JmxRemoteLifecycleListener.
Если вы используете этот метод, вы также можете убедиться, что:
- Клиент JMX должен аутентифицироваться на сервере JMX.
- Обмен TCP между клиентом и сервером шифруется с помощью SSL
Как это делается, описано в документации Sun/Oracle
Другие подходы
Вы можете делать интересные перестановки, чтобы не использовать протокол RMI. В частности, вы можете добавить к вашему процессу механизм сервлетов (например, Jetty). Затем добавьте сервлеты, которые транслируют некоторый обмен через HTTP на внутреннем уровне в прямой доступ к JVM MBeanServer
. Тогда вы были бы в "случае 0", но все же имели возможности управления, возможно, через интерфейс на основе HTML. JBoss JMX Console является примером этого.
Больше не по теме, вы можете напрямую использовать SNMP (что-то, чего я не пробовал) в соответствии с этот документ.
Показать и рассчитать время
И теперь настало время для некоторого кода, чтобы проиллюстрировать обмен JXM. Мы берем вдохновение из учебника Sunoracle.
Это работает в Unix. Мы используем JVM, который настроен как сервер JMX, используя:
-Dcom.sun.management.jmxremote.port=9001
Мы используем lsof
для проверки того, какие порты TCP он держит открытым:
lsof -p <processid> -n | grep TCP
Нужно увидеть что-то вроде этого: порт реестра и эфемерный порт:
java 1068 user 127u IPv6 125614246 TCP *:36828 (LISTEN)
java 1068 user 130u IPv6 125614248 TCP *:9001 (LISTEN)
Мы используем tcpdump
для проверки обмена пакетами между клиентом JMX и сервером JMX:
tcpdump -l -XX port 36828 or port 9001
В домашнем каталоге мы установили файл .java.policy
, чтобы позволить удаленному подключению клиента:
grant {
permission java.net.SocketPermission
"<JMX server IP address>:1024-65535", "connect,resolve";
};
И тогда мы можем запустить это и посмотреть, что произойдет:
package rmi;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.management.remote.rmi.RMIConnection;
import javax.management.remote.rmi.RMIServer;
public class Rmi {
public static void main(String args[]) throws Exception {
// We need a Security Manager (not necessarily an RMISecurityManager)
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
//
// Define a registry (this is just about building a local data structure)
//
final int comSunManagementJmxRemotePort = 9001;
Registry registry = LocateRegistry.getRegistry("<JMX server IP address>", comSunManagementJmxRemotePort);
//
// List registry entries. The client connects (using TCP) to the server on the
// 'com.sun.management.jmxremote.port' and queries data to fill the local registry structure.
// Among others, a definition for 'jmxrmi' is obtained.
//
System.out.print("Press enter to list registry entries");
System.in.read();
String[] names = registry.list();
for (String name : names) {
System.out.println("In the registry: " + name);
}
//
// 'Looking up' the entry registered under 'jmxrmi' involves opening and tearing down
// a TCP connection to the 'com.sun.management.jmxremote.port', as well as a TCP
// connection to an ephemeral secondary port chosen at server startup.
// The actual object locally obtained is a "javax.management.remote.rmi.RMIServerImpl_Stub"
// indicating where the ephemeral port is.
// "RMIServerImpl_Stub[UnicastRef [liveRef: [endpoint:[$IP:$EPHEMERAL_PORT](remote),objID:[-62fb4c1c:131a8c709f4:-7fff, -3335792051140327600]]]]"
//
System.out.print("Press enter to get the 'jmxrmi' stub");
System.in.read();
RMIServer jmxrmiServer = (RMIServer)registry.lookup("jmxrmi");
System.out.println(jmxrmiServer.toString());
//
// Now get a "RMI Connection" to the remote. This involves setting up and tearing
// down a TCP connection to the ephemeral port.
//
System.out.print("Press enter to get the 'RMIConnection'");
System.in.read();
RMIConnection rcon = jmxrmiServer.newClient(null);
//
// Ask away. This involves setting up and tearing
// down a TCP connection to the ephemeral port.
//
System.out.print("Press enter to get the 'domains'");
System.in.read();
for (String domain : rcon.getDomains(null)) {
System.out.println("Domain: " + domain);
}
//
// Ok, that will do. For serious applications, we better use the higher-level JMX classes
//
}
}
Ответ 3
На самом деле есть недокументированное свойство, которое можно использовать для принудительного создания JMX-соединений с дистанционным доступом на случайных номерах портов.
-Dcom.sun.management.jmxremote.authenticate="false"
-Dcom.sun.management.jmxremote="true"
-Dcom.sun.management.jmxremote.ssl="false"
-Dcom.sun.management.jmxremote.port="0"
-Dcom.sun.management.jmxremote.local.only="false"
Последние два свойства имеют наибольшее значение.
Ответ 4
Документация указывает, что агент JMX использует локальный эфемерный порт , если не указать следующее: свойство:
com.sun.management.jmxremote.port=portNum
Порты по умолчанию исключаются из-за того, что в одной системе может быть много java-приложений, и если бы был порт по умолчанию, можно было бы управлять только одним приложением! Вышеупомянутое свойство конфигурации предоставляется для экспресс-цели удаленного управления.
Если вы должны настаивать на использовании эфемерного порта, тогда URL-адрес агента JMX должен быть доступен из JVM через следующее системное свойство (хотя это, скорее всего, локальный адрес):
com.sun.management.jmxremote.localConnectorAddress
Примечание. Я думаю, вы всегда можете открыть сокет на удаленном доступном адресе и запросах прокси на локальный сокет, но использование доступного параметра кажется гораздо более привлекательным!
Ответ 5
Итак, короткий ответ на мой вопрос - "нет".
Однако интересно узнать, почему. Посмотрите на вывод netstat
из действительного локального соединения. Вот порты, которые я вижу, открываются в результате того, что jconsole
делает локальное подключение к себе. Как вы можете видеть, порт 1650 является локальным портом, используемым для информации JMX:
Proto Local Address Foreign Address State
TCP Gandalf:1650 Gandalf:1652 ESTABLISHED
TCP Gandalf:1650 Gandalf:1653 ESTABLISHED
TCP Gandalf:1650 Gandalf:1654 ESTABLISHED
TCP Gandalf:1650 Gandalf:1655 ESTABLISHED
TCP Gandalf:1650 Gandalf:1656 ESTABLISHED
TCP Gandalf:1652 Gandalf:1650 ESTABLISHED
TCP Gandalf:1653 Gandalf:1650 ESTABLISHED
TCP Gandalf:1654 Gandalf:1650 ESTABLISHED
TCP Gandalf:1655 Gandalf:1650 ESTABLISHED
TCP Gandalf:1656 Gandalf:1650 ESTABLISHED
Однако этого недостаточно, чтобы попытаться подключить jconsole
к localhost:1650
. К сожалению, все, что будет чистым, это сообщение "Connection failed: no such object in table".
Итак, вывод моей первоначальной истории заключается в том, что если мы будем способствовать удаленному мониторингу с помощью JMX для наших клиентов, нам действительно нужно идентифицировать уникальные отдельные порты удаленного доступа для различных процессов Java, которые запускаются в нашей системе, К счастью, все это требует разумного использования аргумента VM:
com.sun.management.jmxremote.port=portNum
где мы почти наверняка будем иметь последовательный предварительно заданный диапазон portNum
, чтобы клиент мог выбрать правильное удаленное приложение, используя номер порта.
Ответ 6
Недавно я работал, чтобы выяснить, как включить удаленное управление JMX из Java-кода, не требуя запуска JVM со специальными наборами свойств. Решением, на котором я остановился, является запуск собственного частного реестра RMI - достаточно просто - и выставить службу JMX в этом реестре. Я создаю свой собственный MBeanServer, а затем создаю новый JMXConnectorServer. JMXConnectorServer создается с помощью вызова типа
connector = JXMConnectorServerFactory.newJMXConnectorServer(url, null, server);
Где сервер - MBeanServer, а url - экземпляр JMXServiceURL.
URL-адрес имеет форму "service: jmx: rmi:///jndi/rmi://localhost:/jmxrmi", где port является (локальным) номером порта частного реестра. "jmxrmi" - это стандартное имя службы для службы JMX.
После установки этого и начала подключения я обнаружил, что могу подключиться к нему из jconsole с помощью имени узла: port.
Это полностью удовлетворяет мои потребности; Мне будет интересно узнать, видит ли кто-то недостаток в этом подходе.
Ссылка: JMX Tutorial, Chap. 3
Ответ 7
Если вы запускаете приложение на сервере приложений Glassfish, просто запустите следующую команду asadmin, вам нужно будет перезапустить все запущенные серверы, чтобы изменения повлияли на них.
./asadmin enable-secure-admin
Существуют дополнительные конфигурации сервера Glassfish для дальнейшего обеспечения безопасности, более подробно см. Подключение удаленно к Glassfish через JMX.