Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What's the Magic Behind Quarkus

What's the Magic Behind Quarkus

Quarkus is revolutionizing the way that we develop Java applications for the cloud-native era. Do you want to learn why Quarkus is different from everything else? Then come and join us on this session to take a look at how Quarkus works and the techniques it uses to achieve its dramatic startup speed improvements. As part of this we will also cover the Quarkus extension API, so you can see how to write your own extensions that take advantage of Quarkus’ unique architecture.

Edson Yanaga

July 24, 2019
Tweet

More Decks by Edson Yanaga

Other Decks in Technology

Transcript

  1. !1
    What’s the magic behind Quarkus?
    Edson Yanaga, Red Hat
    @yanaga

    View Slide

  2. !2
    A stack to write Java
    apps
    Cloud Native, Microservices, Serverless

    View Slide

  3. WHY QUARKUS?

    View Slide

  4. From monolith to...
    !4
    ● 1 monolith ≈ 20 microservices ≈ 200 functions
    ● Scale to 1 vs scale to 0
    ● Start up time
    MONOLITH
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    MICRO
    SERVICE
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F
    F F
    F
    F
    F
    F
    F
    F
    F
    F

    View Slide

  5. !5
    Why go through this pain?
    Agility, Scalability, Faster Business Reactivity
    Container platform
    App 1
    Data
    App 2
    Data
    App 3
    Data
    App 4 App 5
    Data

    View Slide

  6. ● Startup overhead
    ○ # of classes, bytecode, JIT
    ● Memory overhead
    ○ # of classes, metadata, compilation
    !6
    The hidden truth about Java + containers
    RSS
    Heap Metaspace off-heap

    View Slide

  7. !7
    Container platform
    Node
    NodeJS
    NodeJS
    NodeJS
    NodeJS
    NodeJS
    NodeJS
    NodeJS
    Node
    Go Go
    Go Go
    Go Go
    Go Go
    Go Go
    Go Go
    Go Go
    Node
    HotSpot Heap
    HotSpot Heap
    HotSpot Heap
    HotSpot Heap
    The hidden truth about Java + containers

    View Slide

  8. WHAT IS QUARKUS?
    QUARK: elementary particle / US: heart of computer science

    View Slide

  9. !9
    A cohesive platform for optimized developer joy:
    ● Based on standards, but not limited
    ● Unified configuration
    ● Zero config, live reload in the blink of an eye
    ● Streamlined code for the 80% common usages,
    flexible for the 20%
    ● No hassle native executable generation
    Benefit No. 1: Developer Joy

    View Slide

  10. !10
    Benefit No. 2: Supersonic Subatomic Java
    Memory (RSS) in Megabytes
    Quarkus + GraalVM
    13 MB
    Quarkus + OpenJDK
    74 MB
    Traditional Cloud-Native Stack
    140 MB
    REST

    View Slide

  11. !11
    Benefit No. 2: Supersonic Subatomic Java
    Memory (RSS) in Megabytes
    REST + CRUD
    Quarkus + GraalVM
    35 MB
    Quarkus + OpenJDK
    130 MB
    Traditional Cloud-Native Stack
    218 MB

    View Slide

  12. !12
    Benefit No. 2: Supersonic Subatomic Java
    Boot + First Response Time (in seconds)
    Quarkus + GraalVM 0.014 Seconds
    REST
    REST + CRUD
    Quarkus + OpenJDK 0.75 Seconds
    Quarkus + GraalVM 0.055 Seconds
    Quarkus + OpenJDK 2.5 Seconds
    Traditional Cloud-Native Stack 9.5 Seconds
    Traditional Cloud-Native Stack 4.3 Seconds
    Time to first response

    View Slide

  13. !13
    Benefit No. 3: Unifies Imperative and Reactive
    ● Combine both Reactive and imperative development in the same application
    ● Use the technology that fits your use-case
    ● Key for reactive systems based on event driven apps
    @Inject
    SayService say;
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
    return say.hello();
    }
    @Inject @Stream(”kafka”)
    Publisher reactiveSay;
    @GET
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public Publisher stream() {
    return reactiveSay;
    }

    View Slide

  14. !14
    Benefit No. 4: Best of Breed Frameworks & Standards
    Eclipse Vert.x Hibernate RESTEasy Apache Camel Eclipse MicroProfile Netty
    Kubernetes OpenShift Jaeger Prometheus Apache Kafka Infinispan

    View Slide

  15. GraalVM
    You keep using that word.
    I do not think it means what you think it means.
    The Enabler

    View Slide

  16. !16
    JVM CI
    Sulong (LLVM)
    Truffle
    Graal Compiler
    Substrate VM
    Java HotSpot VM

    View Slide

  17. Closed-world assumption
    !17
    Dead code elimination
    Substrate
    VM
    Classes
    JDK
    Classes
    JDK
    Classes
    Substrate
    VM
    Classes
    Java
    Application
    Classes
    Java
    Application
    Classes
    Native
    Executable

    View Slide

  18. !18
    Not supported
    The Dark Side
    ● Dynamic classloading
    ● InvokeDynamic & Method handles
    ● Finalizer
    ● Security manager
    ● JVMTI, JMX, native VM Interfaces
    OK with caveats in usage
    ● Reflection (manual list)
    ● Dynamic proxy (manual list)
    ● JNI (manual list)
    ● Static initializers
    ● Lambda, Threads (OK, pfff!)
    ● References (similar)

    View Slide

  19. !19
    Not supported
    The Dark Side
    ● Dynamic classloading
    ● InvokeDynamic & Method handles
    ● Finalizer
    ● Security manager
    ● JVMTI, JMX, native VM Interfaces
    OK with caveats in usage
    ● Reflection (manual list)
    ● Dynamic proxy (manual list)
    ● JNI (manual list)
    ● Static initializers
    ● References (similar)
    The Good Parts

    View Slide

  20. HOW QUARKUS
    WORKS

    View Slide

  21. !21
    What does a framework do at startup time
    Move startup time to build time
    ● Parse config files
    ● Classpath & classes scanning
    ○ for annotations, getters or other metadata
    ● Build framework metamodel objects
    ● Prepare reflection and build proxies
    ● Start and open IO, threads etc

    View Slide

  22. !22
    Do the work once, not at each start
    All the bootstrap classes are no longer loaded
    Less time to start, less memory used
    Less or no reflection nor dynamic proxy
    Build time benefits

    View Slide

  23. !23
    Drives the gathering of metadata needed by GraalVM
    More Build time benefits
    ● based on framework knowledge
    ● Classes using reflection, resources, etc
    Minimize dependencies
    Help dead code elimination

    View Slide

  24. !24
    The end result of a Quarkus build
    should be just enough bytecode to
    start the services that your application
    requires
    Anatomy of a Quarkus Application

    View Slide

  25. !25
    Traditional Application
    Application Startup
    ● Scan for annotations
    ● Parse descriptors
    ● Generate metamodel
    ● Start Services
    Quarkus
    ● Start Services

    View Slide

  26. !26
    The final application contains
    Anatomy of a Quarkus Application
    ● Your (possibly transformed) application code
    ● All libraries needed for runtime
    ● Generated code to wire up and start your services
    ● Generated CDI (ArC) bean classes

    View Slide

  27. !27
    Quarkus Extensions
    RESTEasy
    Netty
    Hibernate ORM
    Hibernate Validator
    MP OpenAPI
    MP JWT
    Eclipse Vert.X
    Agroal (conn pool)
    Narayana JTA
    MP Reactive
    Messaging
    Apache Camel
    ...
    Quarkus Core
    Arc (DI)
    Jandex Gizmo Graal SDK
    HotSpot SubstrateVM

    View Slide

  28. !28
    Quarkus Consists of Two Parts
    Core Runtime
    Core Deployment
    Undertow Runtime
    Undertow
    Deployment
    ArC Runtime
    ArC Deployment

    View Slide

  29. !29
    Build Process
    Compile
    Provision
    (curate)
    Wiring &
    Assemble
    (deployment) AOT Native
    Compilation
    Hotspot Runnable & Image
    Native Executable &
    Image
    app.jar frameworks Runnable java app native-app

    View Slide

  30. !30
    Provisioning

    View Slide

  31. !31
    Provisioning Phase
    ● Applications only depend on runtime components
    ● But we need the deployment components to execute the build
    ● Provisioning phase resolves the required deployment
    dependencies

    View Slide

  32. !32
    Provisioning Phase
    ● Extensions contain a quarkus-extension.properties, generated
    by the extension-maven-plugin
    ● This tells Quarkus what the corresponding deployment artifact is

    View Slide

  33. !33
    Deployment

    View Slide

  34. !34
    Creating the runnable application
    Augmentation Phase
    ● Processing done by @BuildStep methods
    ● All processors produce and consume BuildItem
    instances
    ● Ordering is based on a dependency graph, a build step is
    executed when all its dependencies are available

    View Slide

  35. !35
    BuildItem
    ● All information flows through this process via BuildItem
    instances
    ● Two types, SimpleBuildItem and MultiBuildItem
    ● A @BuildStep method will be run as soon as all the items it
    depends on have been produced
    ● The build is seeded with some initial items (e.g. the current
    application root)
    ● The build asks for some specific outputs (e.g.
    GeneratedClassBuildItem)
    ● Core build items are in io.quarkus.deployment.builditem

    View Slide

  36. !36
    Build Graph
    ● The build is a directed graph, it starts with the requested
    outputs, and then figures out which @BuildStep
    methods it needs to call to achieve this and in what order
    ● If your method does not produce anything it needs then it
    is not called

    View Slide

  37. !37
    CombinedIndexBuildItem
    Important Items
    ● Holds the Jandex annotation index
    ● Can be used to look at any annotation or type hierarchy

    View Slide

  38. !38
    AdditionalBeanBuildItem
    Important Items
    ● Producing this turns a given class into a CDI bean
    ● If you have classes in your runtime module that you want to be
    beans you should produce one of these

    View Slide

  39. !39
    Configuration

    View Slide

  40. !40
    Declarative Config
    Configuration
    ● Configuration is done via @ConfigRoot objects
    ● All config is under the quarkus.* namespace
    ● All config must have javadoc, which used as the
    documentation in the generated config file

    View Slide

  41. !41
    Bytecode
    Recording

    View Slide

  42. !42
    Recorders let you invoke on an object
    at deployment time, but the actual
    invocation gets delayed to runtime.
    Bytecode Recording

    View Slide

  43. !43
    Serializing logic and data
    Bytecode Recording
    ● Recording allows you to specify what happens at startup time, without knowing
    anything about bytecode
    ● Invocations made on a recorder are written to bytecode and executed at runtime
    ● Primitives, JavaBean style objects and collections can all be passed as arguments
    ● The return values can be passed into other recorders (although cannot be used
    directly)

    View Slide

  44. !44
    Return Values
    ● The return value from a recorder cannot be used directly (the object it
    represents has not actually been created yet)
    ● But they can be passed to other recorders methods
    ● We do this by creating proxies, so if the return type cannot be proxied
    wrap it in a RuntimeValue<>
    ● This does not have to be the same recorder, or even the same build step
    ● To pass them between build steps wrap them in a BuildItem

    View Slide

  45. !45
    Native
    Image

    View Slide

  46. !46
    Quarkus simplifies the process
    Substrate
    ● SubstrateVM has a lot of limitations compared to a normal JVM
    ● Quarkus provides tools to easily work around these limitations
    ● Most of these take the form of build items to explicitly request
    substrate functionality
    ● For a full list see io.quarkus.deployment.builditem.substrate package
    ● Also we support compile time boot

    View Slide

  47. !47
    Not supported
    The Dark Side
    ● Dynamic classloading
    ● InvokeDynamic & Method handles
    ● Finalizer
    ● Security manager
    ● JVMTI, JMX, native VM Interfaces
    OK with caveats in usage
    ● Reflection (manual list)
    ● Dynamic proxy (manual list)
    ● JNI (manual list)
    ● Static initializers
    ● Lambda, Threads (OK, pfff!)
    ● References (similar)

    View Slide

  48. !48
    ReflectiveClassBuildItem
    Native Build Items
    ● Reflection does not work in native images unless it is explicitly
    enabled
    ● This build item allows you to enable reflection for a given class
    ● Fine grained, so you can choose if you want methods, fields and
    constructors registered

    View Slide

  49. !49
    ReflectiveHierarchyBuildItem
    Native Build Items
    ● Registers everything about the class for reflection
    ● Supertypes, Field types, method parameters etc
    ● Good for serialization use cases, where you need to set everything
    via reflection

    View Slide

  50. !50
    SubstrateResourceBuildItem
    Native Build Items
    ● Resources are not included by default in SubstrateVM
    ● Using this build item you can specify resources that you want to
    include in the image

    View Slide

  51. !51
    Boot once, run everywhere
    Compile time boot
    ● When SubstrateVM creates a native image it can run java static initializers as
    part of the process
    ● These run in a normal JVM, with no restrictions
    ● The results are serialized directly into the native image
    ● If you record code with @Record(ExecutionTime.STATIC_INIT) then this code will
    be run once at native image build time
    ● The results are directly unpacked into memory when the native image is actually
    run

    View Slide

  52. !52
    Testing

    View Slide

  53. !53
    Unit and Integration Tests
    Extension Testing Framework
    ● @QuarkusUnitTest can be used to test a different application for
    each test class
    ● Quarkus is started and stopped between each class
    ● @QuarkusTest can also be used (especially for native image), but
    needs its own ‘integration-tests’ module
    ● A comprehensive test suite will generally have both

    View Slide

  54. !54
    Thank you.

    View Slide