Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Quarkus入門

6.007 visualizaciones

Publicado el

GlassFish Users Group Japan 勉強会 2019 Springのスライド
https://glassfish.doorkeeper.jp/events/89314
#glassfish_jp #quarkus

Publicado en: Software
  • Sé el primero en comentar

Quarkus入門

  1. 1. Quarkus 入門 GlassFish User Group Japan May 16th, 2019
  2. 2. 上妻 宜人 (あげつま のりと) ● 日本GlassFishユーザ会 理事 ● JBoss EAPのテクニカルサポートエンジニア
  3. 3. QuarkusSupersonic Subatomic Java 高速軽量なWebランタイム Graal対応/100ミリ秒未満で起動
  4. 4. Quarkusは圧倒的に高速起動 WildFly16 JDK8u211 Thorntail-2.4 JDK8u211 Quarkus0.14.0 JDK8u211/java -jar Quarkus0.14.0 GraalVM1.0.0RC16 native-image 9888ms 18224ms 2802ms 71ms JAX-RS/CDI/JPAサンプルアプリケーションで測定 https://github.com/nagetsum/quarkus-glassfishjp
  5. 5. 本日の内容 ● Quarkusが生まれた背景 ● デモ ● Quarkusとは何か ● Quarkusの注意点 ● まとめ
  6. 6. Quarkusが生まれた背景 1 k8sでもやっぱりJavaでコードを書きたい ● コンテナ用途に小さくて軽いJavaが欲しい ● APサーバではJVMプロセスは1サーバに数個〜10程度 ● k8sの1ノードでJavaプロセスを20以上起動したい ● uber-jar登場により1war = 1プロセスが主流に ● 1プロセスに複数warをデプロイしなくなった
  7. 7. Quarkusが生まれた背景 1 k8sでもやっぱりJavaでコードを書きたい ● もっと小さく ● JDK8 HotSpotJVM メモリフットプリント 200MB 〜 ● WildFly16コンテナのイメージサイズ 371MB ● Throntail uber-jar 125MB ● もっと軽く ● 大きなアプリケーションではPod起動に20秒以上 ● 起動速度はPodスケールのネックになる (JAX-RS/CDI/JPA)
  8. 8. Quarkusが生まれた背景 2 GraalVMネイティブコンパイル登場 ● ネイティブバイナリは非常にコンパクト ● Javaで書いて52MBの Mach-O or ELF シングルバイナリ ● 起動時メモリ使用量 (ps RSS) 30MB ※いずれも数値はQuarkusデモAPの場合 ● $GRAALVM_HOME/bin/native-image -jar <uber-jar>
  9. 9. ネイティブコンパイルを試みる ● Undertow ● WildFlyのWebサーバ実装 ● Java SEでも動く import io.undertow.Undertow; import io.undertow.util.Headers; public class Main { public static void main(final String[] args) { Undertow server = Undertow.builder() .addHttpListener(8080, "localhost") .setHandler(exchange -> { exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); exchange.getResponseSender().send("Hello World"); }).build(); server.start(); } }
  10. 10. native-imageが通らない ● ネイティブイメージ作成時の制約事項に引っかかる ● java.nio.ByteBuffer#allocateDirectは使えない ● Undertowの内部実装AjpServerRequestConduitクラスで利用 $ native-image -jar undertow-standalone.jar Warning: Abort stand-alone image build. Unsupported features in 3 methods Detailed message: Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected a direct/mapped ByteBuffer in the image heap. A direct ByteBuffer has a pointer to unmanaged C memory, and C memory from the image generator is not available at image run time. A mapped ByteBuffer references a file descriptor, which is no longer open and mapped at run time. The object was probably created by a class initializer and is reachable from a static field. By default, all class initialization is done during native image building.You can manually delay class initialization to image run time by using the option --delay- class-initialization-to-runtime=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point. Trace: at parsing io.undertow.server.protocol.ajp.AjpServerRequestConduit.read (AjpServerRequestConduit.java:195) Call path from entry point to io.undertow.server.protocol.ajp.AjpServerRequestConduit.read(ByteBuffer): at io.undertow.server.protocol.ajp.AjpServerRequestConduit.read(AjpServerRequestConduit.java:183) at org.xnio.conduits.ConduitStreamSourceChannel.read(ConduitStreamSourceChannel.java:127)
  11. 11. Quarkusが生まれた背景 2 再掲: GraalVMネイティブコンパイル登場 ● ネイティブバイナリは非常にコンパクト ● Javaで書いて 52MB の ELF or Mach-O シングルバイナリ ● 起動時メモリ使用量(ps RSS) 30MB (いずれも数値はQuarkusデモAPの場合) ● シングルバイナリによりJVM不要の小さなイメージが作れる ● native-imageコマンド ● $GRAALVM_HOME/bin/native-image -jar <uber-jar> ● Java EEでも簡単にnative-imageコマンドを通したい
  12. 12. 本日の内容 ● Quarkusが生まれた背景 ● デモ ● Quarkusとは何か ● Quarkusの注意点 ● まとめ
  13. 13. Quarkus Demo https://github.com/nagetsum/quarkus-glassfishjp
  14. 14. Quarkusデモのまとめ 1/2 ● Java EE APIでコードが書ける ● mvn io.quarkus:quarkus-maven-plugin:0.14.0:create で プロジェクト作成 ● mvn compile quarkus:dev でホットスワップ ● HTTPリクエスト受信時にコード変更チェック ● mvn package -Pnative でネイティブビルド
  15. 15. Quarkusデモのまとめ 2/2 ● JAX-RS ● javax.ws.rs.core.Application継承クラスは省略可 ● JPA ● Panacheによるボイラープレートコードの削減 ● テスト ● @QuarkusTestとrest-assuredベースのテスト ● @SubstrateTestによるネイティブバイナリへのテスト
  16. 16. 本日の内容 ● Quarkusが生まれた背景 ● デモ ● Quarkusとは何か ● Quarkusの注意点 ● まとめ
  17. 17. Quarkusとは ● ネイティブビルドが可能なWebフレームワーク ● 2019年3月にBeta版として公開 (現在もBeta) ● Red HatがスポンサーのOSSプロジェクト ● Apache Software License 2.0
  18. 18. Quarkusが実装したこと ● 既存ライブラリをネイティブビルド可能とした ● RESTEasy / Hibernate / Smallrye(MicroProfile) 等 ● Extensionsと呼ばれる https://quarkus.io/extensions/ ● 新たなCDI実装 “arc” の開発 ● Weldは実行時に内部処理で動的バイトコード生成を行う ● SubstrateVM制約でクラス動的ロードができない為、 arcではビルド時にバイトコード生成 ● 既存ライブラリやarcにおいて、元々デプロイ時に 実行していた処理をビルド時に実行して起動高速化
  19. 19. 例: arcビルド時コード生成 @Injectをどうやって実現するか @ApplicationScoped public class SantaclausService { @Inject GiftDao giftDao; } public interface GiftDao {} @ApplicationScoped public class GiftDaoImpl implements GiftDao {}
  20. 20. 例: arcビルド時コード生成 @Injectをどうやって実現するか @ApplicationScoped public class SantaclausService { @Inject GiftDao giftDao; } public interface GiftDao {} @ApplicationScoped public class GiftDaoImpl implements GiftDao {} 1. Bean定義アノテーションのスキャン jar内の全クラスを探索し、Bean定義を示す スコープアノテーションが付与されてるか探索。 アーカイブ内のBean一覧を作成。 1. Bean定義 アノテーションの スキャン
  21. 21. 例: arcビルド時コード生成 @Injectをどうやって実現するか @ApplicationScoped public class SantaclausService { @Inject GiftDao giftDao; } public interface GiftDao {} @ApplicationScoped public class GiftDaoImpl implements GiftDao {} 2. @Injectのスキャン Beanクラスに@Injectがあるかチェックし、 依存性注入が必要な箇所を抽出。 2. @Inject スキャン 1. Bean定義 アノテーションの スキャン
  22. 22. 例: arcビルド時コード生成 @Injectをどうやって実現するか @ApplicationScoped public class SantaclausService { @Inject GiftDao giftDao; } public interface GiftDao {} @ApplicationScoped public class GiftDaoImpl implements GiftDao {} 3. 依存性の解決 (実装クラスの探索) インタフェースに対応する実装型を、 1.で抽出したBean定義一覧の中から特定 (この例の場合はGiftDaoImplクラス) 3. 依存性の 解決 2. @Inject スキャン 1. Bean定義 アノテーションの スキャン
  23. 23. 例: arcビルド時コード生成 @Injectをどうやって実現するか @ApplicationScoped public class SantaclausService { @Inject GiftDao giftDao; //=GiftDao$Proxy$_$$_WeldClientProxy } public interface GiftDao {} @ApplicationScoped public class GiftDaoImpl implements GiftDao {} 4. クライアントプロキシのバイトコード生成 newしたGiftDaoImplインスタンスを注入して 参照関係を直接持たせると、スコープ完了時にGCできない。 プロキシクラスを動的バイトコード生成して注入。 3. 依存性の 解決 2. @Inject スキャン 1. Bean定義 アノテーションの スキャン 4. プロキシ バイトコード 生成
  24. 24. 例: arcビルド時コード生成 @Injectをどうやって実現するか @ApplicationScoped public class SantaclausService { @Inject GiftDao giftDao; //=GiftDao$Proxy$_$$_WeldClientProxy } public interface GiftDao {} @ApplicationScoped public class GiftDaoImpl implements GiftDao {} 5. Beanインスタンスの生成 各Beanの初回コール時にインスタンスを生成。 3. 依存性の 解決 2. @Inject スキャン 1. Bean定義 アノテーションの スキャン 5. Bean 生成 4. プロキシ バイトコード 生成
  25. 25. 例: arcビルド時コード生成 Weld(CDI参照実装)の場合 3. 依存性の 解決 2. @Inject スキャン 1. Bean定義 アノテーションの スキャン 5. Bean 生成 4. プロキシ バイトコード 生成 デプロイ時に実行 初回コール時実行
  26. 26. 例: arcビルド時コード生成 arc – QuarkusのCDI実装 の場合 3. 依存性の 解決 2. @Inject スキャン 1. Bean定義 アノテーションの スキャン 5. Bean 生成 4. プロキシ バイトコード 生成 ビルド時に実行 (Quarkus Maven Plugin) 初回コール 時実行
  27. 27. Quarkusが速い理由 WildFly16 JDK8u211 Thorntail-2.4 JDK8u211 Quarkus0.14.0 JDK8u211/java -jar Quarkus0.14.0 GraalVM1.0.0RC16 native-image 9888ms 18224ms 2802ms 71ms ● Quarkusが速い理由はGraalVMの恩恵だけでない ● Java EEランタイムのレイヤでもビルド時最適化を実装 ● だから java -jar でも速い
  28. 28. Quarkusの構成 RESTEasy Maven/Gradle Plugin Quarkus Core Deployment (Build time processor framework) Quarkus Core Runtime (Launcher, Thread Pool, Logging etc..) arc (CDI implementation on Quarkus) Quarkus Development Mode (hot swap) HotSpotJVM or GraalVM(SubstrateVM) extension-resteasy Hibernate extension-hibernate-orm H2/MariaDB/PostgreSQL JDBC extension-jdbc Small-rye (Microprofile impl) extension-small-rye … and mores Quarkus extensions Undertow extension-undertow 既存のライブラリ Quarkusで新たに 実装されたもの VM Quarkus Core
  29. 29. 本日の内容 ● Quarkusが生まれた背景 ● デモ ● Quarkusとは何か ● Quarkusの注意点 ● まとめ
  30. 30. Quarkusで注意すること ● ネイティブビルドの制約を意識してコードを書く ● 動的バイトコード生成しない (Objenesis, cglib etc..) ● クラスパスから設定ファイルをロードしない (ClassLoader#getResourceAsStreamを使わない) ● ビルド時に存在しないクラスをリフレクションしない ● staticイニシャライザはビルド時に動くことに注意 (最新のGraalVM19.0.0からランタイム時実行に変更になりました) https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md ● 上記の制約は依存ライブラリにも適用される ● 引っかかる場合はネイティブ化は諦めて java -jar 利用 ● またはQuarkus Extensionを自作
  31. 31. Quarkusの気になるところ ● 非OSSに対するextention開発が難しい ● エンプラ領域ではOracle JDBCは避けて通れない ● extensionによりバージョンが固定される ● 依存先ライブラリではなくextensionを読み込む仕組み ● 例: pgjdbcバージョンアップにextensionが追従できるか ● mvn package -Pnativeに時間が掛かる ● GraalVMのネイティブコンパイル高速化に期待
  32. 32. ● ネイティブAPでもOOMエラーは起こる ● DBからの大量レコードフェッチ、巨大なListやMap ● Full GC連発の末にOOMエラー ● メモリフットプリントは小さいが、アプリが大量に 要求するとメモリ使用量は増えることに注意 ./quarkus-oom-0.1-runner -Xms256m -Xmx256m -XX:+PrintGC -XX:+PrintGCSummary -XX:+PrintGCTimeStamps ... [28878 msec: Incremental GC (CollectOnAllocation.Sometimes) 26650K->7973K, 0.0460786 secs] [28985 msec: Incremental GC (CollectOnAllocation.Sometimes) 34312K->19966K, 0.0749783 secs] ... [38259 msec: Full GC (CollectOnAllocation.Sometimes) 267658K->253378K, 1.8340780 secs] [40128 msec: Full GC (CollectOnAllocation.Sometimes) 279897K->266638K, 1.8257359 secs] 2019-05-10 01:10:43,433 ERROR [io.und.request] (executor-thread-1) UT005023: Exception handling request to /echo: java.lang.OutOfMemoryError: Garbage-collected heap size exceeded. バイナリ実行で OutOfMemoryError
  33. 33. SubstrateVMのヒープ設定 ● 最大ヒープサイズ ● -Xmx または -XX:MaximumHeapSizePercent=xx ● デフォルトは利用可能メモリの80% (物理 or cgroups) ● コンテナのメモリを使い切るデフォルト値のため、 以前と比べてチューニングの機会は少ないのでは? ● 詳細はソースコード参照 ● https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.core.genscavenge/ src/com/oracle/svm/core/genscavenge/HeapPolicyOptions.java
  34. 34. 本日の内容 ● Quarkusが生まれた背景 ● デモ ● Quarkusとは何か ● Quarkusの注意点 ● まとめ
  35. 35. Quarkusを学ぶには ● 公式サイト ● https://quarkus.io ● Quarkus Youtubeチャネル ● https://www.youtube.com/channel/UCaW8QG_QoIk_FnjLgr5eOqg ● SubstrateVM (Graal) ● https://github.com/oracle/graal/tree/master/substratevm
  36. 36. まとめ ● Quarkusは高速起動が特徴のフレームワーク ● 100ミリ秒未満で起動 ● 起動停止が頻繁発生するコンテナ環境に効果的 ● 速い理由 ● デプロイ時 or 実行中に行なっていた処理を 可能な限りビルド時に実行して高速化 ● GraalVMによるネイティブイメージ作成で高速化

×