Les problèmes de performances sont toujours un problème pour les ingénieurs. Il existe différents types de traitement lent. Si un processus est simplement plus lourd que le seuil, ou parce qu'il s'agit d'un lot, chaque processus n'est pas si lent, mais il sera lent à cause du chiritsumo. Surtout ce dernier est assez difficile à identifier. Même si vous utilisez Flight Recorder, il est assez difficile de savoir où il est lent pour Java simple, et l'introduction de l'APM à grande échelle a tendance à être un gros problème.
Donc, cette fois, j'ai essayé de voir si je pouvais utiliser AspectJ pour tracer des méthodes lentes. Vous pouvez obtenir l'exemple de code à partir de ce qui suit. https://github.com/koduki/example-aspectj
AspectJ est une bibliothèque Java pour réaliser l'AOP et l'orientation d'aspect. En gros, c'est "une méthode pour intégrer des préoccupations (aspects) transversales dans de multiples domaines tels que l'exploitation forestière et la vérification des autorisations dans le traitement existant". C'était assez populaire comme méthode pour compléter l'orientation des objets pendant un certain temps, mais il semble que je ne dis pas grand-chose ces jours-ci. C'est peut-être parce que le FW et autres sont bons pour les choses mentionnées dans l'exemple, donc ce n'est plus un domaine qui intéresse les ingénieurs individuels.
Cette fois, en créant un aspect de «journalisation des méthodes lentes», j'essaierai de sortir des logs sans modifier le traitement existant de la cible de mesure.
Fondamentalement, vous pouvez développer avec du code Java ordinaire, de sorte que vous pouvez facilement démarrer le développement avec NetBeans + Maven. pom.xml ressemble à ceci. Notez qu'il est nécessaire d'ajouter un plugin ainsi qu'une dépendance.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.orz.pascal</groupId>
<artifactId>example-aspectj</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputProperty>aspectj-weaver-path</outputProperty>
<includeGroupIds>org.aspectj</includeGroupIds>
<includeArtifactIds>aspectjweaver</includeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.13</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<complianceLevel>1.8</complianceLevel>
<outxml>true</outxml>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Continuez à créer l'aspect. Cependant, vous pouvez l'écrire en tant que classe Java simplement en ajoutant @ Aspect
.
@Aspect
public class SlowMethodLogger {
private static final long LIMIT_TIME;
static {
String limit = System.getenv("SLOW_METHOD_LIMIT");
LIMIT_TIME = (limit == null) ? 0 : Long.parseLong(limit);
}
@Around("execution(* cn.orz.pascal.example.aspectj.*.*(..))")
public Object logging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long start = System.nanoTime();
try {
return proceedingJoinPoint.proceed();
} finally {
long end = System.nanoTime();
long time = end - start;
if (time >= LIMIT_TIME) {
int line = proceedingJoinPoint.getSourceLocation().getLine();
String method = proceedingJoinPoint.getSignature().toString();
System.out.println("SLOW_METHOD:" + method + "\tLINE:" + line + "\tTIME(ns):" + time);
}
}
}
}
C'est une méthode que @Around incorpore sous la forme d'un aspect appelé coupe par point. Cette fois, en utilisant @ Around
, le temps d'exécution est mesuré en exécutant la méthode cible [procedingJoinPoint.proceed ()]. C'est un formulaire à enregistrer uniquement lorsque la valeur est supérieure à LIMIT_TIME
après l'exécution.
La cible à incorporer est spécifiée par exécution, et avec cette méthode d'écriture, tous les subordonnés sous cn.orz.pascal.example.aspectj
sont enregistrés indépendamment de privé / public.
Si vous sortez simplement tous les journaux, cela ne se terminera pas comme un goulot d'étranglement dans le processus de bouclage 100 millions de fois, il est donc nécessaire de mettre en place une sorte de mécanisme d'échantillonnage pour l'enregistrement de la synchronisation et la synchronisation de l'enregistrement. Il y a.
Cette fois, c'est un exemple, j'utilise donc System.out.println, mais en réalité, il est préférable d'utiliser log4j2 ou quelque chose comme ça.
Maintenant, créons une application à mesurer. Il n'est fondamentalement pas nécessaire de connaître l'aspect créé précédemment ainsi que la bibliothèque associée à AspectJ au moment du développement. Cependant, seul le package doit correspondre à celui spécifié dans ʻexecution`. * Normalement, l'exécution sera modifiée en fonction de la cible de mesure.
package cn.orz.pascal.example.aspectj;
public class Main {
public static void main(String[] args) {
System.out.println("run");
Sub1 sub = new Sub1();
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
sub.getProcess();
}
}
}
package cn.orz.pascal.example.aspectj;
public class Sub1 {
private long count = 0;
public void getProcess() {
getPrivateProcess();
}
private void getPrivateProcess() {
if (count % 3 == 0) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
count += 1;
}
}
Je suppose que Sub est appelé dans la boucle depuis Main et que Sub est lent environ une fois toutes les trois fois.
Tout d'abord, exécutez l'application à mesurer normalement.
$ time SLOW_METHOD_LIMIT=500000000 java -cp "example-targetapp-0.1.jar" cn.orz.pascal.example.aspectj.Main 10
run
real 0m2.158s
user 0m0.015s
sys 0m0.000s
C'est le temps attendu car 500ms font 4 tours. Ensuite, attachons l'aspect créé précédemment. Pour la pièce jointe, utilisez javaagent comme JFR et d'autres systèmes APM.
$ time SLOW_METHOD_LIMIT=500000000 java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" -javaagent:asp ectjweaver-1.8.13.jar cn.orz.pascal.example.aspectj.Main 10
run
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Sub1.getPrivateProcess() LINE:24 TIME(ns):500278916
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Sub1.getProcess() LINE:20 TIME(ns):503194581
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Sub1.getPrivateProcess() LINE:24 TIME(ns):500142922
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Sub1.getProcess() LINE:20 TIME(ns):501776905
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Sub1.getPrivateProcess() LINE:24 TIME(ns):500856763
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Sub1.getProcess() LINE:20 TIME(ns):502748879
SLOW_METHOD:void cn.orz.pascal.example.aspectj.Main.main(String[]) LINE:15 TIME(ns):2021801158
real 0m2.459s
user 0m0.000s
sys 0m0.000s
Je l'ai mesuré trois fois chacun, mais dans ce cas, il n'y avait pas beaucoup de différence de performance. Cependant, comme il s'agit d'un cas par cas, il est nécessaire de l'appliquer au code effectivement utilisé et de décider de l'introduction proprement dite.
$ time SLOW_METHOD_LIMIT=500000000 java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" -javaagent:asp ectjweaver-1.8.13.jar cn.orz.pascal.example.aspectj.Main 1000 > /dev/null
real 2m47.602s
$ time SLOW_METHOD_LIMIT=500000000 java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" -javaagent:asp ectjweaver-1.8.13.jar cn.orz.pascal.example.aspectj.Main 1000 > /dev/null
real 2m47.591s
$ time SLOW_METHOD_LIMIT=500000000 java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" -javaagent:asp ectjweaver-1.8.13.jar cn.orz.pascal.example.aspectj.Main 1000 > /dev/null
real 2m47.572s
$ time java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" cn.orz.pascal. example.aspectj.Main 1000 > /dev/null
real 2m47.327s
$ time java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" cn.orz.pascal. example.aspectj.Main 1000 > /dev/null
real 2m47.319s
$ time java -cp "aspectjrt-1.8.13.jar;example-aspectj-0.1.jar;example-targetapp-0.1.jar" cn.orz.pascal. example.aspectj.Main 1000 > /dev/null
real 2m47.304s
Cette fois, j'ai essayé d'utiliser AspectJ pour identifier les méthodes lentes. Il est plus facile à installer qu'un APM à grande échelle, il est donc pratique lorsque vous souhaitez le placer rapidement dans un environnement de développement ou de vérification. De plus, il semble plus facile de le faire avec AOP que de le faire soi-même, comme le mécanisme de traçage distribué. Je n'ai pas tellement essayé, mais maintenant je réalise la commodité d'AspectJ ...
Alors bon piratage!
Recommended Posts