aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
Java
  • Engineering
  • Software Engineering

Announcing Native Image Support For Java Client Libraries — Optimize Your Short Lived Workloads

  • aster.cloud
  • July 19, 2022
  • 5 minute read

We are excited to announce that Cloud Java Client Libraries now have built-in support for Native Image compilation!

 


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

Native Image technology enables you to compile your Java applications ahead-of-time and into a standalone executable. This results in several performance benefits, such as fast cold startup times and less upfront memory usage (as it doesn’t require a JVM).

 

However, Native Image compilation isn’t always compatible with some forms of Java code (resource loading, reflection) and requires extra configuration. With this launch, Cloud Client Libraries now come with the configuration that the libraries need for native image compilation, allowing users to compile their applications without additional configurations. It is also important to note that with this technology, you lose the JVM’s run time optimizations, making native compilation best suited for short-lived workloads where quick startup and response time is key.

 

Performance Benefits

We conducted a performance comparison of an application built as a native image against the same application run with standard Java (17.0.3, Temurin) and noticed the following benefits.

 

 

 

The performance gap shown above is significant, especially when just comparing startup times. In this example, 87.65% of the native image start up times came in under 1 millisecond, which would make an enormous difference when aiming to optimize for cold start latency.

 

Memory Usage

Memory usage for the application compiled to a native image is also significantly smaller. We used the ps command to check the resident set size, which is the non-swapped physical memory that a task has used, and saw the following results:

 

Getting Started

This section will walk you through running the Pub/Sub Storage Sample with native image compilation.

 

To demonstrate the performance benefits unlocked by the client library support of native image compilation we’ll build a sample application that makes use of the Pub/Sub and Storage client libraries, informed by this guide. Feel free to follow along on your own machine, or with the Cloud Shell.

 

Prerequisites

 

To reproduce the application that we used to gather the performance data above, you will need:

  • A Google Cloud project (with the Pub/Sub and Storage APIs enabled)
  • A Pub/Sub topic
  • A Storage bucket
Read More  Eventarc: A Unified Eventing Experience In Google Cloud

 

Building the sample app

 

Start by generating our project with the following Maven goal:

 

mvn archetype:generate -DgroupId=com.mycompany.app
-DartifactId=native-image-client-libraries-sample
-DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4
-DinteractiveMode=false

 

This will generate a new Maven project that will serve as a reasonable starting point for our sample app.

 

Start by setting the maven compiler plugin’s release version to 17 (or later) and adding the client libraries as dependencies:

 

<properties>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>libraries-bom</artifactId>
        <!-Or latest version-->
        <version>25.4.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-storage</artifactId>
    </dependency>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-pubsub</artifactId>
    </dependency>

 

Add a class called ListPubSubNotifications in the same directory as as App.java:

 

package com.mycompany.app;

import com.google.cloud.storage.Notification;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import java.util.List;

public class ListPubSubNotifications {

  public static void listPubSubNotifications(String bucketName) {

    Storage storage = StorageOptions.newBuilder().build().getService();
    List<Notification> notificationList = storage.listNotifications(bucketName);
    for (Notification notification : notificationList) {
      System.out.println(
          "Found notification " + notification.getTopic() + " for bucket " + bucketName);
    }
  }
}

 

This class will simply list any Pub/Sub notifications that are set up for a given Storage bucket.

Next, add another class in the same package called PublishWithErrorHandlerExample:

 

package com.mycompany.app;

import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutureCallback;
import com.google.api.core.ApiFutures;
import com.google.api.gax.rpc.ApiException;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.TopicName;

import java.io.IOException;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class PublishWithErrorHandlerExample {

    public static void publishWithErrorHandlerExample(String projectId, String topicId)
            throws IOException, InterruptedException {
        TopicName topicName = TopicName.of(projectId, topicId);
        Publisher publisher = null;

        try {
            // Create a publisher instance with default settings bound to the topic
            publisher = Publisher.newBuilder(topicName).build();

            String message = String.valueOf(new Date().getTime());

            ByteString data = ByteString.copyFromUtf8(message);
            PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build();

            // Once published, returns a server-assigned message id (unique within the topic)
            ApiFuture<String> future = publisher.publish(pubsubMessage);

            // Add an asynchronous callback to handle success / failure
            ApiFutures.addCallback(
                    future,
                    new ApiFutureCallback<String>() {

                        @Override
                        public void onFailure(Throwable throwable) {
                            if (throwable instanceof ApiException) {
                                ApiException apiException = ((ApiException) throwable);
                                // details on the API exception
                                System.out.println(apiException.getStatusCode().getCode());
                                System.out.println(apiException.isRetryable());
                            }
                            System.out.println("Error publishing message : " + message);
                        }

                        @Override
                        public void onSuccess(String messageId) {
                            // Once published, returns server-assigned message ids (unique within the topic)
                            System.out.println("Published message ID: " + messageId);
                        }
                    },
                    MoreExecutors.directExecutor());
        } finally {
            if (publisher != null) {
                // When finished with the publisher, shutdown to free up resources.
                publisher.shutdown();
                publisher.awaitTermination(1, TimeUnit.MINUTES);
            }
        }
    }
}

 

Read More  Understanding Firestore Performance With Key Visualizer

This class will publish a timestamp message to a given topic, and handle exceptions in case of failure.

Finally, in App.java’s main function, add some logic to call the functions in both classes and keep track of startup/execution time:

 

package com.mycompany.app;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

public class App 
{
    private static final Instant INITIALIZATION_TIME = Instant.ofEpochMilli(ManagementFactory.getRuntimeMXBean().getStartTime());

    private static final String projectId = "YOUR_PROJECT_ID";
    private static final String bucketName = "YOUR_BUCKET_NAME";
    private static final String topicId = "YOUR_TOPIC_ID";

    public static void main(String... args) throws IOException, InterruptedException {
        final Duration startupTime = Duration.between(INITIALIZATION_TIME, Instant.now());
        ListPubSubNotifications.listPubSubNotifications(bucketName);
        final Duration timeToFirstRequest = Duration.between(INITIALIZATION_TIME, Instant.now());
        PublishWithErrorHandlerExample.publishWithErrorHandlerExample(projectId, topicId);


        System.out.println("Startup time: " + startupTime.toMillis() + " ms, or " + TimeUnit.NANOSECONDS.toMicros(startupTime.toNanos()) + " microseconds");
        System.out.println("Time to finish first request: " + timeToFirstRequest.toMillis() + "ms");
        System.out.println("Shutting down. Total time elapsed: " + Duration.between(INITIALIZATION_TIME, Instant.now()).toMillis() + "ms");
    }
}

 

Now that the sample application is in place you are ready to configure the native image build.

 

Build configuration

Add the following `native-image` build profile to your pom.xml:

 

<profiles>
  <profile>
    <id>native-image</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.graalvm.buildtools</groupId>
          <artifactId>native-maven-plugin</artifactId>
          <version>0.9.11</version>
          <extensions>true</extensions>
          <executions>
            <execution>
              <id>build-native</id>
              <goals>
                <goal>build</goal>
              </goals>
              <phase>package</phase>
            </execution>
          </executions>
          <configuration>
            <mainClass>com.mycompany.app.App</mainClass>
          </configuration>
        </plugin>
      </plugins>
    </build>
  </profile>
  <profile>
    <id>regular-jar</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
              <configuration>
                <archive>
                  <manifest>
                    <mainClass>
                      com.mycompany.app.App
                    </mainClass>
                  </manifest>
                </archive>
                <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

 

This plugin and profile simplify the process of providing the native-image builder with the configuration it needs to build your application into a native image. Ensure that the `mainClass` parameter is correct for your application, and note that `buildArgs` can be used to pass options to the builder.

 

At this point, your app is ready to be built into a native image. There are, however, a few things worth keeping in mind with native-image’s ahead-of-time builds:

  • They take longer than equivalent just-in-time builds (approx. 5-10 minutes*)
  • They take quite a bit of memory (approx. 6-10GB*)
Read More  Improve Responsiveness With Session Affinity On Cloud Run

* values come from building this sample on the Cloud Shell’s e2-standard-4 machine type

 

To run the build, we will need to ensure that we have an appropriate JDK and the native-image builder. This process can be greatly simplified with the help of SDKMAN!.

Install the appropriate JDK distribution like GraalVM  with the following command:

 

#Or latest version
sdk install java 22.1.0.r17-grl

 

Then, inform sdkman to use this version in your current shell:

 

sdk use java 22.1.0.r17-grl

 

Next, install the native-image extension:

 

gu install native-image

 

Finally, run the build the native-image-client-libraries-sample project with the `native-image` profile:

 

#For the native image
mvn clean package -P native-image

#For the regular fat jar
mvn clean package -Pregular-jar

 

This build process may take a few minutes. Once the build finishes, you will have everything you need to see the performance differences in action!

The generated executable is in the “target” directory. Run the program to see it receives notifications from the Cloud Storage bucket

 

#For the native image
./target/native-image-client-libraries-sample

#For the regular jar
java -jar ./target/my-app-1.0-SNAPSHOT-jar-with-dependencies.jar

 

In this example, the native image started up 159x faster than the regular jar, and finished 19 times faster as well. The results of native image compilation can vary greatly depending on the workload, so feel free to experiment with your own applications to get the most out of your cloud resources.

 

Conclusion

This is only one example of how native image compilation is supported in Cloud Java Client Libraries. Please check out our official documentation to learn more about what libraries are supported and how you can build applications as native images. The documentation page also links to a couple of samples that you can try out.

 

 

By: Aaron Wanjala (Java Developer Advocate) and Cameron Balahan (Product Manager)
Source: Google Cloud Blog


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • Google Cloud
  • Java
  • Tutorials
You May Also Like
View Post
  • Engineering

Just make it scale: An Aurora DSQL story

  • May 29, 2025
View Post
  • Engineering
  • Technology

Guide: Our top four AI Hypercomputer use cases, reference architectures and tutorials

  • March 9, 2025
View Post
  • Software Engineering
  • Technology

Claude 3.7 Sonnet and Claude Code

  • February 25, 2025
View Post
  • Computing
  • Engineering

Why a decades old architecture decision is impeding the power of AI computing

  • February 19, 2025
View Post
  • Engineering
  • Software Engineering

This Month in Julia World

  • January 17, 2025
View Post
  • Engineering
  • Software Engineering

Google Summer of Code 2025 is here!

  • January 17, 2025
View Post
  • Data
  • Engineering

Hiding in Plain Site: Attackers Sneaking Malware into Images on Websites

  • January 16, 2025
View Post
  • Computing
  • Design
  • Engineering
  • Technology

Here’s why it’s important to build long-term cryptographic resilience

  • December 24, 2024

Stay Connected!
LATEST
  • 1
    Just make it scale: An Aurora DSQL story
    • May 29, 2025
  • 2
    Reliance on US tech providers is making IT leaders skittish
    • May 28, 2025
  • Examine the 4 types of edge computing, with examples
    • May 28, 2025
  • AI and private cloud: 2 lessons from Dell Tech World 2025
    • May 28, 2025
  • 5
    TD Synnex named as UK distributor for Cohesity
    • May 28, 2025
  • Weigh these 6 enterprise advantages of storage as a service
    • May 28, 2025
  • 7
    Broadcom’s ‘harsh’ VMware contracts are costing customers up to 1,500% more
    • May 28, 2025
  • 8
    Pulsant targets partner diversity with new IaaS solution
    • May 23, 2025
  • 9
    Growing AI workloads are causing hybrid cloud headaches
    • May 23, 2025
  • Gemma 3n 10
    Announcing Gemma 3n preview: powerful, efficient, mobile-first AI
    • May 22, 2025
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • Understand how Windows Server 2025 PAYG licensing works
    • May 20, 2025
  • By the numbers: How upskilling fills the IT skills gap
    • May 21, 2025
  • 3
    Cloud adoption isn’t all it’s cut out to be as enterprises report growing dissatisfaction
    • May 15, 2025
  • 4
    Hybrid cloud is complicated – Red Hat’s new AI assistant wants to solve that
    • May 20, 2025
  • 5
    Google is getting serious on cloud sovereignty
    • May 22, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.