[編集者注] クラウドネイティブ時代の到来は Java 開発者とどのような関係があるのでしょうか?クラウド ネイティブは Java にはまったく適していないと言う人もいます。しかし、この記事の著者は、クラウドネイティブ時代においても、Java は依然として「巨人」の役割を果たすことができると考えています。著者は一連の実験を通じて学生の視野を広げ、有益な思考を提供したいと考えています。 エンタープライズ ソフトウェアの分野では、Java は依然として絶対的な王者ですが、開発者の間では Java を愛する気持ちと嫌う気持ちが分かれています。一方では、豊富なエコシステムと完全なツール サポートにより、アプリケーション開発の効率が大幅に向上します。しかし、実行時の効率という点では、Java は「メモリを大量に消費する」および「CPU を大量に消費する」という悪評も持っており、NodeJS、Python、Golang などの新旧の言語からの挑戦を受け続けています。 テクノロジーコミュニティでは、Java テクノロジーはクラウドネイティブコンピューティングの開発トレンドに適合しなくなったと考え、Java テクノロジーを批判する人がよくいます。上記の観点はさておき、まずはアプリケーション ランタイムに対するクラウド ネイティブのさまざまな要件について考えてみましょう。 サイズが小さい:マイクロサービス分散アーキテクチャの場合、サイズが小さいほどダウンロード帯域幅が少なくなり、配布とダウンロードの速度が速くなります。 起動速度の高速化:従来のモノリシック アプリケーションの場合、起動速度は動作効率と比較して重要な指標ではありません。その理由は、これらのアプリケーションは再起動およびリリースされる頻度が比較的低いためです。ただし、迅速な反復と水平拡張を必要とするマイクロサービス アプリケーションの場合、起動速度が速いほど、配信効率が高くなり、ロールバックが速くなります。特に、何百ものコピーを持つアプリケーションをリリースする必要がある場合、起動速度が遅いと時間の無駄になります。サーバーレス アプリケーションの場合、エンドツーエンドのコールド スタート速度がさらに重要になります。基盤となるコンテナ テクノロジによって 100 ミリ秒以内にリソースを準備できたとしても、アプリケーションが 500 ミリ秒以内に起動できない場合、ユーザーはアクセスの遅延を感じます。 リソース使用量の削減:実行時のリソース使用量が少ないということは、展開密度が高くなり、コンピューティング コストが低くなることを意味します。同時に、JVM が起動すると、バイトコードをコンパイルするために大量の CPU リソースが消費されます。起動時のリソース消費を削減することで、リソースの競合を減らし、他のアプリケーションの SLA をより適切に保証できます。 水平拡張のサポート: JVM のメモリ管理方法では、大容量メモリの管理が比較的非効率的です。一般的に、アプリケーションはヒープ サイズを大きく構成してもパフォーマンスの向上を実現できません。 16G 以上のメモリを効果的に使用できる Java アプリケーションはほとんどありません。一方、メモリコストの低下と仮想化の普及により、大きなメモリ比率がトレンドになってきました。したがって、通常は水平拡張アプローチを採用し、複数のアプリケーション コピーを同時に展開します。リソースの使用率を向上させるために、アプリケーションの複数のコピーをコンピューティング ノードで実行できます。 準備し始めるSpring フレームワークに精通している開発者のほとんどは、Spring Petclinic にも精通しているでしょう。この記事では、この有名なサンプル アプリケーションを使用して、Java アプリケーションをより小型、高速、軽量、強力にする方法を説明します。 私たちは IBM の Michael Thompson の例をフォークし、いくつかの調整を加えました。
まず、PetClinic アプリケーション用の Docker イメージを構築します。 Dockerfile では、OpenJDK をベース イメージとして使用し、Maven をインストールし、Spring PetClinic アプリケーションをダウンロード、コンパイル、パッケージ化し、最後にイメージの起動パラメータを設定してイメージのビルドを完了します。
イメージをビルドして実行します:
アプリケーション インターフェイスには、http://localhost:8080/ からアクセスできます。 ビルドされた Docker イメージを確認すると、「petclinic-openjdk-openj9」のサイズは 871 MB ですが、ベース イメージ「adoptopenjdk/openjdk8」はわずか 300 MB です。これは膨らみすぎです!
その理由は、Spring アプリケーションをビルドするために、Git、Maven などの一連のコンパイル時の依存関係をイメージに導入し、大量の一時ファイルを生成したためです。ただし、これらのコンテンツは実行時には必要ありません。 有名な「ソフトウェアの 12 の要素」の 5 番目には、「ビルド段階と実行段階を厳密に分離する」と明記されています。ビルド段階と実行段階を厳密に分離することで、アプリケーションのトレーサビリティを向上させ、アプリケーション配信の一貫性を確保できるだけでなく、アプリケーションの配布サイズを縮小し、セキュリティ リスクを軽減することもできます。 鏡像痩身Docker は、イメージのスリム化を実現できるマルチステージビルドを提供します。 イメージ構築は 2 つの段階に分かれています。
新しい画像サイズを確認してください。871 MB から 167 MB に削減されています。
イメージがスリム化されると、アプリケーションの配信速度が大幅に加速されます。アプリケーションの起動速度を最適化する方法はありますか? JIT から AOT へ — スタートアップの高速化Java 起動のパフォーマンスボトルネックを解決するには、まず JVM の実装原理を理解する必要があります。 「一度書けばどこでも実行できる」機能を実現するために、Java プログラムはアーキテクチャに依存しないバイトコードにコンパイルされます。 JVM は、実行時に実行するためにバイトコードをネイティブ マシン コードに変換します。この変換プロセスによって、Java アプリケーションの起動および実行速度が決まります。実行効率を向上させるために、JVM では JIT コンパイラ (Just in Time Compiler) が導入されました。その中でも、Sun/Oracle の HotSpot は最も有名な JIT コンパイラ実装です。 HotSpot は、コード実行中にクリティカル パスを動的に分析および検出し、コンパイルの最適化を実行できる適応型オプティマイザーを提供します。 HotSpot の登場により、Java アプリケーションの実行効率が大幅に向上し、Java 1.4 以降ではデフォルトの VM 実装になりました。ただし、HotSpot VM は起動時にのみバイトコードをコンパイルするため、起動時の実行効率が低下します。一方、コンパイルと最適化には多くの CPU リソースが必要となり、起動速度が低下します。このプロセスを最適化して起動速度を上げることはできますか? Java の歴史に詳しい人なら、IBM のエンタープライズ レベルのソフトウェア製品で使用されている高性能 JVM である IBM J9 VM を知っているはずです。これにより、IBM は商用アプリケーション プラットフォーム ミドルウェアにおけるリーダーとしての地位を確立することができました。 2017 年 9 月、IBM は J9 を Eclipse Foundation に寄贈し、Eclipse OpenJ9 と改名してオープン ソースの旅を開始しました。 OpenJ9 は、Shared Class Cache (SCC 共有クラス キャッシュ) と Ahead-of-Time (AOT 事前コンパイル) テクノロジを提供し、Java アプリケーションの起動時間を大幅に短縮します。 SCC は、バイトコードとコンパイルされたネイティブ コードの J9 VM 実行分析情報を含むメモリ マップ ファイルです。 AOT コンパイルを有効にすると、JVM コンパイルの結果が SCC に保存され、その後の JVM 起動時に直接再利用できるようになります。 SCC から事前コンパイルされた実装をロードすると、起動時に JIT コンパイルするよりもはるかに高速になり、リソースの消費も少なくなります。起動時間を大幅に改善できます。 まず、AOT 最適化を含む Docker アプリケーション イメージを構築します。
Java パラメータ -Xshareclasses は SCC を有効にし、-Xquickstart は AOT を有効にします。 Dockerfile では、SCC をウォームアップするためのトリックを使用しました。ビルド プロセス中に、JVM を起動してアプリケーションをロードし、SCC と AOT を有効にし、アプリケーションの起動後に JVM を停止します。これには、Docker イメージに生成された SCC ファイルが含まれます。 次に、Docker イメージをビルドしてテスト アプリケーションを起動します。
ご覧のとおり、起動時間は 8.2 秒から 4 秒に短縮され、約 50% の改善が見られました。 このソリューションでは、時間とエネルギーを消費するコンパイル最適化プロセスをビルド時間に移行し、一方で、スペースと時間を交換する方法を使用して、事前コンパイルされた SCC キャッシュを Docker イメージに保存します。コンテナが起動すると、JVM はメモリマップされたファイルを直接使用して SCC をロードできるため、起動速度とリソース使用量が最適化されます。 この方法のもう 1 つの利点は、Docker イメージが階層化ストレージを使用するため、同じホスト上の複数の Docker アプリケーション インスタンスが同じ SCC メモリ マップを共有することになり、単一のマシン上で高密度に展開する際のメモリ消費を大幅に削減できることです。 次に、リソースの消費量を比較します。まず、HotSpot VM ベースのイメージを使用して 4 つの Docker アプリケーション インスタンスを同時に起動し、次に docker stats を使用して 30 秒後にリソースの消費量を表示します。
次に、OpenJ9 VM ベースのイメージを使用して、4 つの Docker アプリケーション インスタンスを同時に起動し、リソースの消費量を確認します。
HotSpot VM と比較すると、OpenJ9 シナリオでのアプリケーション メモリ使用量は平均 600 MB から 120 MB に減少しました。驚きますか? 一般的に、HotSpot JIT は AOT よりも包括的かつ詳細な実行パス最適化を実行できるため、運用効率が向上します。この矛盾を解決するために、OpenJ9 の AOT SCC は起動フェーズでのみ有効になり、その後の実行中は分岐予測やコード インライン化などの詳細なコンパイル最適化に JIT を引き続き使用します。 HotSpot もクラス データ共有 (CDS) と AOT で大きな進歩を遂げていますが、この点では IBM J9 の方が成熟しています。 Alibaba の Dragonwell が対応する最適化サポートを提供することを期待しています。 考え: C/C++、Golang、Rust などの静的にコンパイルされる言語とは異なり、Java は VM モードで実行されるため、パフォーマンスは多少犠牲になりますが、アプリケーションの移植性が向上します。 AOT を極限まで推し進めることができるでしょうか?バイトコードからネイティブコードへのコンパイルプロセスを完全に削除しますか? ネイティブコードのコンパイルJava アプリケーションをネイティブ実行可能コードにコンパイルするには、まず実行時の JVM とアプリケーション フレームワークの動的な課題に対処する必要があります。 JVM は柔軟なクラス ローディング メカニズムを提供し、Spring の依存性注入 (DI、Dependency-injection) により実行時に動的なクラス ローディングとバインディングを実現できます。 Spring フレームワークでは、リフレクションやアノテーション ランタイム プロセッサなどのテクノロジも広く使用されています。これらのダイナミクスにより、アプリケーション アーキテクチャの柔軟性と使いやすさが向上する一方で、アプリケーションの起動速度が低下し、AOT ネイティブ コンパイルと最適化が非常に複雑になります。 これらの課題に対処するために、コミュニティは多くの興味深い探求を行ってきましたが、Micronaut はその最も優れた代表例の 1 つです。 Spring フレームワークとは異なり、Micronaut はコンパイル時の依存性注入と AOP 処理機能を提供し、リフレクションと動的プロキシの使用を最小限に抑えます。 Micronaut アプリケーションは起動時間が短く、メモリ使用量が少なくなります。私たちにとってさらに興味深いのは、Micronaut が GraalVM との連携をサポートしており、Java アプリケーションをネイティブ実行可能コードにコンパイルしてフルスピードで実行できることです。 注: GraalVM は、Oracle がリリースした新しい汎用仮想マシンであり、複数の言語をサポートし、Java アプリケーションをローカル ネイティブ アプリケーションにコンパイルできます。 私たちの冒険を始めるには、Mitz が提供している PetClinic サンプル プロジェクトの Micronaut バージョンを使用し、いくつかの調整を行います。 (Graal VM 19.2 を使用)
Docker イメージの内容は次のとおりです。
で:
アプリケーションをビルドします。
テスト データベースを起動します。
テストアプリケーションを起動します。
アプリケーションの起動速度は 159 ミリ秒に向上し、HotSpot VM の 1/50 にまで短縮されました。 Micronaut と Graal VM はまだ急速に開発が進んでおり、Spring アプリケーションを移行する際には考慮すべき作業がまだたくさんあります。さらに、Graal VM のデバッグ、監視、その他のツール チェーンはまだ完璧ではありません。しかし、これにより、Java アプリケーションとサーバーレスの世界が遠くないという希望が生まれました。 要約と追記 攻撃的な巨人として、Java テクノロジーもクラウド ネイティブ時代において絶えず進化しています。 JDK 8u191 および JDK 10 以降、JVM は Docker コンテナ内のリソース認識を強化しました。同時に、コミュニティはさまざまな方向から Java テクノロジー スタックの境界を探求しています。従来の VM のメンバーとして、JVM OpenJ9 は、既存の Java アプリケーションとの高い互換性を維持しながら、起動速度とメモリ使用量を詳細に最適化しています。 Spring などの既存のマイクロサービス アーキテクチャでの使用に適しています。 Micronaut/Graal VM は異なるアプローチを採用しています。プログラミングモデルとコンパイルプロセスを変更することで、コンパイル期間中にアプリケーションの動的な性質を可能な限り早く処理し、アプリケーションの起動時間を大幅に最適化し、サーバーレス分野で有望な将来を秘めています。これらのデザインのアイデアは学ぶ価値があります。 クラウドネイティブ時代においては、水平的なアプリケーション開発ライフサイクルにおける開発、デリバリー、運用保守の各プロセスを効果的に分割・再編成し、R&Dコラボレーションの効率を向上させる必要があります。徹底的な簡素化とシステム効率の向上を実現するには、垂直的なソフトウェア技術スタック全体において、プログラミング モデル、アプリケーション ランタイム、インフラストラクチャなどの複数のレベルでシステムの最適化を実行できる必要があります。 この時代に感謝し、私たちを助け、サポートしてくれるすべてのパートナーに感謝し、夢を追いかけるすべての技術者に感謝し、一緒にクラウドネイティブの未来を探求していきましょう。 |
<<: Kafka ソースコード分析とブローカーエンドのグラフィック原理
>>: 平安科技は包括的なマルチクラウド管理能力を実証し、クラウド・トライポッド賞を受賞した。
[[354831]] 「IBM中国開発センターでは、同僚たちと私はIBMハイブリッドクラウドプラット...
著者 |シルヴァン・カラシュ翻訳者 |張野貴 Kubernetes (略して K8s)上のデータ サ...
SEO を行う人の中には、個人のウェブマスターではなく、企業にサービスを提供するタイプの人もいます。...
Directspace に新しいバージョンの SSD ハード ディスク VPS があることを知りまし...
従来の考え方では、ユーザーがサイトの製品ページに長く滞在すればするほど、コンバージョン率が高くなると...
月収10万元の起業の夢を実現するミニプログラム起業支援プラン最近、人気番組「The Rap of C...
先日、友人とSEO業界の現状について話しました。SEO業界の現状は、ほとんどの人が一人で仕事をしてい...
ゲーム市場では「製品が王か」それとも「トラフィックが王か」という議論が絶えません。これまで明確な答え...
JD.com への入り口が QQ インターフェースに表示される (TechWeb の写真) 【Tec...
近年、インターネット時代の「恋愛産業」は急速に発展し、大手企業が独自の出会い系サイトを立ち上げるよう...
最近、国際的に有名なコンサルティング会社であるガートナーが、最新のクラウドベンダー製品評価レポートを...
みなさんこんにちは。私は長沙SEOのLong Junです。ウェブサイトの外部リンクの品質が高ければ高...
[[389269]]シナリオの説明最近、Redis を使用しているときに、分散ロックに似たシナリオに...
fadayun.comは現在、ダブルイレブンプロモーションを実施しています。香港CN2、韓国CN2、...
[[287275]]企業がワークロードをクラウドに移行するケースが増えていますが、これまでは、規制上...