Quarkus

Supersonic Subatomic Java

 

Peter Palaga

@ppalaga

Peter Palaga

  • Senior engineer at Red Hat Middleware
    • Red Hat Fuse on EAP (WildFly Camel)
    • JBoss EAP (WildFly)
  • Author of
    • srcdeps - source dependencies for Maven and Gradle
    • Maven and Gradle plugins for .editorconfig

Agenda

  • 7 ms demo
  • What is Quarkus
  • How it works
  • More demos

Demo

Demo



$ export GRAALVM_HOME=...
$ mvn clean package -Pnative
$ ls -lh target/*-runner
-rwxrwxr-x. 1 ppalaga ppalaga 19M Mar 20 14:39 target/quarkus-hello
$ ./target/*-runner
INFO  [io.quarkus] (main) Quarkus 0.11.0 started in 0.007s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]


https://quarkus.io/guides/building-native-image-guide

What is Quarkus

Quarkus

=

Quark - an elementary particle

+

us - the hardest problem in software

Toolkit

and

Framework

for writing Java and Kotlin applications
Based on

Existing standards

  • Servlet
  • JAX-RS
  • JPA, JDBC
  • CDI
  • Bean Validation
  • Transactions
  • Logging
MicroProfile
  • Fault Tolerance
  • Health
  • JWT
  • Metrics
  • OpenAPI
  • OpenTracing
  • Reactive Messaging
  • Rest Client

Libs and frameworks

you love and use today
Eclipse Vert.x Hibernate Resteasy Apache Camel Netty
Kubernetes Jaeger Prometheus Apache Kafka Infinispan
Unifies

Imperative

and

Reactive    

@Inject
SayService say;

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
    return say.hello();
}
@Inject @Stream("kafka")
Publisher<String> reactiveSay;

@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public Publisher<String> stream() {
    return reactiveSay;
}

Developer joy

  • Easy to start with
  • Live reload, a.k.a. dev mode
  • Java or Kotlin
  • Maven or Gradle
  • Runners for JUnit 4 and 5
  • Isolation from GraalVM CLI/API

Container First

💾 Small size on disk ✓ Small container images
🚀 Fast boot time ✓ Instant scale up
🔬 Low memory footprint ✓ More containers with the same RAM

Measuring memory



RSS1 = all RAM consumed by the process
$ ps -o pid,rss,command -p $(pgrep quarkus)
  PID   RSS COMMAND
11229 12628 ./target/quarkus-hello

 

1) Resident Set Size

Memory (RSS)

Quarkus + GraalVM Quarkus + OpenJDK Traditional Cloud-Native Stack
REST 13 MB 74 MB 140 MB
REST+JPA 35 MB 130 MB 218 MB

Startup time

Modern frameworks use lazy initialization

"started" before all classes are initialzed

What matters:

Time to first request

Time to first request1/2

@Path("/")
public class GreetingEndpoint {
    @GET @Path("/greeting")
    public String greeting(@QueryParam("name") String name) {
        System.out.println(System.currentTimeMillis());
        return "Hello " + name;
    }
    void onStart(@Observes StartupEvent startup) {
        System.out.println(System.currentTimeMillis());
    }
}

Time to first request2/2

$ while [[ \
    "$(curl -s -o /dev/null -w '%{http_code}' localhost:8080/greeting)" \
       != "200" \
  ]]; do sleep .00001; done
$ echo $(($(date +%s%N)/1000000)) && target/*-runner
1552931436155
1552931436626
INFO  [io.quarkus] (main) Quarkus 0.11.0 started in 0.035s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jsonb]
1552931436637
$ expr 1552931436637 - 1552931436155
482      # Time to first request in milliseconds

 Time to first request

REST
REST + JPA

How it works

Traditional app server

  • Hundreds of classes run only during the boot
  • Later unused
  • Still occupy memory

XML parsers, annotation lookups, management model, ...

Quarkus:

Build time boot

As much work as possible done at build time

  • Configuration parsing
  • Annotation lookup and evaluation
  • ...

Output: recorded wiring bytecode

Wiring code invocation

Decided by extensions

static initializer OR main()
preferred access to files,
sockets, etc.

Build oriented container

Quarkus extensions

  • Required for frameworks that hit GraalVM limitations
  • Code divided into build time and runtime
  • Same JVM in dev mode
  • New extensions welcome!
GraalVM

Two distinct things:

  1. Graal compiler (AoT or JIT)
  2. GraalVM - the polyglot VM
In this presentation:

GraalVM

=

Graal compiler

+

SubstrateVM

AoT1 compilation with GraalVM

1) Ahead-of-time (1/3)

AoT compilation with GraalVM

(2/3)

  • Static analysis
  • Closed world assumption
  • Dead code elimination:
        classes, fields, methods, branches

AoT compilation with GraalVM

(3/3)

$ native-image -jar my-app.jar
$ ./my-app
🚀  Fast process start
🔬  Less memory
💾  Small size on disk
GraalVM

Limitations

GraalVM GraalVM

Dynaminc Classloading



Deloying jars, wars, etc. at runtime impossible

GraalVM GraalVM

JVMTI, JMX

+ other native VM interfaces



No agents

JRebel, Byteman, profilers, tracers, ...

GraalVM GraalVM

JVMTI, JMX

+ other native VM interfaces

  • No Java debugger
  • Native debugger (GDB) still works
  • DWARF debug symbols
    • Inserted only by GraalVM enterprise
    • Allows stepping through your java code
GraalVM GraalVM

Miscellaneous



Security Manager

finalize() (deprecated anyway)

InvokeDynamic and MethodHandles

GraalVM GraalVM

Reflection



Requires registration via native-image CLI/API

@RegisterForReflection in Qarkus

GraalVM GraalVM

More



Require registration via native-image CLI/API

  • Dynamic proxies
  • Resources
  • JNI, Unsafe Memory Access, ...
GraalVM GraalVM

Static init

1/2

Build time OpenJDK instance:

  • Resolve classes, run all static initilizers
  • Take a snapshot of the produced heap
  • Store it in the executable
GraalVM GraalVM

Static init

2/2

Downsides:

no file handles, sockets, threads

More Quarkus

Please!

Get started



$ mvn io.quarkus:quarkus-maven-plugin:0.12.0:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=quarkus-hello \
    -DclassName="org.acme.quickstart.GreetingResource" \
    -Dpath="/hello"
$ mvn package
$ java -jar target/*-runner.jar
INFO  [io.quarkus] (main) Quarkus 0.11.0 started in 0.729s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

https://quarkus.io/get-started/

Native



$ export GRAALVM_HOME=...
$ mvn clean package -Pnative
$ ls -lh target/*-runner
-rwxrwxr-x. 1 ppalaga ppalaga 19M Mar 20 14:39 target/quarkus-hello
$ ./target/*-runner
INFO  [io.quarkus] (main) Quarkus 0.11.0 started in 0.005s.
INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]


https://quarkus.io/guides/building-native-image-guide

dev mode



$ mvn compile quarkus:dev


https://quarkus.io/guides/getting-started-guide

Testing



@QuarkusTest runner

JUnit 4 or 5

$ mvn clean test


https://quarkus.io/guides/getting-started-guide#testing

Testing native



@SubstrateTest runner

$ mvn clean verify -Pnative


https://quarkus.io/guides/building-native-image-guide.html#testing-the-native-executable

Discover extensions

$ mvn quarkus:list-extensions
...
[INFO] Available extensions:
...
[INFO]   * Hibernate ORM (io.quarkus:quarkus-hibernate-orm)
[INFO]   * Hibernate ORM with Panache (io.quarkus:quarkus-hibernate-orm-panache)
[INFO]   * Hibernate Validator (io.quarkus:quarkus-hibernate-validator)
...

https://quarkus.io/guides/maven-tooling.html

Add an extension

$ mvn quarkus:add-extension -Dextensions=hibernate-orm-panache

https://quarkus.io/guides/maven-tooling.html

Panache

Makes simple Hibernate ORM easy

@Entity
public class Person extends PanacheEntity {
    public String name;
    public LocalDate birth;
    public PersonStatus status;
}

https://quarkus.io/guides/hibernate-orm-panache-guide

Panache persist

// Create a person
Person person = new Person();
person.name = "Stef";
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
person.status = Status.Alive;

// Persist and delete
person.persist();
if (person.isPersistent()){
  person.delete();
}

https://quarkus.io/guides/hibernate-orm-panache-guide

Panache Queries

List<Person> allPersons = Person.listAll(); // All persons
Person p = Person.findById(personId); // Specific person by ID
// Living persons
List<Person> livingPersons = Person.list("status", Status.Alive);

// Count
int countAll = Person.count();
int countAlive = Person.count("status", Status.Alive);

// Delete
Person.delete("status", Status.Alive);
Person.deleteAll();

https://quarkus.io/guides/hibernate-orm-panache-guide

More Panache



  • Paging
  • Sorting
  • Simplified query language
  • Autogenerated DAO/Repositories


https://quarkus.io/guides/hibernate-orm-panache-guide

Quarkus wrap up

 

  • Good old Java
  • Good old standards and libs
  • Efficiency level of Go language

 

Makes Java the choice #1 for the cloud and serverless

Quarkus Links