Como ativar o JMX na minha JVM para acessar com o jconsole?

223

Como ativar o JMX em uma JVM para acessar com o jconsole?

Mauli
fonte
32
é allowd, e na verdade é apenas um lembrete para mim, porque eu sempre esqueço de onde copiar os parâmetros de e agora eu sei onde encontrá-lo :-)
Mauli
20
Stack Exchange tiver usuários sempre incentivou explicitamente para responder às suas próprias perguntas, consulte aqui: stackoverflow.com/help/self-answer
Tim Buthe
11
Mais de uma vez, procurei algo no SO e encontrei uma pergunta respondida ... sozinha. E um deles foi perguntado por mim também. É por isso que é bom colocar suas próprias respostas. Além disso, pense em todas as outras pessoas que podem ter encontrado seu problema. Se você responder à sua pergunta, também as ajudará.
Mike Miller
2
Doc atualizados para Java 8 é aqui
Andrew Johnston
@Mauren: Você pode fornecer uma referência à sua pergunta fechada que você mesmo respondeu? Pode valer a pena discutir sobre o Meta.
Kevinarpe

Respostas:

290

A documentação relevante pode ser encontrada aqui:

http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html

Inicie seu programa com os seguintes parâmetros:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.rmi.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Por exemplo, assim:

java -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9010 \
  -Dcom.sun.management.jmxremote.local.only=false \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -jar Notepad.jar

-Dcom.sun.management.jmxremote.local.only=falsenão é necessariamente necessário, mas sem ele, não funciona no Ubuntu. O erro seria algo como isto:

01 Oct 2008 2:16:22 PM sun.rmi.transport. customer .TCPTransport$AcceptLoop executeAcceptLoop
WARNING: RMI TCP Accept-0: accept loop for ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=37278] throws
java.io.IOException: The server sockets created using the LocalRMIServerSocketFactory only accept connections from clients running on the host where the RMI remote objects have been exported.
    at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:89)
    at sun.rmi.transport. customer .TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:387)
    at sun.rmi.transport. customer .TCPTransport$AcceptLoop.run(TCPTransport.java:359)
    at java.lang.Thread.run(Thread.java:636)

consulte http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6754672

Também tenha cuidado com o-Dcom.sun.management.jmxremote.authenticate=false que torna o acesso disponível para qualquer pessoa, mas se você o usar apenas para rastrear a JVM em sua máquina local, isso não importa.

Atualização :

Em alguns casos, não consegui acessar o servidor. Isso foi corrigido se eu definir esse parâmetro também:-Djava.rmi.server.hostname=127.0.0.1

Mauli
fonte
9
O -Dcom.sun.management.jmxremote.local.only = false é necessária no CentOS, bem como agora
LenW
1
Nit pick: é estranho para mim que com.sun.management.jmxremotetenha o valor padrão como true. (Obrigado, Sun!) Para ser super claro, especialmente para aqueles menos familiarizados com os nobs JMX, eu uso: com.sun.management.jmxremote=trueRef: docs.oracle.com/javase/8/docs/technotes/guides/management/…
kevinarpe
1
"-Djava.rmi.server.hostname" funcionou como um encanto para mim!
precisa saber é o seguinte
1
definir o nome do host como localhost é muito importante se você estiver tentando conectar um a um servidor remoto através do túnel SSH, que é um caso muito comum.
Nikhil Owalekar
1
Isso funciona apenas se eu desativar o firewall no servidor. Abri a porta 9010 / tcp neste exemplo, é claro, também tentei adicionar Dcom.sun.management.jmxremote.rmi.port=9011e abrir no firewall - ainda não consigo conectar com o firewall ativo. Alguma ideia? Perdi alguma coisa?
Carmageddon
70

A execução em um contêiner do Docker introduziu uma série de problemas adicionais para conexão, por isso espero que isso ajude alguém. Acabei precisando adicionar as seguintes opções que explicarei abaixo:

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=${DOCKER_HOST_IP}
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9998

DOCKER_HOST_IP

Ao contrário do jconsole localmente, você deve anunciar um IP diferente do que provavelmente verá no contêiner. Você precisará substituir ${DOCKER_HOST_IP}pelo IP (nome DNS) externamente resolvível do seu host do Docker.

Portas remotas e RMI JMX

Parece que o JMX também requer acesso a uma interface de gerenciamento remoto ( jstat ) que usa uma porta diferente para transferir alguns dados ao arbitrar a conexão. Não vi nenhum lugar imediatamente óbvio jconsolepara definir esse valor. No artigo vinculado, o processo foi:

  • Experimente e conecte-se jconsolecom o log ativado
  • Falhou
  • Descobrir qual porta jconsoletentou usar
  • Use iptables/ firewallrules conforme necessário para permitir que a porta se conecte

Enquanto isso funciona, certamente não é uma solução automatizável. Optei por uma atualização do jconsole para o VisualVM, pois permite especificar explicitamente a porta na qual jstatdestá sendo executada. No VisualVM, adicione um novo host remoto e atualize-o com valores que se correlacionam com os especificados acima:

Adicionar host remoto

Em seguida, clique com o botão direito do mouse na nova conexão de host remoto e Add JMX Connection...

Adicionar conexão JMX

Não se esqueça de marcar a caixa de seleção Do not require SSL connection. Felizmente, isso deve permitir que você se conecte.

Joel B
fonte
-Djava.rmi.server.hostname=localhost -Dcom.sun.management.jmxremote.rmi.port=[...]é também a chave no caso de tunelamento JMX / RMI através do SSH. Sem eles, os objetos remotos são acessados ​​usando o IP público / principal / ... do servidor usando alguma porta aleatória, que não pode ser encaminhada facilmente.
Thorsten Schöning
1
Posso confirmar que você realmente precisa usar o IP externo ao contêiner. Por exemplo, ele não funciona com-Djava.rmi.server.hostname=0.0.0.0
raisercostin 19/05/19
Eu não tinha necessidade de usar DOCKER_HOST_IPem qualquer lugar - Eu apenas usei localhoste transmitiu as portas ao executar a imagem janela de encaixe: -p 9998:9998, -p 9999:9999etc.
Barney
9

Observe que o Java 6 na versão mais recente permite que o jconsole se conecte a um processo em execução, mesmo depois de ter sido iniciado sem os encantamentos do JMX.

Se isso estiver disponível, considere também o jvisualvm, pois fornece uma grande quantidade de informações sobre os processos em execução, incluindo um criador de perfil.

Thorbjørn Ravn Andersen
fonte
3
Isso funciona apenas se você estiver executando o jconsole no mesmo host que a JVM que você está tentando monitorar.
cinza
1
@ Thorbjorn Se eu iniciar o meu programa java sem nenhum parâmetro e tentar conectar-me ao jconsole, vejo o meu programa na lista, mas quando tento conectar, ele falha. Eu acho que é por falta de certificados SSL. Eu só queria ver a demonstração, portanto, tive que usar os parâmetros especificados na resposta pelo usuário3013578 e funcionou para mim (JDK 1.7, Windows 8.1, 64 bits).
Capitão Jack Sparrow
2
A API de conexão requer que o jconsole tenha a mesma JVM de 32/64 bits que o programa iniciado em algumas plataformas.
Thorbjørn Ravn Andersen
1
É possível desativar esse comportamento?
Kevinarpe
7

Estou usando o WAS ND 7.0

Minha JVM precisa que todos os seguintes argumentos sejam monitorados no JConsole

    -Djavax.management.builder.initial= 
    -Dcom.sun.management.jmxremote 
    -Dcom.sun.management.jmxremote.port=8855 
    -Dcom.sun.management.jmxremote.authenticate=false 
    -Dcom.sun.management.jmxremote.ssl=false
user3013578
fonte
Sim sua resposta funcionou para mim (JDK 1.7, o Windows 8.1 de 64 bits)
Capitão Jack Sparrow
6

No Linux, usei os seguintes parâmetros:

-Djavax.management.builder.initial= 
-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9010 
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false

e também editei /etc/hostspara que o nome do host resolva para o endereço do host (192.168.0.x) em vez do endereço de loopback (127.0.0.1)

alex.pulver
fonte
2

Execute seu aplicativo java com os seguintes parâmetros de linha de comando:

-Dcom.sun.management.jmxremote.port=8855
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

É importante usar o parâmetro -Dcom.sun.management.jmxremote.ssl = false se você não desejar configurar certificados digitais no host jmx.

Se você iniciou seu aplicativo em uma máquina com o endereço IP 192.168.0.1 , abra o jconsole , coloque 192.168.0.1:8855 no campo Processo Remoto e clique em Conectar .

Wasif
fonte
Qual é o comportamento esperado se você esquecer -Dcom.sun.management.jmxremote.ssl=false? Deveria jconsolemostrar um erro ou apenas falharia discretamente na conexão?
precisa saber é
2

junto com os parâmetros de linha de comando abaixo,

-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Às vezes, nos servidores linux, a conexão imx não é bem-sucedida. isso ocorre porque, no host linux na nuvem, em / etc / hosts, para que o nome do host seja resolvido no endereço do host.

a melhor maneira de corrigi-lo é fazer o ping do servidor linux específico de outra máquina na rede e usar esse endereço IP do host no

-Djava.rmi.server.hostname=IP address that obtained when you ping that linux server.

Mas nunca confie no endereço ip que você obtém do servidor linux usando o ifconfig.me. o ip que você chegar lá é mascarado e está presente no arquivo host.

Phani Kumar
fonte
1

Primeiro, você precisa verificar se o seu processo java já está em execução com os parâmetros JMX. Faça isso:

ps -ef | grep java

Verifique seu processo java que você precisa monitorar. Se você puder ver o parâmetro jmx rmi Djmx.rmi.registry.port = xxxx , use a porta mencionada aqui em seu java visualvm para conectá-lo remotamente sob conexão jmx.

Se não estiver executando através da porta jmx rmi, será necessário executar o processo java com os parâmetros abaixo mencionados:

-Djmx.rmi.registry.port=1234 -Djmx.rmi.port=1235 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

Nota: os números de porta são baseados em sua escolha.

Agora você pode usar essa porta para a conexão jmx. Aqui é porto 1234.

Abhay S
fonte
Você deve conseguir ver a porta 1234 em uso pela jmx depois de executar isso? sudo lsof -i:1234não está mostrando nada para mim
Gorgon_Union
1

Etapa 1: execute o aplicativo usando os seguintes parâmetros.

-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false

Os argumentos acima vinculam o aplicativo à porta 9999.

Etapa 2: Inicie o jconsole executando o comando jconsole no prompt de comando ou no terminal.

Selecione 'Processo remoto:' e digite o URL como {Endereço_IP}: 9999 e clique no botão Conectar para conectar-se ao aplicativo remoto.

Você pode consultar este link para obter a aplicação completa.

Hari Krishna
fonte