Skip to content

Latest commit

 

History

History
217 lines (181 loc) · 14.4 KB

StillRunningYourJavaCodeWithTheJvm.md

File metadata and controls

217 lines (181 loc) · 14.4 KB

Still using JVM to run your Java code? Too slow, try Oracle's GraalVM

foreword

For Java developers, they deal with the JVM almost every day, but the JVM is about to become obsolete. Developers who maintain a keen insight into new technologies may have already deployed binary programs generated by GraalVM in the production environment. Have you started using them, my friends?

一、What is the charm of GraalVM?

GraalVM is the next generation high-performance multi-language virtual machine developed and promoted by Oracle , and many frameworks now support GraalVM, such as Spring. GraalVM's core strength lies in its Native Image technology, which can directly compile Java code into independent binary executable files , optimize code execution and improve performance by using Just-In-Time (JIT) and Ahead-Of-Time (AOT) compilers, and has the following advanced features:

  • Low CPU and memory usage: GraalVM has an efficient garbage collection mechanism that can reduce memory usage and improve application performance.

  • Multi-language support: GraalVM can run multiple other languages such as JavaScript, Python, Ruby, etc., thus expanding its application scope.

  • Extremely high security: Provides a higher level of security that can better protect applications from security threats such as attacks and data breaches.

  • Fast startup and warm-up: GraalVM enables fast application startup and achieves optimal performance without warm-up.

  • Toolchain: Provides a set of tools, such as debuggers, performance analyzers, etc., to help developers develop and optimize applications.

After understanding the characteristics of GraalVM, many friends may say that it looks good, but is it a rigid requirement for production environment? What pain points can it actually solve? I will answer them for you in the following text.

二、Can the problem of slow Java service be solved?

Java development partners, have you ever complained about Java slow? Here are three main aspects of slow service:

  • It takes 5-6 minutes to start a microservice, and the virtual memory usage is increasing. Should we expand the resources?

  • Should we adjust the VM parameters and how to adjust them?

  • Is there slow SQL in the code and how to optimize it?

The above two problems of slow startup and JVM tuning are really painful for developers, but they have to face them. They can only hope that the official can solve this problem. To solve the problem of slow SQL in the code, there are some tools in the industry, but most of them are based on experience rule review, which cannot effectively identify performance problems and cannot be completely cured. Is there a way to completely cure the slow problem?

1)How to completely solve the problems of slow microservice startup and JVM parameter tuning?

Orace's newly launched GraalVM has met everyone's expectations, directly addressing the pain points and solving the above two problems. Why did the official want to eliminate JVM?

  • JVM as the running environment of the Java program, light startup will take a lot of time, after the JVM startup is completed, it can execute the startup work of the application itself, which is the root cause of the slow startup of the Java program.
  • JVM parameter tuning is also a technical job with a threshold and relies on experience.

Since the slow problem is caused by the JVM mechanism, the official will completely eliminate the JVM. You may be curious, how does GraalVM solve the slow problem?

The core function of GraalVM is to run high-performance and low-usage executable binary files directly on the machine (in other words, it can run without the JDK environment). Compared with the running of JVM-based Java services, the native executable files obtained through compilation have been greatly optimized in terms of startup speed. This process eliminates the dependence on JVM or other Runtime Environments, reduces memory usage, and enables Java programs to start quickly. This is very beneficial for scenarios such as Cloud Services and microservices that require fast startup and low memory usage.

2)SQL slow problem, how to identify code SQL performance issues from the root?

Recently, the SQL audit function of the DBdoctor tool has been released, which is a blessing for development colleagues. DBdoctor is a good partner of GraalVM. During the code development stage, it can evaluate the real performance of business SQL after it is launched in the future, and provide optimization suggestions, such as recommending the best index to solve the problem of slow business SQL performance. Interested friends can read this article:

《Database index recommendation big PK, DBdoctor and senior DBA ultimate contest》

The problem of slow service can be completely cured. Developers can take action now. GraalVM + DBdoctor can make your service start and run more smoothly and stably.

三、How to use GraalVM?

Below we will demonstrate through a simple Java demo.

1)Download GraalVM and view the currently installed components.

Command to view the currently installed components, you can see that native-image is the default installed component

cd graalvm-jdk-<version>_linux-<architecture>/bin
./gu list
ComponentId              Version             Component name                Stability                     Origin
---------------------------------------------------------------------------------------------------------------------------------
graalvm                  23.0.4              GraalVM Core                  Supported
native-image             23.0.4              Native Image                  Early adopter

2)Prepare demo code (Maven project)

Here, the native-maven-plugin maven plugin is used to simplify the compile process. Of course, you can also compile directly through the native-image command without using the plugin.

  • a)Project catalog structure
├── NativeImageDemo
 │   ├── pom.xml
 │   └── src
 │       ├── main
 │       │   ├── java
 │       │   │   └── HelloWorld.java
 │       │   └── resources
  • b)HelloWorld.java
public class HelloWorld {
    static class Greeter {
        static {
            System.out.println("Greeter is getting ready!");
        }
        public static void greet() {
            System.out.println("Hello, World!");
        }
    }
    public static void main(String[] args) {
        Greeter.greet();
    }
}
  • c)pom.xml
<?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>org.example</groupId>
    <artifactId>NativeImageDemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <version>0.10.2</version>
                <configuration>
                    <imageName>${project.artifactId}</imageName>
                    <mainClass>HelloWorld</mainClass>
                    <skipNativeTests>true</skipNativeTests>
                    <buildArgs>
                        <buildArg>-H:+ReportExceptionStackTraces</buildArg>
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3)compile and execute binary programs

  • a)compiling

Execute the following command in the project root directory and wait for a moment for the command line to output BUILD SUCCESS, indicating that the compile was successful.

mvn -U clean package native:compile
========================================================================================================================
GraalVM Native Image: Generating 'NativeImageDemo' (executable)...
========================================================================================================================
[1/8] Initializing...                                                                                    (4.8s @ 0.19GB)
 C compiler: gcc (redhat, x86_64, 4.8.5)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
[2/8] Performing analysis...  [****]                                                                     (3.9s @ 0.25GB)
   1,856 (59.16%) of  3,137 types reachable
   1,737 (46.34%) of  3,748 fields reachable
   7,717 (35.62%) of 21,663 methods reachable
     640 types,     0 fields, and   283 methods registered for reflection
      49 types,    32 fields, and    48 methods registered for JNI access
       4 native libraries: dl, pthread, rt, z
[3/8] Building universe...                                                                               (1.0s @ 0.38GB)
[4/8] Parsing methods...      [*]                                                                        (1.5s @ 0.33GB)
[5/8] Inlining methods...     [***]                                                                      (0.4s @ 0.38GB)
[6/8] Compiling methods...    [***]                                                                     (11.0s @ 0.51GB)
[7/8] Layouting methods...    [*]                                                                        (1.0s @ 0.45GB)
[8/8] Creating image...       [*]                                                                        (1.3s @ 0.52GB)
   2.75MB (43.13%) for code area:     3,486 compilation units
   3.46MB (54.34%) for image heap:   48,919 objects and 1 resources
 165.42kB ( 2.53%) for other data
   6.38MB in total
------------------------------------------------------------------------------------------------------------------------
Top 10 origins of code area:                                Top 10 object types in image heap:
   1.43MB java.base                                          549.55kB byte[] for code metadata
   1.13MB svm.jar (Native Image)                             415.45kB byte[] for java.lang.String
  69.54kB com.oracle.svm.svm_enterprise                      325.83kB java.lang.String
  33.89kB org.graalvm.nativeimage.base                       304.98kB java.lang.Class
  30.23kB org.graalvm.sdk                                    253.66kB byte[] for general heap data
  18.95kB jdk.internal.vm.ci                                 147.78kB java.util.HashMap$Node
  14.10kB jdk.internal.vm.compiler                           111.71kB char[]
   1.17kB jdk.proxy3                                          78.91kB java.lang.Object[]
   1.15kB jdk.proxy1                                          72.50kB com.oracle.svm.core.hub.DynamicHubCompanion
  360.00B jdk.proxy2                                          70.45kB byte[] for reflection metadata
  162.00B for 1 more packages                                441.46kB for 506 more object types
------------------------------------------------------------------------------------------------------------------------
Recommendations:
 G1GC: Use the G1 GC ('--gc=G1') for improved latency and throughput.
 PGO:  Use Profile-Guided Optimizations ('--pgo') for improved throughput.
 HEAP: Set max heap for improved and more predictable memory usage.
 CPU:  Enable more CPU features with '-march=native' for improved performance.
 QBM:  Use the quick build mode ('-Ob') to speed up builds during development.
------------------------------------------------------------------------------------------------------------------------
                        0.8s (3.0% of total time) in 99 GCs | Peak RSS: 1.18GB | CPU load: 15.45
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
 /usr/local/NativeImageDemo/target/NativeImageDemo (executable)
========================================================================================================================
Finished generating 'NativeImageDemo' in 25.6s.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  28.975 s
[INFO] Finished at: 2024-07-21T13:29:33Z
[INFO] --------------------------------------------------------------
  • b)Execute binary programs

Cd to the target directory and execute the following command to get the result. It can be seen that the NativeImageDemo file is an executable file that can be executed on any Linux server with the same architecture.

./NativeImageDemo
Greeter is getting ready!
Hello, World!

四、How to discover performance issues before going online?

After downloading DBdoctor, you can install and deploy the service with zero dependency in one minute. SQL auditing mainly includes two parts.

  • a)SQL rule review (specification):

SQL rule review is equivalent to the company's SQL specification. Through DBdoctor, specification issues can be quickly identified and the cause of the problem pointed out.

  • b)SQL Performance Audit:

DBdoctor is based on an external COST optimizer and calculates the COST consumption ranking of all index combinations by collecting real data. It recommends the index with the smallest COST (optimal index). Simply paste the SQL into the SQL audit for review to view the recommended results.

五、Summary

GraalVM Native Image technology brings the advantages of fast startup and low resource consumption to Java applications. DBdoctor's SQL audit technology brings the advantages of fast SQL performance audit and evaluation without production changes to Java applications. The cooperation of GraalVM + DBdoctor can help Java services speed up. Welcome to join our technical exchange group and discuss with us!