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

CodeFest 2019. Никита Липский (Excelsior) — Невыносимая легкость AOT-компиляции Spring приложений

CodeFest 2019. Никита Липский (Excelsior) — Невыносимая легкость AOT-компиляции Spring приложений

Spring framework использует, пожалуй, весь набор динамических свойств Java: Spring Boot приложения грузятся своим загрузчиком классов, повсеместно используются reflection, порождение и загрузка Java байт-кода на лету и т.д.

С другой стороны, в мире микросервисов набирает популярность статическая AOT компиляция Java приложений, для решения проблем быстрого старта, предсказуемой производительности, мгновенного достижения пиковой производительности. Становится интересно: может ли динамичность Spring framework ужиться со статической компиляцией?

Ответ — да, может. В этом докладе я на примере поддержки Spring Boot приложений в AOT-центричной JVM Excelsior JET покажу, как динамические свойства Java, используемые в Spring framework, могут работать совместно с AOT-порожденным машинным кодом.

CodeFest

April 06, 2019
Tweet

More Decks by CodeFest

Other Decks in Programming

Transcript

  1. Никита Липский ? •  Инициатор проекта Excelsior JET –  работал

    над проектом более 18 лет –  как идейный вдохновитель –  компиляторный инженер –  руководитель –  и много в каких еще ролях •  twitter: @pjBooms •  team blog: https://www.excelsiorjet.com/blog 9
  2. Excelsior JET? •  Полная реализация Java SE –  c 2005

    года cертифицирована как Java Compatible •  AOT compiler + Java Runtime –  смешанная компиляция: AOT + JIT –  поддержка нестандартных загрузчиков классов в AOT режиме (для Eclipse RCP, Tomcat) •  Toolkit –  Startup Optimizer –  Deployment 10
  3. Никита Липский ? •  Инициатор проекта Excelsior JET –  работал

    над проектом более 18 лет –  как идейный вдохновитель –  компиляторный инженер –  руководитель –  и много в каких еще ролях •  twitter: @pjBooms •  team blog: https://www.excelsiorjet.com/blog 11
  4. Секретная биография ? •  1.5 года руководства разработкой интернет сервиса

    –  Spring (MVC, Security, AOP, etc.) –  JPA (EclipseLink) –  MySQL –  Liquibase –  ELK –  Angular –  Amazon EC2, EBS 12
  5. План доклада •  Spring –  context, configuration, classpath scanning, bean

    definitions processing, DI •  Spring Boot –  auto configuration, @SpringBootApplication, Spring Boot executable archive •  Как Spring работает на уровне JVM –  reflection, dynamic proxies •  Как Spring AOT компилируется –  почему все продолжает работать •  Бенчмарки на производительность, стартап
  6. Spring Application Context @Component class MyComponent @Service class MyService @Configuration

    class MyConfig { @Bean MyBean myBean(){ new MyBean(); } } Context
  7. @Autowired Object postProcess(Object bean, String beanName) { Field[] fields =

    bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); ReflectionUtils.setField(field, bean, cxt.getBean(field.getType()); } } return bean; }
  8. @Configuration @Configuration class MyConfig { @Bean MyBean1 myBean1() { new

    MyBean1(); } @Bean MyBean2 myBean2() { new MyBean2(myBean1()); } }
  9. Auto @Configuration @Configuration // Some conditions class MyAutoConfiguration { //

    Auto-configured beans @Configuration @ConditionalOnClass(EmbeddedAcmeService.class) static class EmbeddedConfiguration { @Bean @ConditionalOnMissingBean public EmbeddedAcmeService embeddedAcmeService() { ... } } }
  10. @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan @SpringBootApplication public class

    Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
  11. Spring Boot Executable архив +---org | \---springframework | \---boot |

    \---loader | | JarLauncher.class | | LaunchedURLClassLoader.class | +---jar | | JarFile.class | \---BOOT-INF +---classes | \—example | Example.class | +---lib | spring-core.jar, spring-boot.jar, spring-web.jar
  12. Spring Boot Executable архив •  LaunchedURLClassLoader грузит классы из BOOT-INF/classes,

    BOOT-INF/lib/* •  Доступ к классам жаров из BOOT-INF/lib осуществляется через свою реализацию JarFile
  13. Spring Boot •  Все такое динамичное: –  Везде reflection – 

    Разбор аннотаций –  Генерация и загрузка proxy классов –  Рантайм связывание Как такой AOT?
  14. Spring Boot •  Все такое динамичное: –  Везде reflection – 

    Разбор аннотаций –  Генерация и загрузка proxy классов –  Рантайм связывание Как такой AOT?
  15. Reflection field.set(bean, cxt.getBean("beanName")); Parameter[] cparams = constr.getParameters(); //if cparams.length ==

    1 constr.newInstance( cxt.getBean(cparams[0].getName())); method.invoke(bean, cxt.getBean(mparams[0].getName()));
  16. Reflection //from java/lang/Class.java private native Field[] getDeclaredFields0(boolean publicOnly); private native

    Method[] getDeclaredMethods0(boolean publicOnly); private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
  17. JVM OS + CPU Monitoring AOT Class files Classloading engine

    Bytecode Verification Execution engine: interpreter, JIT Threading Synchronization Meta information Memory management, Garbage Collection Native methods
  18. JVM •  JVM при загрузке классов строит их рантайм представление

    и складывает результат в Metaspace •  Reflection реализован через прямой доступ к Metaspace
  19. JVM + AOT •  В JVM с AOT компилятором Reflection

    работает практически также как в обычной JVM за тем лишь исключением, что рантайм представление класса строится AOT компилятором до исполнения
  20. Java Runtime JDK classes JVM Metaspace C1 C2 C3 C4

    C5 C6 Reflection Executable Meta data Native code GC JIT Threading
  21. Java Runtime Java File System OS OS File System Executable

    Meta data Native code Embedded File System Jar1 Jar2 Jar3
  22. Classpath •  Jars внутри Exe формируют свою (виртуальную) файловую систему

    и монтируются к Java файловой системе вместе с OS файловой системой.
  23. Classpath •  URL из classpath ccылаются на эти виртуальные файлы.

    •  getResource() загрузчика через java.util.zip находит ресурсы внутри jars зашитых в executable.
  24. Classpath Но в jars лежат не только ресурсы, но и

    классы. Они тоже попадают в Exe?
  25. Synthetic Class Files Проблема: спрингу нужны классы приложения во время

    исполнения. Решение: порождать их из метаинформации
  26. Synthetic Class Files Проблема: спрингу нужны классы приложения во время

    исполнения. Решение: порождать их из метаинформации
  27. AOT + JIT Spring порождает классы: •  Spring AOP – Порождение

    Proxy класса, который перед выполнением кода проксируемого класса исполняет код аспекта (пример @Transactional)
  28. AOT + JIT Spring порождает классы: •  Для @Configuration классов

    – порождение наследника переопределяющего @Bean методы
  29. AOT + JIT Вопрос: как загружаются классы порожденные Spring в

    случае AOT? Ответ: c помощью JIT компилятора (линковка с AOT кодом через metaspace)
  30. Executable Meta data Native code Resources Java Runtime JDK classes

    JVM OS+CPU DynProxy JITed code Classes JIT getProxy()
  31. AOT + JIT Вопрос: как загружаются классы порожденные Spring в

    случае AOT? Ответ: c помощью JIT компилятора (линковка с AOT кодом через metaspace)
  32. AOT + JIT Вопрос: как загружаются классы порожденные Spring в

    случае AOT? Ответ: c помощью JIT компилятора (линковка с AOT кодом через metaspace)
  33. Нестандартные загрузчики классов •  Переопределяют умолчательную логику разрешений ссылок между

    классами •  Уникальное пространство имен •  Позволяют управлять зависимостями •  В случае Spring Boot позволяют прятать зависимости внутрь Spring Boot executable jar 118
  34. Нестандартные загрузчики классов Как компилировать статически? •  Компилировать каждый класс

    изолировано от других –  Плохо для производительности •  Изучить логику разрешения ссылок для популярных загрузчиков 119
  35. Нестандартные загрузчики классов Схема поддержки загрузчиков в AOT: •  Во

    время AOT компиляции: –  Разрешение ссылок между классами согласно логики загрузчика •  Во время исполнения: –  Назначение каждому предкомпилированному классу соответсвующего инстанса загрузчика Работает для Eclipse RCP и Tomcat. В Spring Boot один загрузчик – все много проще. 120
  36. Java application Jar1 Jar2 Jar3 Executable Native code Resources Jar1

    Jar2 Jar3 Java Runtime JDK classes JVM Reflection GC JIT Meta data
  37. Промежуточный итог Хоть все и не просто, но это все

    реально работает! Вопрос, но как быстро?
  38. Промежуточный итог Хоть все и не просто, но это все

    реально работает! Вопрос, но как быстро?
  39. Spring Boot Startup •  Dave Syer бенчмарк (https://github.com/dsyer/spring-boot-startup-bench) –  configserver

    – launched on Spring Boot 1.4 and 1.5 framework versions –  demo application – launched on Spring Boot 1.4, 1.5 and 2.0 versions –  minimal – launched on Spring Boot 1.5. Disabled auto configuration –  Petclinic – classic Petclinic sample launched on Spring Boot 1.5.9. –  Petclinic-latest – the same app launched on the latest Spring Boot (2.1.0)
  40. Spring Boot Startup 0% 20% 40% 60% 80% 100% 120%

    ConfigServer14x ConfigServer15x Minimal Petclinic Petclinic21x SpringBoot14x SpringBoot15x SpringBoot20x Average Fat jar HotSpot Fat jar JET Exploded HotSpot Exploded JET
  41. Spring Boot Startup Вопрос: Как синтетические класс файлы влияют на

    стартап. Ответ: Ускоряют (незначительно) Причина: Синтетические классы ~ в два раза меньше оригинальных – время на их синтез меньше, чем издержки на дальнейшее чтение
  42. Spring Boot Startup Вопрос: Как синтетические класс файлы влияют на

    стартап. Ответ: Ускоряют (незначительно) Причина: Синтетические классы ~ в два раза меньше оригинальных – время на их синтез меньше, чем издержки на дальнейшее чтение
  43. Spring Boot Startup Вопрос: Как синтетические класс файлы влияют на

    стартап. Ответ: Ускоряют (незначительно) Причина: Синтетические классы ~ в два раза меньше оригинальных – время на их синтез меньше, чем издержки на дальнейшее чтение
  44. Spring Boot Startup Вопрос: Как джитование динамически порожденных классов влияет

    на стартап. Ответ: Значительно. На текущий момент 40% времени старта Решение: Мы подумываем над реализацией интерпретатора
  45. Spring Boot Startup Вопрос: Как джитование динамически порожденных классов влияет

    на стартап. Ответ: Значительно. На текущий момент 40% времени старта Решение: Мы подумываем над реализацией интерпретатора
  46. Spring Boot Startup Вопрос: Как джитование динамически порожденных классов влияет

    на стартап. Ответ: Значительно. На текущий момент 40% времени старта Решение: Мы подумываем над реализацией интерпретатора
  47. Spring Boot Startup •  Spring Boot Startup – это производительность

    – Spring Boot на старте очень много чего делает – Очень много кода успевает прогреться – Изучение этого кода дает мотивацию для некоторых оптимизаций
  48. https://github.com/dsyer/spring-boot-aot •  Open JDK 8u181 Spring Boot Startup 2018-11-30 13:04:39.577

    INFO 12484 --- [ main] com.acme.SampleApplication : Started SampleApplication in 0.456 seconds (JVM running for 0.885)
  49. https://github.com/dsyer/spring-boot-aot •  Excelsior JET 15.3 (Java 8u181) 2018-11-30 12:59:28.155 INFO

    3300 --- [ main] com.acme.SampleApplication : Started SampleApplication in 0.028 seconds (JVM running for 0.167) Spring Boot Startup
  50. https://github.com/dsyer/spring-boot-aot •  Excelsior JET 15.3 (Java 8u181) 2018-11-30 12:59:28.155 INFO

    3300 --- [ main] com.acme.SampleApplication : Started SampleApplication in 0.028 seconds (JVM running for 0.167) Spring Boot Startup Опасайтесь замеров Хелловорлдов!
  51. Заключение •  Spring Boot очень удобная платформа для создания микросервисов.

    •  Не смотря на динамичность Spring, AOT вполне может справится с этой динамикой
  52. Заключение •  Чем больше микросервисов, тем важнее стартап тайм и

    производительность – CPU стоит денег в облаках •  AOT -- многообещающий подход для ускорения старта и производительности
  53. Excelsior JET •  Бесплатная пробная версия (90 дней) – https://www.excelsiorjet.com/evaluate • 

    Бесплатная версия Standard Edition (32- бита) •  Team Blog – https://www.excelsiorjet.com/blog