Wywołanie metody JMX MBean ze skryptu powłoki

98

Czy są jakieś biblioteki, które pozwoliłyby mi wywołać metodę JMX MBean ze skryptu powłoki? Udostępniamy niektóre operacje / polecenia administratora za pośrednictwem JMX i moglibyśmy poprosić administratorów o używanie JConsole lub VisualVM, ale niektóre zadania lepiej pozostawić automatyzacji. W tej automatyzacji chcielibyśmy móc wywołać metodę JMX MBean na naszym uruchomionym serwerze, najlepiej ze skryptu powłoki.

Dougnukem
źródło

Odpowiedzi:

106

Dostępne są następujące narzędzia JMX wiersza poleceń:

  1. jmxterm - wydaje się być najbardziej funkcjonalnym narzędziem.
  2. cmdline-jmxclient - użyty w projekcie WebArchive wydaje się być bardzo nagim szkieletem (i wygląda na to, że nie jest rozwijany od 2006 roku)
  3. Skrypt Groovy i JMX - zapewniają naprawdę potężną funkcjonalność JMX, ale wymagają groovy i innej konfiguracji biblioteki.
  4. Funkcjonalność wiersza poleceń JManage - (wadą jest to, że wymaga działającego serwera JManage do wykonywania poleceń proxy)

Przykład Groovy JMX:

import java.lang.management.*
import javax.management.ObjectName
import javax.management.remote.JMXConnectorFactory as JmxFactory
import javax.management.remote.JMXServiceURL as JmxUrl

def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:9003/jmxrmi'
String beanName = "com.webwars.gameplatform.data:type=udmdataloadsystem,id=0"
def server = JmxFactory.connect(new JmxUrl(serverUrl)).MBeanServerConnection
def dataSystem = new GroovyMBean(server, beanName)

println "Connected to:\n$dataSystem\n"

println "Executing jmxForceRefresh()"
dataSystem.jmxForceRefresh();

Przykład cmdline-jmxclient:

Jeśli masz

  • MBean: com.company.data:type=datasystem,id=0

Z operacją o nazwie:

  • jmxForceRefresh ()

Następnie możesz napisać prosty skrypt bash (zakładając, że pobierzesz cmdline-jmxclient-0.10.3.jar i umieścisz w tym samym katalogu co skrypt):

#!/bin/bash

cmdLineJMXJar=./cmdline-jmxclient-0.10.3.jar
user=yourUser
password=yourPassword
jmxHost=localhost
port=9003

#No User and password so pass '-'
echo "Available Operations for com.company.data:type=datasystem,id=0"
java -jar ${cmdLineJMXJar} ${user}:${password} ${jmxHost}:${port} com.company.data:type=datasystem,id=0

echo "Executing XML update..."
java -jar ${cmdLineJMXJar} - ${jmxHost}:${port} com.company.data:type=datasystem,id=0 jmxForceRefresh
Dougnukem
źródło
jmxterm nie działa w Javie 7 bugs.launchpad.net/jmxterm/+bug/942693
artbristol
19

Opracowałem jmxfuse, który eksponuje JMX Mbeans jako system plików Linux FUSE z podobną funkcjonalnością jak / proc fs. Opiera się na Jolokii jako pomoście do JMX. Atrybuty i operacje są udostępniane do odczytu i zapisu.

http://code.google.com/p/jmxfuse/

Na przykład, aby odczytać atrybut:

me@oddjob:jmx$ cd log4j/root/attributes
me@oddjob:jmx$ cat priority

napisać atrybut:

me@oddjob:jmx$ echo "WARN" > priority

wywołać operację:

me@oddjob:jmx$ cd Catalina/none/none/WebModule/localhost/helloworld/operations/addParameter
me@oddjob:jmx$ echo "myParam myValue" > invoke
Alastair McCormack
źródło
12

Wtyczki Syabru Nagios JMX jest przeznaczona do stosowania z Nagios, ale nie wymaga Nagios i jest bardzo wygodne do użycia wiersza poleceń:

~$ ./check_jmx -U service:jmx:rmi:///jndi/rmi://localhost:1099/JMXConnector --username myuser --password mypass -O java.lang:type=Memory -A HeapMemoryUsage -K used 
JMX OK - HeapMemoryUsage.used = 445012360 | 'HeapMemoryUsage used'=445012360;;;;
Austin Mills
źródło
To jest świetne i bardzo szybkie. Około 0,3 sekundy, aby zwrócić wartość w porównaniu z 3 sekundami dla jmxterm
sivann
9

Potencjalnie najłatwiej jest napisać to w Javie

import javax.management.*;
import javax.management.remote.*;

public class JmxInvoke {

    public static void main(String... args) throws Exception {

        JMXConnectorFactory.connect(new JMXServiceURL(args[0]))
            .getMBeanServerConnection().invoke(new ObjectName(args[1]), args[2], new Object[]{}, new String[]{})


    }

}

Skompilowałoby się to do pojedynczej klasy i nie wymaga żadnych zależności w serwerze ani żadnego skomplikowanego pakietu maven.

nazwij to z

javac JmxInvoke.java
java -cp . JmxInvoke [url] [beanName] [method]
teknopaul
źródło
4

Trochę ryzykowne, ale możesz uruchomić polecenie curl POST z wartościami z formularza z konsoli JMX, jego adresem URL i uwierzytelnianiem http (jeśli jest wymagane):

curl -s -X POST --user 'myuser:mypass'
  --data "action=invokeOp&name=App:service=ThisServiceOp&methodIndex=3&arg0=value1&arg1=value1&submit=Invoke"
  http://yourhost.domain.com/jmx-console/HtmlAdaptor

Uwaga: indeks metody może ulec zmianie wraz ze zmianami w oprogramowaniu. Implementacja formularza internetowego może się zmienić.

Powyższe jest oparte na źródle strony usługi JMX dla operacji, którą chcesz wykonać:

http://yourhost.domain.com/jmx-console/HtmlAdaptor?action=inspectMBean&name=YourJMXServiceName

Źródło formularza:

form method="post" action="HtmlAdaptor">
   <input type="hidden" name="action" value="invokeOp">
   <input type="hidden" name="name" value="App:service=ThisServiceOp">
   <input type="hidden" name="methodIndex" value="3">
   <hr align='left' width='80'>
   <h4>void ThisOperation()</h4>
   <p>Operation exposed for management</p>
    <table cellspacing="2" cellpadding="2" border="1">
        <tr class="OperationHeader">
            <th>Param</th>
            <th>ParamType</th>
            <th>ParamValue</th>
            <th>ParamDescription</th>
        </tr>
        <tr>
            <td>p1</td>
           <td>java.lang.String</td>
         <td> 
            <input type="text" name="arg0">
         </td>
         <td>(no description)</td>
        </tr>
        <tr>
            <td>p2</td>
           <td>arg1Type</td>
         <td> 
            <input type="text" name="arg1">
         </td>
         <td>(no description)</td>
        </tr>
    </table>
    <input type="submit" value="Invoke">
</form>
BBay
źródło
Zaimplementowałem to w ten sposób z Java za pomocą a HttpURLConnectioni mogę potwierdzić, że działa. (przy okazji submit=Invokejest niepotrzebne)
tom
czy można opisać, jak to działa? Mam na myśli, że domyślnie używa jmx rmii tam widzę http. Czy to oznacza, że ​​serwer musi być skonfigurowany do obsługi żądań JMX http?
Psychozoic
3

Spójrz na JManage . Jest w stanie wykonywać metody MBean i pobierać / ustawiać atrybuty z wiersza poleceń .

ChssPly76
źródło
Jedynym minusem jest użycie narzędzia wiersza poleceń, które wymaga uruchomienia JManage do poleceń proxy na serwerach JMX. Wolałbym bardziej lekkie podejście bezpośrednio do samego serwera JMX.
Dougnukem
3

Możesz również rzucić okiem na jmx4perl . Zapewnia dostęp bez języka Java do komponentów MBean zdalnego serwera Java EE Server. Jednak na platformie docelowej należy zainstalować mały serwlet agenta, który zapewnia spokojny dostęp JMX przez HTTP z ładunkiem JSON. (Wersja 0.50 doda tryb bezagentowy poprzez implementację proxy JSR-160).

Zalety to szybki czas uruchamiania w porównaniu z uruchamianiem lokalnej maszyny JVM Java i łatwość obsługi. jmx4perl zawiera pełny zestaw modułów Perla, które można łatwo wykorzystać we własnych skryptach:

use JMX::Jmx4Perl;
use JMX::Jmx4Perl::Alias;   # Import certains aliases for MBeans

print "Memory Used: ",
      JMX::Jmx4Perl
          ->new(url => "http://localhost:8080/j4p")
          ->get_attribute(MEMORY_HEAP_USED);

Możesz także użyć aliasu dla typowych kombinacji MBean / Attribute / Operation (np. Dla większości MXBean). Dodatkowe funkcje (wtyczka Nagios, dostęp podobny do XPath do złożonych typów atrybutów, ...) można znaleźć w dokumentacji jmx4perl.

Roland Huß
źródło
1

@Dougnukem odpowiedź bardzo mi pomogła. Przyjąłem podejście Groovy (używając groovy 2.3.3).

Zrobiłem kilka zmian w kodzie Dougnukem. To zadziała z Javą 7 i wydrukuje dwa atrybuty na standardowe wyjście co 10 sekund.

        package com.my.company.jmx
        import groovy.util.GroovyMBean;
        import javax.management.remote.JMXServiceURL
        import javax.management.remote.JMXConnectorFactory
        import java.lang.management.*

            class Monitor {
                static main(args) {
                    def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:5019/jmxrmi'
                    String beanName = "Catalina:type=DataSource,class=javax.sql.DataSource,name=\"jdbc/CommonDB\""
                    println  "numIdle,numActive"

                    while(1){
                        def server = JMXConnectorFactory.connect(new JMXServiceURL(serverUrl))
                       //make sure to reconnect in case the jvm was restrated 
                        server.connect()
                        GroovyMBean mbean = new GroovyMBean(server.MBeanServerConnection, beanName)
                        println  "${mbean.numIdle},${mbean.numActive}"
                        server.close()
                        sleep(10000)
                    }

                }
            }

Skompiluj ten kod do pliku jar za pomocą wtyczki maven-compiler-plugin, więc nie będziesz potrzebować groovy instalacji tylko groovy-all.jar. Poniżej znajduje się odpowiednia definicja i zależności wtyczki.

   <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>2.8.0-01</version>
                    </dependency>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-batch</artifactId>
                        <version>2.3.4-01</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.3</version>
        </dependency>
    </dependencies>

Owiń go nietoperzem lub muszlą, a wydrukuje dane na standardowe wyjście.

Haim Raman
źródło
0

Nie jestem pewien co do środowiska podobnego do basha. Możesz wypróbować kilka prostych programów opakowujących w Javie (z argumentami programów), które wywołują komponenty MBean na zdalnym serwerze. Następnie możesz wywołać te opakowania ze skryptu powłoki

Jeśli możesz użyć czegoś takiego jak Python lub Perl, możesz być zainteresowany JSR-262, który umożliwia eksponowanie operacji JMX za pośrednictwem usług internetowych. Jest to zaplanowane do uwzględnienia w Javie 7, ale możesz użyć kandydata do wydania implementacji referencyjnej

Kevin
źródło