Recorded at the London Microservices Meetup: https://www.meetup.com/London-Microservices/
- Date: 05/08/2020
- Event page: https://www.meetup.com/London-Microservices/events/272223163/
Follow us on Twitter! https://twitter.com/LondonMicrosvc
---
Services interpreted at runtime often suffer from slow startup times when components are intitialized at runtime. Ahead of time compilation allows condensing down an application by stripping down unused dependencies and pre-initializing components for a short time to first request served. This is explored by the example of GraalVM and native images.
Key takeaways:
- Be aware what your service contains
- Approaches to improve startup time of a service
- Reduction of resource requirements for a service
Tobias works at Loveholidays.com as a senior software engineer extending it's microservice architecture and turning it more event-driven.
2. Tobias Piper
● Senior Software Engineer at
loveholidays.com
● Book Team
○ Responsible for booking and post-
book systems
○ Integration of payment suppliers
● Services in K8 in GCP
5. Startup time of a service
Application startup can be an essential performance indicator for a service
- Highly volatile load - scaling up and down frequently
- Inconsistent latency / throughput caused by slow starting service
- Short running (cron)jobs
- Pipelines of services
6. Build fast starting microservices
What slows down application startup
- Component loading
- Component initialization
The more luggage you bring, the slower you get
- Backend (e.g. DB) connections
- Custom initialization code
9. Quick JVM 101
Runtime artifact contains:
- Full JVM
- Dependencies pulled in via build system
- Your code
Application startup is slowed down by:
- JIT compilation
- Class initialization
The more luggage you bring, the slower you get
23. Caveats
Native Images are compiled for a target architecture and classes statically loaded at compile time
Static code analysis is quite slow, so bring some time
- you trade faster initialization at runtime for slower build time (seconds to minutes)
- Code inspection / tree shaking is CPU intensive, can your CI worker handle it in real time?
JVM provides dynamic features, which are hard to initialize statically e.g.
● Reflection (examine and manipulate your runtime)
● Dynamic Proxies (Used e.g. by some DI frameworks, like Spring)
● Interpretation for different architectures / environments
Workarounds exist to still allow native image generation
● Delaying class initialization
● Register classes requiring reflection
Configuring the native image build can be quite painful, especially when dealing with 3rd party
dependencies
24. Resources
● Github Repo with example
projects for a Quarkus native
image vs Spring Boot app
● GraalVM Docs
● Native Image creation
explained
● Tree shaking in the webpack
docs
26. Don’t trust the marketing slide
Trying it out is more fun anyways
Code at: https://github.com/loveholidays/quarkus-demo
Frameworks used for comparison
- Spring Boot
- Quarkus
- Quarkus - Native image
$ java -version
openjdk version "11.0.6" 2020-01-14
OpenJDK Runtime Environment GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02)
OpenJDK 64-Bit Server VM GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02, mixed mode, sharing)
27. Let’s try it out - Spring Boot
$ java -jar boot-demo/build/libs/demo-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/ / ___'_ __ _ _(_)_ __ __ _
( ( )___ | '_ | '_| | '_ / _` |
/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
.....
2020-05-06 16:04:20.200 INFO 1948140 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on
port(s): 8081 (http) with context path ''
2020-05-06 16:04:20.203 INFO 1948140 --- [ main] com.loveholidays.demo.DemoApplication : Started DemoApplication
in 6.073 seconds (JVM running for 6.994)
$ ps -au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
toby 817339 12.1 4.1 9099040 676604 pts/2 Sl+ 09:41 0:14 java -jar boot-demo/build/libs/demo-0.0.1-SNAPSHOT.jar
$ time curl http://localhost:8081/foo
0.01s user 0.00s system 1% cpu 0.414 total
28. Let’s try it out - Quarkus JVM mode (uber-jar)
$ java -jar quarkus-demo/build/demo-1.0.0-SNAPSHOT-runner.jar
__ ____ __ _____ ___ __ ____ ______
--/ __ / / / / _ | / _ / //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /
--________/_/ |_/_/|_/_/|_|____/___/
2020-05-11 22:51:12,804 WARN [io.agr.pool] (main) Datasource '<default>': Driver does not support the provided URL:
jdbc:mysql:127.0.0.1:3306/test
2020-05-11 22:51:13,234 INFO [io.quarkus] (main) demo 1.0.0-SNAPSHOT (powered by Quarkus 1.4.2.Final) started in 1.703s.
Listening on: http://0.0.0.0:8080
2020-05-11 22:51:13,236 INFO [io.quarkus] (main) Profile prod activated.
2020-05-11 22:51:13,236 INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache,
jdbc-mysql, narayana-jta, resteasy, resteasy-jsonb]
$ ps -au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
toby 816802 2.8 2.2 9005840 364772 pts/3 Sl+ 09:41 0:03 java -jar quarkus-demo/build/demo-1.0.0-SN...jar
$ time curl http://localhost:8080/foo
0.01s user 0.01s system 16% cpu 0.100 total
29. Let’s try it out - Quarkus native mode
$ quarkus-demo/build/demo-1.0.0-SNAPSHOT-runner
__ ____ __ _____ ___ __ ____ ______
--/ __ / / / / _ | / _ / //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /
--________/_/ |_/_/|_/_/|_|____/___/
2020-05-11 22:23:53,093 INFO [io.quarkus] (main) demo 1.0.0-SNAPSHOT (powered by Quarkus 1.4.2.Final) started in 0.049s.
Listening on: http://0.0.0.0:8080
2020-05-11 22:23:53,093 INFO [io.quarkus] (main) Profile prod activated.
2020-05-11 22:23:53,094 INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache,
jdbc-mysql, narayana-jta, resteasy, resteasy-jsonb]
$ ps -au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
toby 893179 0.1 0.2 1737672 44416 pts/0 Sl+ 09:46 0:00 ./demo-1.0.0-SNAPSHOT-runner
$ time curl http://localhost:8080/foo
0.01s user 0.01s system 2% cpu 0.759 total