Safe Harbor
Safe Harbor Statement
The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.
Java in a World of Containers
intro
Who me?
  • Matthew Gilliard (@MaximumGilliard)
  • Java user since 199x
  • Now working for Oracle since 2015
  • Working on FnProject since mid-2017
intro
What the Fn?
  • Open-source Serverless Compute Platform
  • Run anywhere: Datacenter / laptop / rPi
  • Functions are containers
  • Fully open (Apache 2.0) with commercial backing from Oracle
  • Fn Java
The World of Containers
By the way...
What even is a "container" ?!
The World of Containers
World of Containers
What can we expect in a world of containers?
  • Mixed workloads
  • Many instances
  • Heterogeneous hardware
  • Heterogeneous configuration
The World of Containers
So.... isn't Java already perfect?
(spoiler: not quite)
Good points about Java:
  • Managed Runtime
  • Hardware and OS agnostic
  • Safety and Security
  • Runtime adaptive: Stable in differing environments
JPG is committed to keeping Java as the first choice for container deployments
Demo:
Hello Container
Java in Containers
Java in containers
What do we want containerized JVMs to do?
  • Start fast
  • Run in small images
  • Respect container environment
Starting Fast
Java in Containers
Fast JVM startup
Why? Containerized JVMs can be stopped/started/moved/rescheduled more frequently. Any delay is annoying.

For serverless workloads, startup latency (aka cold start) is crucial.
Java in Containers
Fast JVM startup
How? Move startup costs to build-time. Also allows us to share the pre-built cached data between JVMs.
  • libc, libjava.so can be shared (assuming same layer/file/inode)
  • What else can we share?
    • Class Data Sharing (CDS)
    • Application CDS
    • AOT compilation
Java in Containers
Fast JVM startup - CDS
  • Like an shared object file but for Java Class Data
  • Class data read from classes.jsa without reading/parsing classes from Jar files
  • Class data can be shared between containers
Demo time!
  • Anecdata: saves me about 40ms at startup
  • Use java -Xshare:dump to create the cache
  • And use java -Xshare:on ... to force usage
Java in Containers
Fast JVM startup - AppCDS
Application CDS is like "regular" CDS, but for application classes.
  • Cache size & speedup depends on how big your application's classes are
  • Memory saving depends on number of containers sharing the same cache
  • AppCDS was an OracleJDK commercial feature until JDK10
Java in Containers
Fast JVM startup - AppCDS
How to use it?
  • You need to provide a list of classes to cache:
    • -XX:DumpLoadedClassList=myapp.classlist
  • Then write out the cache with
    • -Xshare:dump
    • -XX:SharedClassListFile=myapp.classlist
    • -XX:SharedArchiveFile=myapp.jsa
  • Finally you can run with AppCDS enabled!
    • -XX:+UseAppCDS
    • -Xshare:on
    • -XX:SharedArchiveFile=myapp.jsa
Java in Containers
Fast JVM startup - AOT
Ahead-of-time compilation for Java classes, ie bytecode ⇨ native code. Available since Java 9.
  • Shared memory
  • Quicker startup
  • Optionally include profiling paths
Java in Containers
Fast JVM startup - AOT
How? You need to specify a list of which methods in which classes should be compiled. This isn't easy to generate but you can start with:
  • -XX:+UnlockDiagnosticVMOptions
  • -XX:+LogTouchedMethods
  • -XX:+PrintTouchedMethodsAtExit
...then massage this data with grep and/or sed... Then you have to pass this list to jaotc which compiles your bytecodes into a Shared Object file. Not easy, maybe worth it though.

More anec-data: I found that using CDS, AppCDS and AOT all at once cut the startup time for a Clojure application by over 60%. YMMV, of course.
Smaller images
Java in Containers
Smaller images
Why? Smaller container images mean faster startup:
  • Transferring images to the host
  • COW caches
  • Overlay FS
Again, for serverless, this translates into relief from the dreaded cold start.
Java in Containers
Smaller images
How? Put less stuff in 'em!
  • jlink - remove unused core JDK modules
  • Smaller base images - remove unnecessary OS stuff
  • Substrate VM - futuristic new JVM, compile your Java to a static binary
Java in Containers
Smaller images - jlink
  • Only includes the jigsaw modules you use
  • Make even smaller with --compress
  • Also: --vm minimal includes only Serial GC and client compiler - size reduced to ~15MB (32bit JVM only tho)
Question Do I need to use modules to use jlink?
Answer Nope, you can use jdeps to generate a list of modules used by non-module code.
Java in Containers
Smaller images - jlink
How?
  • jlink
  • --module-path $JAVA_HOME/jmods:mods
  • --add-modules myapp.module
  • --output linked
This creates a smaller JVM in directory called linked.

Question Can I use jlink, CDS, AppCDS and AOT all at the same time?
Answer Yes, yes you can. This speeds JVM startup over 2x, even outside of a container.
Java in Containers
Smaller images - Alpine & Musl
Ubuntu / Debian / Oracle Linux base images can be 100s of MB, even the "slim" versions. We don't care much about the base image so long as it can run Java. Project Portola makes the JVM run on Alpine Linux/Musl.

  • Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox. Alpine base image is 5mb (!)

  • Musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety.
Let's have another quick demo!
Java in Container
Smaller images - Alpine & Musl
A request: Currently is it unknown whether there is enough interest in JVM on Alpine to justify a GA release of Portola. If you are interested please please show your interest to project lead @MikaelVidstedt.
Java in Container
Smaller images - Substrate VM
Substrate VM from Oracle Labs compiles Java source to a single binary, like C or Golang.
  • Part of Graal project
  • Small VM overhead
  • Experimental, in active development
  • No support for dynamic code generation, serialization
  • Limited support for reflection
  • Tiny image sizes (<10mb)
Respecting the Environment
Java in Containers
Respecting Resource Constraints
The JVM self-tunes to the underlying system (aka Ergonomics).
  • Memory
    • Heap size
    • GC region sizes
    • JIT code cache sizes
  • CPU
    • ThreadPool sizes
    • Runtime.availableProcessors()
This is not transparent - requires JVM to support cgroups resource limitations. Much good stuff landed recently for JDK10. See JDK-8146115 for more details.
Java in Container
Being Container Friendly
Other work:
  • JDK-8179498: attach in linux should be relative to /proc/pid/root and namespace aware (JDK 10) - this means you can run tools that inspect running JVMs, against containerized JVMs
  • JDK-8193710: jcmd -l and jps commands do not list Java processes running in Docker containers (JDK 11)
  • And more... JDK-8182070: Container aware Java
Thank you for listening
Java in a World of Containers :: @MaximumGilliard :: Virtual JUG, 28 March 2018