Supersonic Subatomic Java
Peter Palaga
$ which docker # make sure you have docker
~/bin/docker
$ mvn clean package -Pnative -Dnative-image.docker-build
$ 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.22.0 started in 0.004s.
INFO [io.quarkus] (main) Installed features: [cdi, resteasy]
Java EE | Spring | ||
|
|
|
1) via compatibility layers |
Eclipse Vert.x | Netty | Apache Camel | Infinispan | Caffeine | Keycloak |
Kubernetes | AWS Lambda | Azure Functions | Apache Tika | ElasticSearch | Kogito |
|
|
Unifies | ||||
Imperative |
and | Reactive |
||
|
|
mvn quarkus:create
or code.quarkus.iomvn compile quarkus:dev
💾 | Small size on disk | ✓ | Small container images |
🚀 | Fast boot time | ✓ | Instant scale up |
🔬 | Low memory footprint | ✓ | More containers with the same RAM |
$ ps -o pid,rss,command -p $(pgrep quarkus)
PID RSS COMMAND
11229 12628 ./target/quarkus-hello
1) Resident Set Size
Quarkus + GraalVM | Quarkus + OpenJDK | Traditional Cloud-Native Stack | |
REST | 13 MB | 74 MB | 140 MB |
REST+JPA | 35 MB | 130 MB | 218 MB |
Modern frameworks use lazy initialization
"started" before all classes are initialzed
What matters:
@Path("/")
public class GreetingEndpoint {
@GET @Path("/greeting")
public String greeting(@QueryParam("name") String name) {
System.out.println(System.currentTimeMillis());
return "Hello " + name;
}
}
$ while [[ \
"$(curl -s -o /dev/null -w '%{http_code}' localhost:8080/hello)" \
!= "200" \
]]; do sleep .00001; done
$ echo $(($(date +%s%N)/1000000)) && target/*-runner
1552931436155
INFO [io.quarkus] (main) Quarkus 0.22.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
REST |
REST + JPA |
XML parsers, annotation lookups, management model, ...
As much work as possible done at build time
Output: recorded wiring bytecode
|
|
|
Decided by extensions
static initializer |
OR | main() |
preferred | access to files, sockets, etc. |
Two distinct things:
1) Ahead-of-time (1/3)
(2/3)
(3/3)
$ native-image -jar my-app.jar
$ ./my-app
in cloud environments
Deloying jars, wars, etc. at runtime impossible
No agents
JRebel, Byteman, profilers, tracers, ...
Security Manager
finalize()
(deprecated anyway)
InvokeDynamic
and MethodHandles
Requires registration via native-image
CLI/API
@RegisterForReflection
in Qarkus
Require registration via native-image
CLI/API
1/2
Build time OpenJDK instance:
2/2
Downsides:
no file handles, sockets, threads
$ native-image -jar my-app.jar \
-H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime \
-J-Djava.util.concurrent.ForkJoinPool.common.parallelism=1 \
-H:FallbackThreshold=0 \
-H:ReflectionConfigurationFiles=...
-H:+ReportExceptionStackTraces \
-H:+PrintAnalysisCallTree \
-H:-AddAllCharsets \
-H:EnableURLProtocols=http \
-H:-JNI \
-H:-UseServiceLoaderFeature \
-H:+StackTrace \
--no-server \
--initialize-at-build-time=... \
-J-Djava.util.logging.manager=org.jboss.logmanager.LogManager \
-J-Dio.netty.leakDetection.level=DISABLED \
-J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory \
-J-Dsun.nio.ch.maxUpdateArraySize=100 \
-J-Dio.netty.allocator.maxOrder=1 \
-J-Dvertx.disableDnsResolver=true
docker
(easier)export GRAALVM_HOME=...
$ mvn clean package -Dnative -Dnative-image.docker-build
$ 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.22.0 started in 0.005s.
INFO [io.quarkus] (main) Installed features: [cdi, resteasy]
$ 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)
...
$ mvn quarkus:add-extension -Dextensions=hibernate-orm-panache
Makes simple Hibernate ORM easy
@Entity
public class Person extends PanacheEntity {
public String name;
public LocalDate birth;
public PersonStatus status;
}
// 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();
}
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();
Makes Java the choice #1 for the cloud and serverless