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

Faster, greener, and happier- why Quarkus should be your next tech stack

Faster, greener, and happier- why Quarkus should be your next tech stack

Java never went away, but it’s having a renaissance. After some initial teething pains on the cloud (too big, too slow, too hard to configure) a new breed of Java frameworks are changing everything. In this talk, Holly will introduce Quarkus and then delve into some of the advanced features you might not know about. She’ll cover native binaries, what makes Quarkus super-fast running on the JVM, TDD with Quarkus, and Quarkus’s carbon footprint. The talk includes some theory (what underpins Quarkus’s surprising speed?) and also live demos (does Quarkus really start faster than a light bulb? What does an integration testing flow with Quarkus look like?)

Holly Cummins

November 30, 2023
Tweet

More Decks by Holly Cummins

Other Decks in Programming

Transcript

  1. Holly Cummins Senior Principal Software Engineer, quarkus Cloud Builders Java

    Conf November 20, 2023 @[email protected] faster greener happier why quarkus should be your next tech stack
  2. @holly_cummins #RedHat Container platform um … no machine node.js node.js

    node.js node.js node.js node.js node.js machine go go go go go go go go go go go go go go
  3. @holly_cummins #RedHat Container platform um … no machine HotSpot Heap

    HotSpot Heap HotSpot Heap HotSpot Heap machine node.js node.js node.js node.js node.js node.js node.js machine go go go go go go go go go go go go go go
  4. @holly_cummins #RedHat “I can’t bring up the microservices in my

    Java dev stack … on my brand new Apple laptop with a M1 chip and 64GB of RAM.” - fintech developer
  5. @holly_cummins #RedHat traditional cloud-native java stack traditional cloud-native java stack

    traditional cloud-native java stack traditional cloud-native java stack node.js node.js node.js node.js node.js node.js node.js go go machine go go go go go go go go go go go go go go go go go go go quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus quarkus spoiler: we did better :) container orchestration machine machine machine https:/ /developers.redhat.com/blog/2017/03/14/java-inside-docker/
  6. @holly_cummins #RedHat machine quarkus quarkus quarkus quarkus quarkus quarkus quarkus

    quarkus quarkus quarkus quarkus quarkus quarkus quarkus container orchestration machine traditional cloud-native java stack traditional cloud-native java stack traditional cloud-native java stack traditional cloud-native java stack … a lot better quarkus native
  7. @holly_cummins #RedHat machine quarkus quarkus quarkus quarkus quarkus quarkus quarkus

    quarkus quarkus quarkus quarkus quarkus quarkus quarkus container orchestration machine traditional cloud-native java stack traditional cloud-native java stack traditional cloud-native java stack traditional cloud-native java stack … a lot better quarkus native (but quarkus on jvm is also way smaller than traditional java)
  8. do quarkus applications start faster? quarkus + graalvm 0.014 Seconds

    REST quarkus + open jdk 0.75 Seconds traditional cloud-native stack 4.3 Seconds https://quarkus.io/blog/runtime-performance/
  9. ok but does startup time matter? fast boot time means

    auto-scaling works better more resilience to load spikes
  10. quarkus + GraalVM 13 MB quarkus + OpenJDK 74 MB

    Traditional Cloud-Native Stack 140 MB rest application https://quarkus.io/blog/runtime-performance/ does quarkus improve memory utilization?
  11. #Quarkus @holly_cummins hey, wanna see quarkus? hey, wanna see quarkus?

    hey, wanna see quarkus? hey, wanna see quarkus? hey, wanna see quarkus?
  12. #Quarkus @holly_cummins hey, wanna see quarkus? hey, wanna see quarkus?

    hey, wanna see quarkus? hey, wanna see quarkus? hey, wanna see quarkus? uhh … are you supposed to shut down applications after using them?
  13. #Quarkus @holly_cummins hey, wanna see quarkus? hey, wanna see quarkus?

    hey, wanna see quarkus? hey, wanna see quarkus? hey, wanna see quarkus? uhh … are you supposed to shut down applications after using them? 120 instances (!)
  14. do quarkus applications have higher throughput? 48 concurrent connections quarkus

    native 3212 req/s https://www.redhat.com/en/resources/mi-quarkus-lab-validation-idc-analyst-paper
  15. do quarkus applications have higher throughput? 48 concurrent connections traditional

    cloud native stack 3555 req/s quarkus native 3212 req/s https://www.redhat.com/en/resources/mi-quarkus-lab-validation-idc-analyst-paper
  16. do quarkus applications have higher throughput? 48 concurrent connections traditional

    cloud native stack 3555 req/s quarkus on jvm 6389 req/s quarkus native 3212 req/s https://www.redhat.com/en/resources/mi-quarkus-lab-validation-idc-analyst-paper
  17. traditional cloud native stack 3555 req/s quarkus on jvm 6389

    req/s quarkus native 3212 req/s https://www.redhat.com/en/resources/mi-quarkus-lab-validation-idc-analyst-paper
  18. traditional cloud native stack 3555 req/s quarkus on jvm 6389

    req/s quarkus native 3212 req/s https://www.redhat.com/en/resources/mi-quarkus-lab-validation-idc-analyst-paper a trade-off of throughput against footprint
  19. traditional cloud native stack 3555 req/s quarkus on jvm 6389

    req/s quarkus native 3212 req/s https://www.redhat.com/en/resources/mi-quarkus-lab-validation-idc-analyst-paper no trade-off, just better :) a trade-off of throughput against footprint
  20. @holly_cummins #RedHat 2010 multiple applications share a single application server

    instance application re-deployed many times between server restarts application dependencies changed while it is running
  21. @holly_cummins #RedHat a highly dynamic runtime in a container is

    pointless loading classes that aren’t needed
  22. @holly_cummins #RedHat a highly dynamic runtime in a container is

    pointless loading classes that aren’t needed expensive, slow, reflection
  23. @holly_cummins #RedHat a highly dynamic runtime in a container is

    pointless loading classes that aren’t needed expensive, slow, reflection the same initialisation on every startup
  24. @holly_cummins #RedHat how does a framework start? @ @ </>

    packaging (maven, gradle…) build time runtime
  25. @holly_cummins #RedHat @ @ </> load and parse config files,

    properties, yaml, xml, etc. build time runtime how does a framework start?
  26. @holly_cummins #RedHat @ @ </> • classpath scanning and annotation

    discovery • attempt to load class to enable/disable features build time runtime how does a framework start?
  27. @holly_cummins #RedHat @ @ </> build a metamodel of the

    world build time runtime how does a framework start?
  28. @holly_cummins #RedHat @ @ </> start thread pools, I/O, etc.

    build time runtime how does a framework start?
  29. @ @ </> doing more up-front enables better devex @

    @ </> build time runtime runtime build time
  30. @ @ </> doing more up-front enables better devex @

    @ </> build time runtime runtime build time we can do cool code introspections here that would be too expensive and annoying to do at runtime
  31. @holly_cummins #RedHat tests are run on every code change “reverse

    code coverage” means only relevant tests run mvn quarkus:dev continuous testing
  32. @holly_cummins #RedHat testcontainers integration … without quarkus @TestConfiguration(proxyBeanMethods = false)

    public class ContainersConfig { @Bean @ServiceConnection public PostgreSQLContainer<?> postgres() { return new PostgreSQLContainer<>(DockerImageName.parse("postgres:14")); } } public class TestApplication { public static void main(String[] args) { SpringApplication .from(MySpringDataApplication::main) .with(ContainersConfig.class) .run(args); } } @Import(ContainersConfig.class)
  33. @holly_cummins #RedHat zero-config testcontainers integration the only thing you need

    to do to make testcontainers work is not configure anything # configure your datasource quarkus.datasource.db-kind = postgresql quarkus.datasource.username = sarah quarkus.datasource.password = connor quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/mydatabase # drop and create the database at startup quarkus.hibernate-orm.database.generation = drop-and-create
  34. @holly_cummins #RedHat zero-config testcontainers integration the only thing you need

    to do to make testcontainers work is not configure anything # drop and create the database at startup quarkus.hibernate-orm.database.generation = drop-and-create
  35. @holly_cummins #RedHat zero-config testcontainers integration the only thing you need

    to do to make testcontainers work is not configure anything
  36. @holly_cummins #RedHat zero-config testcontainers integration the only thing you need

    to do to make testcontainers work is not configure anything quarkus also auto-invokes flyway and liquibase
  37. @holly_cummins #RedHat zero-config testcontainers integration realistically, use profiles so things

    work in production :) # configure your datasource %prod.quarkus.datasource.db-kind = postgresql %prod.quarkus.datasource.username = sarah %prod.quarkus.datasource.password = connor %prod.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/mydatabase # on real databases, defaults to ‘none’, but let’s validate %prod.quarkus.hibernate-orm.database.generation = validate
  38. @holly_cummins #RedHat • databases • redis • keycloak • kafka

    • elasticsearch • kubernetes • … or add your own auto-provision services “dev services” using testcontainers under the hood
  39. @holly_cummins #RedHat package com.example; import org.jboss.logging.Logger; public class MyService {

    private static final Logger log = Logger.getLogger(MyService.class); public void doSomething() { log.info("It works!"); } } example: logging
  40. @holly_cummins #RedHat package com.example; import org.jboss.logging.Logger; public class MyService {

    private static final Logger log = Logger.getLogger(MyService.class); public void doSomething() { log.info("It works!"); } } example: logging import io.quarkus.logging.Log; Log
  41. @holly_cummins #RedHat package org.acme; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public

    class SpringDemo { public static void main(String[] args) { SpringApplication.run(SpringDemo.class, args); } } example: declaring an application
  42. @holly_cummins #RedHat @ApplicationScoped public class GreetingRepository { public Entity findByName(int

    name) { return find("name", name).firstResult(); } void persist(Entity entity) {} void delete(Entity entity) {} Entity findById(Id id) {} List<Entity> list(String query, Sort sort, Object... params) { return null; } Stream<Entity> stream(String query, Object... params) { return null; } long count() { return 0; } long count(String query, Object... params) { return 0; } } example: panache + hibernate
  43. @holly_cummins #RedHat example: panache + hibernate @ApplicationScoped public class GreetingRepository

    implements PanacheRepository<Greeting> { public Entity findByName(int name) { return find("name", name).firstResult(); } }
  44. @holly_cummins #RedHat DAO example: panache + hibernate @ApplicationScoped public class

    GreetingRepository implements PanacheRepository<Greeting> { public Entity findByName(int name) { return find("name", name).firstResult(); } } repository pattern
  45. @holly_cummins #RedHat example: panache + hibernate active record pattern @Entity

    public class Greeting extends PanacheEntity { public String name; public LocalDate issued; @Version public int version; public static List<Greeting> getTodaysGreetings() { return list("date", LocalDate.now()); } }
  46. @holly_cummins #RedHat int port = 8081; ClientInterceptor[] interceptors = new

    ClientInterceptor[3]; interceptors[0] = new EventLoopBlockingCheckInterceptor(); interceptors[1] = new IOThreadClientInterceptor(); interceptors[2] = new StorkMeasuringGrpcInterceptor(); // etc Channel channel = ManagedChannelBuilder .forAddress(“localhost", port) .usePlaintext() .build(); GreeterGrpc.GreeterStub greeter = GreeterGrpc .newStub(channel) .withInterceptors(interceptors); example: gRPC
  47. @holly_cummins #RedHat the old ways all still work but you

    don’t have to type all the stuff unless you want to magic optional
  48. @holly_cummins #RedHat <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-spring-web</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-spring-data-jpa</artifactId> </dependency>

    ok but we use spring option 1: compatibility libraries option 2: migration tooling • migration toolkit for applications (mta) • windup • open rewrite
  49. @holly_cummins #RedHat “After a week of development with quarkus, I

    was able to regain the same level of productivity as when I was developing with Spring Boot.” – Fawaz Paraïso, Decathlon
  50. @holly_cummins #RedHat Emiliia Nesterovych Emmanuel Bernard Emre Kaplan Enrique gonzález

    Martínez Enrique Mingorance Cano Eoin Gallinagh Eric Deandrea Eric Wittmann Erik Åsén Erik Mattheis Erin Schnabel Eugene Berman Evan Shortiss Fabricio Gregorio faculbsz Falko Modler Fedor Dudinskiy Felipe Carvalho dos Anjos Formentin Felipe Henrique Gross Windmoller Fernando Comunello Fernando Henrique fhavel Fikru Mengesha Filippe Spolti Florian Beutel Florian Bütler Florian Heubeck Florin Botis Foivos Zakkak Foobartender Fouad Almalki Francesco Nigro Francisco Javier Tirado Sarti Francois Steyn Frank Eichfelder franz1981 freakse-sa Fred Bricon Frédérc Blanc Freeman Fang Fu Cheng Gabriele Cardosi Galder Zamarreño galiacheng Gavin King Gavin Ray Geert Schuring Geoffrey De Smet Geoffrey GREBERT Georg Leber George Gastaldi manofthepeace Manyanda Chitimbo Marat Gubaidullin Marc Nuri Marc Schlegel Marc Wrobel Marcel Hanser Marcel Lohmann Marcell Cruz Marcelo Pereira Marcin Czeczko Marcin Kłopotek Marco Bungart Marco Schaub Marco Yeung Marco Zanghì Marcus Paulo Marek goldmann Marek Skacelik Marián Macik Mario Fusco MarioHNogueira Mark Lambert Mark Little Mark McLaughlin Mark Sailes marko-bekhta Markus Heberling Markus Himmel Markus Schwer Martin C. Richards Martin Grammelspacher Martin Kouba Martin Muzikar Martin Panzer Martin Weiler martin-kofoed-jyskebank-dk MartinWitt Marvin B. Lillehaug masini Matej Novotny Matej Vasek Matheus Cruz Mathias Holzer Matteo Mortari Matthias Andreas Benkard Matthias Cullmann mauroal Max Andersen Max Gabrielsson Max Rydahl Andersen Victor Hugo de Oliveira Molinar Vincent Sevel Vincent van Dam Vinícius Ferraz Campos Florentino Viswa Teja Nariboina Vladimir Konkov Vojtech Juranek Vratislav Hais w.glanzer Walter Medvedeo Wayne Ellis Werner Glanzer Willem Jan Glerum William Antônio Siqueira Wim goeman Wippermueller, Frank wojciech.stryjewski Xavier Xieshen xstefank Y. Luis Yann-Thomas LE MOIGNE Yannick Reifschneider YassinHajaj Yelzhas Suleimenov yesunch9 Yoann Rodière Yoshikazu Nojima Youngmin Koo Yubao Liu yugoccp Yukihiro Okada Zaheed Beita zanmagerl zedbeit Zheng Feng Žiga Deisinger Zineb Bendhiba zohar Zoran Regvart Шумов Игорь Юрьевич 出 门 三不惹 open source community of contributors
  51. @holly_cummins #RedHat step 1: measure power usage wall power measurement

    more complete needs access to the wall and equipment
  52. @holly_cummins #RedHat step 1: measure power usage wall power measurement

    more complete needs access to the wall and equipment RAPL
  53. @holly_cummins #RedHat step 1: measure power usage wall power measurement

    more complete needs access to the wall and equipment RAPL programmatically accessible
  54. @holly_cummins #RedHat step 1: measure power usage wall power measurement

    more complete needs access to the wall and equipment RAPL programmatically accessible misses some components
  55. @holly_cummins #RedHat step 1: measure power usage wall power measurement

    more complete needs access to the wall and equipment data costs carbon RAPL programmatically accessible misses some components
  56. @holly_cummins #RedHat density Source: Clement Escoffier experiment 1: cloud Setup:

    • 800 requests/second, over 20 days • SLA > 99% • AWS instances Assumptions: • Costs are for us-east-1 data centre
  57. @holly_cummins #RedHat Setup: • 800 requests/second, over 20 days •

    SLA > 99% Assumptions: Source: Clement Escoffier x Teads cloud carbon impact of framework choice interpolated carbon metrics
  58. @holly_cummins #RedHat Setup: • 800 requests/second, over 20 days •

    SLA > 99% Assumptions: Source: Clement Escoffier x Teads cloud carbon impact of framework choice the carbon is lower because the cost is lower interpolated carbon metrics
  59. @holly_cummins #RedHat Setup: • REST + CRUD • large heap

    • RAPL energy measurement • multiple instances to support high load
 Assumptions: • US energy mix Source: John O’Hara experiment 2: RAPL measurements
  60. @holly_cummins #RedHat Setup: • REST + CRUD • large heap

    • RAPL energy measurement • multiple instances to support high load
 Assumptions: • US energy mix Source: John O’Hara experiment 2: RAPL measurements quarkus on JVM has the lowest carbon … because it has the highest throughput
  61. • quarkus cuts carbon by ~2-3x* • native consumes more

    carbon than JVM carbon measurements: conclusions
  62. @holly_cummins #RedHat “We can run 3 times denser deployments without

    sacrificing availability and response times of services. quarkus live coding is a really good thing: Making changes and reloading pages instantaneously is a great feature.” – Fawaz Thorsten Pohl, Lufthansa AVIATAR
  63. @holly_cummins #RedHat 2019: Moved digital experience to quarkus (from Spring

    Boot) • Startup times 40s ➡ 12s • RAM 800 MB ➡ 360 MB • Developer productivity ⬆ 30-40% – Christos Sotiriou, Vodafone Greece
  64. @holly_cummins #RedHat tl;dpa (too long didn’t pay attention) deployment density

    lower cloud bill frictionless development experience Medium Nano auto-provision services zero-config live coding continuous testing developer UI greener