Ali outil de surveillance de diagnostic Arthas Source Principe Analyse

Le mois dernier, Ali open source de surveillance et de diagnostic outil, « Arthas », un outil en ligne peut être utilisé pour l' analyse des problèmes, les gains à court terme un de beaucoup d'attention, même sur Twitter officiel Java Twitter a également transmis, vraiment la louange .

GitHub est le readme:

Arthas est une surveillance en ligne des produits de diagnostic dans une perspective globale pour afficher des informations d'état en temps réel sur la charge de l'application, la mémoire, gc, fil, et peut, sans modifier le code d'application, les questions d'affaires diagnostic, y compris l'accès pour afficher l'appel de méthode ginseng, méthode chronophage surveillance exception, les informations de chargement de classe, d'améliorer considérablement l'efficacité de dépannage en ligne.

Je vois souvent des outils intéressants open source, vous trouverez quelques sites fonctionnels de coupe plus d'intérêt, de la source à comprendre le principe de la conception et la mise en œuvre. Pour une partie de leur propre compréhension de la réalisation des idées, puis vérifier le code source pour voir si l'idée est d'utiliser la même mise en œuvre. Si elles veulent atteindre et même, vous pourriez penser, Aha, pensa quelques semaines. Si la source est une autre application, vous aurez envie Cool, vous pouvez aussi jouer. Comme si dans le dialogue comme auteur et la source du même .

Profitant de la fête nationale et lire quelques « Arthas source », à peu près résumées ci - dessous.

A partir de la structure de paquets source peut être vu divisé en plusieurs modules principaux:

  • Agent - VM chargé Agent personnalisé

  • Client - implémentation client Telnet

  • Base - Arthas mise en œuvre de base, comprend une connexion VM, résoudre toutes sortes de commandes, etc.

  • Site - Arthas contenu de l'aide du site du livre

Je regardais les principales caractéristiques suivantes:

  • Le processus de connexion

  • Décompiler classe, obtenir le code source

  • Requête classe charge spécifiée

Le processus de connexion

Se connecter au processus spécifié, suivi le suivi et le diagnostic de la fondation . Seule la première attache au processus ci - dessus, afin d'obtenir des informations correspondant à la machine virtuelle, requête ClassLoader classes chargées et ainsi de suite.

Comment se connecter au processus?
Les lecteurs de l' outil de diagnostic similaires peuvent avoir l'impression, comme JProfile, VisualVM et d' autres outils, vous permettra de choisir un processus pour se connecter. Actionnez ensuite sur la machine virtuelle spécifiée. Par exemple, pour afficher les informations de partition mémoire correspondante, les informations de collecte des ordures mémoire, les scripts BTrace et ainsi de suite.

Nous devons d' abord penser à ce sujet, ces processus une liste des connexions disponibles, est de savoir comment la liste il?
En général , il peut être similaire  ps aux | grep java outil pour cela, ou utilise Java fourni  la jps -lv liste peut contenir le numéro de processus du contenu. Je l' ai écrit dans un article précédent, une heure de début du contenu JPS ( vous ne pouvez pas être au courant de quelques gadgets java ), derrière sa mise en œuvre, sont tous les processus Java locaux commencera à  pid comme nom de fichier stocké dans Java répertoire temporaire. Cette liste, parcourir ces fichiers peuvent sortir.

Arthas est de savoir comment faire?
Dans le script de démarrage  as.sh , le code a sur la liste des processus ci - dessous, réalisé également par jps écartera Jps de leur propre:

# check pid
    if [ -z ${TARGET_PID} ] && [ ${BATCH_MODE} = false ]; then
        local IFS_backup=$IFS
        IFS=$'\n'
        CANDIDATES=($(${JAVA_HOME}/bin/jps -l | grep -v sun.tools.jps.Jps | awk '{print $0}'))

        if [ ${#CANDIDATES[@]} -eq 0 ]; then
            echo "Error: no available java process to attach."
            # recover IFS
            IFS=$IFS_backup
            return 1
        fi

        echo "Found existing java process, please choose one and hit RETURN."

        index=0
        suggest=1
        # auto select tomcat/pandora-boot process
        for process in "${CANDIDATES[@]}"; do
            index=$(($index+1))
            if [ $(echo ${process} | grep -c org.apache.catalina.startup.Bootstrap) -eq 1 ] \
                || [ $(echo ${process} | grep -c com.taobao.pandora.boot.loader.SarLauncher) -eq 1 ]
            then
               suggest=${index}
               break
            fi
        done

Une fois le processus de sélection, il est relié à un procédé spécifié. Dans la partie de connexion , attach

# attach arthas to target jvm
# $1 : arthas_local_version
attach_jvm()
{
    local arthas_version=$1
    local arthas_lib_dir=${ARTHAS_LIB_DIR}/${arthas_version}/arthas

    echo "Attaching to ${TARGET_PID} using version ${1}..."

    if [ ${TARGET_IP} = ${DEFAULT_TARGET_IP} ]; then
        ${JAVA_HOME}/bin/java \
            ${ARTHAS_OPTS} ${BOOT_CLASSPATH} ${JVM_OPTS} \
            -jar ${arthas_lib_dir}/arthas-core.jar \
                -pid ${TARGET_PID} \
                -target-ip ${TARGET_IP} \
                -telnet-port ${TELNET_PORT} \
                -http-port ${HTTP_PORT} \
                -core "${arthas_lib_dir}/arthas-core.jar" \
                -agent "${arthas_lib_dir}/arthas-agent.jar"
    fi
}

La machine virtuelle Java attache à l'intérieur réalisé
par tools.jarl'emballage com.sun.tools.attach.VirtualMachineet  VirtualMachine.attach(pid) de cette manière à atteindre.

Il est par le bas JVMTI. Article précédent avait une simple analyse  JVMTI technique ( quand on parle de débogage, de quoi nous parlons (Debug principe de mise en œuvre) ), avant d' exécuter ou d' exécution, les charges personnalisées Agent et VM et effectuer la communication .
Dans la mise en œuvre spécifique du contenu au- dessus  de arthas-core.jar la classe principale, nous examinons le contenu spécifique:

private void attachAgent(Configure configure) throws Exception {
        VirtualMachineDescriptor virtualMachineDescriptor = null;
        for (VirtualMachineDescriptor descriptor : VirtualMachine.list()) {
            String pid = descriptor.id();
            if (pid.equals(Integer.toString(configure.getJavaPid()))) {
                virtualMachineDescriptor = descriptor;
            }
        }
        VirtualMachine virtualMachine = null;
        try {
            if (null == virtualMachineDescriptor) { // 使用 attach(String pid) 这种方式
                virtualMachine = VirtualMachine.attach("" + configure.getJavaPid());
            } else {
                virtualMachine = VirtualMachine.attach(virtualMachineDescriptor);
            }

            Properties targetSystemProperties = virtualMachine.getSystemProperties();
            String targetJavaVersion = targetSystemProperties.getProperty("java.specification.version");
            String currentJavaVersion = System.getProperty("java.specification.version");
            if (targetJavaVersion != null && currentJavaVersion != null) {
                if (!targetJavaVersion.equals(currentJavaVersion)) {
                    AnsiLog.warn("Current VM java version: {} do not match target VM java version: {}, attach may fail.",
                                    currentJavaVersion, targetJavaVersion);
                    AnsiLog.warn("Target VM JAVA_HOME is {}, try to set the same JAVA_HOME.",
                                    targetSystemProperties.getProperty("java.home"));
                }
            }

            virtualMachine.loadAgent(configure.getArthasAgent(),
                            configure.getArthasCore() + ";" + configure.toString());
        } finally {
            if (null != virtualMachine) {
                virtualMachine.detach();
            }
        }
    }

Par  VirtualMachine, vous pouvez joindre au courant pid spécifié, ou par la  VirtualMachineDescriptor réalisation du processus spécifié attache, le noyau est cette phrase:

virtualMachine.loadAgent(configure.getArthasAgent(),
                            configure.getArthasCore() + ";" + configure.toString());

Ainsi, VM et spécifier le processus pour établir une connexion, vous pouvez communiquer avec des amis.

Décompiler mise en œuvre de classe

Nous nous interrogeons sur le diagnostic, il y a des moments où vous avez besoin de connaître le contenu de la classe correspondante chargée pour une identification facile classe chargée sont correctes et ainsi de suite, le plus souvent par  javap ne montrent un résumé similaire du contenu, pas intuitif. Du côté du bureau, nous pouvons , grâce  à jd-guices outils, la ligne de commande est généralement beaucoup plus en option. 
Arthas intègre alors cette fonctionnalité.
Les étapes suivantes essentiellement:

  1. Tout d'abord pour trouver le contenu de la classe spécifiée par nom de classe

  2. Selon les options, déterminer si à ressembler intérieur classe

  3. décompiler

Nous cherchons à atteindre les Arthas.
Pour VM, indiquez le nom de l'apparence de classe, nous voyons les lignes de code ci - dessous:

    public void process(CommandProcess process) {
        RowAffect affect = new RowAffect();
        Instrumentation inst = process.session().getInstrumentation();
        Set<Class<?>> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code);

        try {
            if (matchedClasses == null || matchedClasses.isEmpty()) {
                processNoMatch(process);
            } else if (matchedClasses.size() > 1) {
                processMatches(process, matchedClasses);
            } else {
                Set<Class<?>> withInnerClasses = SearchUtils.searchClassOnly(inst,  classPattern + "(?!.*\\$\\$Lambda\\$).*", true, code);
                processExactMatch(process, affect, inst, matchedClasses, withInnerClasses);
    }

La clé est de trouver le contenu, faites le paquet, SearchUtilsoù il y a un noyau de l'argument: Instrumentationsont ce gars - là à atteindre.

    /**
     * 根据类名匹配,搜已经被JVM加载的类
     *
     * @param inst             inst
     * @param classNameMatcher 类名匹配
     * @return 匹配的类集合
     */
    public static Set<Class<?>> searchClass(Instrumentation inst, Matcher<String> classNameMatcher, int limit) {
        for (Class<?> clazz : inst.getAllLoadedClasses()) {
            if (classNameMatcher.matching(clazz.getName())) {
                matches.add(clazz);
            }
        }
        return matches;
    }

inst.getAllLoadedClasses(), Ce sont les grands joueurs derrière.
Après la classe trouver, comment il décompiler?

 private String decompileWithCFR(String classPath, Class<?> clazz, String methodName) {
        List<String> options = new ArrayList<String>();
        options.add(classPath);
//        options.add(clazz.getName());
        if (methodName != null) {
            options.add(methodName);
        }
        options.add(OUTPUTOPTION);
        options.add(DecompilePath);
        options.add(COMMENTS);
        options.add("false");
        String args[] = new String[options.size()];
        options.toArray(args);
        Main.main(args);
        String outputFilePath = DecompilePath + File.separator + Type.getInternalName(clazz) + ".java";
        File outputFile = new File(outputFilePath);
        if (outputFile.exists()) {
            try {
                return FileUtils.readFileToString(outputFile, Charset.defaultCharset());
            } catch (IOException e) {
                logger.error(null, "error read decompile result in: " + outputFilePath, e);
            }
        }

        return null;
    }

Par un tel procédé: decompileWithCFRNous avons donc appris décompilation est « par des outils tiers CFR atteint. » Le code ci - dessus est ensuite passé à la lutte Option méthode Main mise en œuvre CFR, puis conservé. amis intéressés peuvent rechercher  benf cfr pour un usage spécifique.

Mettre en oeuvre les classes de charge de requête

Après avoir lu le contenu de la classe ci - dessus décompilé, nous savons que encapsule une  SearchUtilclasse qui sera utilisée plus tard dans de nombreux endroits, mais aussi dans la requête ci - dessus décompiler puis après la classe est. processus de requête, mais aussi sur la base de l'instrument, ainsi qu'une variété de filtre de règle de correspondance, donc plus de détails ne seront pas répétées.

Nous avons trouvé plusieurs fonctions pour atteindre ce qui précède, il y a deux choses principales:

  • Machine virtuelle

  • Instrumentation

Arthas logique tout est mis en œuvre sur une base Instrumentation de Java, toutes les classes chargées seront en chargeant l'agent par après addTransformer, amélioré, le tissage de conseils correspondante, recherchez le type de recherche, la méthode, sont est effectuée par SearchUtil, toute la machine virtuelle Java chargée match de la classe par son nom par la méthode loadAllClass instrument, cohérente serait retourné.

L'instrumentation est un bon camarade! :)

lecture connexe

  1. Lors de la lecture du code source, à la fin de ce que nous lisons?

  2. Comment lire le code source?

  3. Un puissant outil de contrôle de gestion Tomcat

  4. Sept armes Java série anneau sentimental - polyvalent outil JVisual VM profilage

  5. Sept armes Java série longévité épée - Java Virtual Machine Microscope Agent d'entretien

 

Regarder «  Tomcat chose   »  , trouver l' article plus excellent! Comprendre les principes sous - jacents et les réponses aux questions fréquemment posées. analyse Source approfondie des détails, le contenu original, l' attention de bienvenue.

 

Publié 56 articles originaux · louanges gagnées 0 · Vues 7762

Je suppose que tu aimes

Origine blog.csdn.net/chainhou/article/details/105007699
conseillé
Classement