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  NetApp And Google Cloud Introduce Managed Storage Service to Revolutionize Enterprise Workloads In The 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  This Year, Resolve To Become A Certified Professional Cloud Developer – Here’s How

* 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
  • 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
IBM and Ferrari Premium Partner
View Post
  • Data
  • Engineering

IBM Selected as Official Fan Engagement and Data Analytics Partner for Scuderia Ferrari HP

  • November 7, 2024

Stay Connected!
LATEST
  • college-of-cardinals-2025 1
    The Definitive Who’s Who of the 2025 Papal Conclave
    • May 7, 2025
  • conclave-poster-black-smoke 2
    The World Is Revalidating Itself
    • May 6, 2025
  • oracle-ibm 3
    IBM and Oracle Expand Partnership to Advance Agentic AI and Hybrid Cloud
    • May 6, 2025
  • 4
    Conclave: How A New Pope Is Chosen
    • April 25, 2025
  • Getting things done makes her feel amazing 5
    Nurturing Minds in the Digital Revolution
    • April 25, 2025
  • 6
    AI is automating our jobs – but values need to change if we are to be liberated by it
    • April 17, 2025
  • 7
    Canonical Releases Ubuntu 25.04 Plucky Puffin
    • April 17, 2025
  • 8
    United States Army Enterprise Cloud Management Agency Expands its Oracle Defense Cloud Services
    • April 15, 2025
  • 9
    Tokyo Electron and IBM Renew Collaboration for Advanced Semiconductor Technology
    • April 2, 2025
  • 10
    IBM Accelerates Momentum in the as a Service Space with Growing Portfolio of Tools Simplifying Infrastructure Management
    • March 27, 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
  • 1
    Tariffs, Trump, and Other Things That Start With T – They’re Not The Problem, It’s How We Use Them
    • March 25, 2025
  • 2
    IBM contributes key open-source projects to Linux Foundation to advance AI community participation
    • March 22, 2025
  • 3
    Co-op mode: New partners driving the future of gaming with AI
    • March 22, 2025
  • 4
    Mitsubishi Motors Canada Launches AI-Powered “Intelligent Companion” to Transform the 2025 Outlander Buying Experience
    • March 10, 2025
  • PiPiPi 5
    The Unexpected Pi-Fect Deals This March 14
    • March 13, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.