Spring Bootでの埋め込みサーブレットコンテナの比較

Spring Bootでの埋め込みサーブレットコンテナの比較

1. 前書き

クラウドネイティブのアプリケーションとマイクロサービスの人気の高まりにより、組み込みサーブレットコンテナの需要が高まっています。 開発者は、Spring Bootを使用して、Tomcat、Undertow、およびJettyの3つの最も成熟したコンテナーを使用して、アプリケーションまたはサービスを簡単に構築できます。

このチュートリアルでは、起動時と負荷がかかった状態で取得した指標を使用して、コンテナの実装をすばやく比較する方法を示します。

2. 依存関係

使用可能な各コンテナ実装のセットアップでは、常にpom.xmlspring-boot-starter-webへの依存関係を宣言する必要があります。

一般に、親をspring-boot-starter-parentとして指定してから、必要なスターターを含めます。


    org.springframework.boot
    spring-boot-starter-parent
    2.0.3.RELEASE
    



    
        org.springframework.boot
        spring-boot-starter
    

    
        org.springframework.boot
        spring-boot-starter-web
    

2.1. トムキャット

Tomcatを使用する場合、spring-boot-starter-webを使用するとデフォルトで含まれるため、これ以上の依存関係は必要ありません。

2.2. 桟橋

Jettyを使用するには、最初にspring-boot-starter-webからspring-boot-starter-tomcatを除外する必要があります。

次に、spring-boot-starter-jettyへの依存関係を宣言するだけです。


    org.springframework.boot
    spring-boot-starter-web
    
        
            org.springframework.boot
            spring-boot-starter-tomcat
        
    


    org.springframework.boot
    spring-boot-starter-jetty

2.3. 引き綱

Undertowの設定は、依存関係としてspring-boot-starter-undertowを使用することを除いて、Jettyと同じです。


    org.springframework.boot
    spring-boot-starter-web
    
        
            org.springframework.boot
            spring-boot-starter-tomcat
        
    


    org.springframework.boot
    spring-boot-starter-undertow

2.4. アクチュエータ

Spring Bootのアクチュエータを、システムへのストレスと指標のクエリの両方に便利な方法として使用します。

アクチュエータの詳細については、this articleを確認してください。 pomに依存関係を追加して、利用できるようにします。


    org.springframework.boot
    spring-boot-starter-actuator

 2.5. アパッチベンチ

Apache Benchは、Apacheウェブサーバーにバンドルされているオープンソースの負荷テストユーティリティです。

Windowsユーザーは、hereにリンクされているサードパーティベンダーの1つからApacheをダウンロードできます。 ApacheがすでにWindowsマシンにインストールされている場合は、apache/binディレクトリでab.exeを見つけることができるはずです。

Linuxマシンを使用している場合、apt-getを使用してabをインストールできます。

$ apt-get install apache2-utils

3. スタートアップメトリック

3.1. コレクション

起動指標を収集するために、Spring BootのApplicationReadyEventで起動するイベントハンドラーを登録します。

Actuatorコンポーネントで使用されるMeterRegistryを直接操作して、関心のあるメトリックをプログラムで抽出します。

@Component
public class StartupEventHandler {

    // logger, constructor

    private String[] METRICS = {
      "jvm.memory.used",
      "jvm.classes.loaded",
      "jvm.threads.live"};
    private String METRIC_MSG_FORMAT = "Startup Metric >> {}={}";

    private MeterRegistry meterRegistry;

    @EventListener
    public void getAndLogStartupMetrics(
      ApplicationReadyEvent event) {
        Arrays.asList(METRICS)
          .forEach(this::getAndLogActuatorMetric);
    }

    private void processMetric(String metric) {
        Meter meter = meterRegistry.find(metric).meter();
        Map stats = getSamples(meter);

        logger.info(METRIC_MSG_FORMAT, metric, stats.get(Statistic.VALUE).longValue());
    }

    // other methods
}

手動でActuator RESTエンドポイントを照会したり、イベントハンドラー内で起動時に興味深いメトリックを記録することにより、スタンドアロンJMXコンソールを実行する必要はありません。

3.2. 選択

Actuatorにはすぐに使用できる多数のメトリックがあります。 サーバーの起動後、主要なランタイム特性の概要を把握するのに役立つ3つのメトリックを選択しました。

  • jvm.memory.used –起動以降にJVMによって使用された合計メモリ

  • jvm.classes.loaded –ロードされたクラスの総数

  • jvm.threads.live –アクティブなスレッドの総数。 私たちのテストでは、この値は「停止中」のスレッド数として見ることができます

4. ランタイムメトリック

4.1. コレクション

起動指標を提供することに加えて、アプリケーションに負荷をかけるために、Apache Benchを実行するときに、アクチュエータによって公開された/metrics endpointをターゲットURLとして使用します。

実際のアプリケーションを負荷の下でテストするために、代わりにアプリケーションが提供するエンドポイントを使用する場合があります。

サーバーが起動すると、コマンドプロンプトが表示され、abが実行されます。

ab -n 10000 -c 10 http://localhost:8080/actuator/metrics

上記のコマンドでは、10個の同時スレッドを使用して合計10,000件のリクエストを指定しました。

4.2. 選択

Apache Benchは、接続時間や特定の時間内に処理されたリクエストの割合など、有用な情報を非常に迅速に提供できます。

私たちの目的では、we focused on requests-per-second and time-per-request (mean).

5. 結果

起動時に、Undertowが他の2つよりもわずかに多くのメモリを必要とし、Jettyが最小量を必要とするthe memory footprint of Tomcat, Jetty, and Undertow was comparableが見つかりました。

ベンチマークでは、the performance of Tomcat, Jetty, and Undertow was comparableであるが、Undertow was clearly the fastest and Jetty only slightly less fast. であることがわかりました。

メトリック

トムキャット

桟橋

引き綱

jvm.memory.used (MB)

168

155

164

jvm.classes.loaded

9869

9784

9787

jvm.threads.live

25

17

19

1秒あたりのリクエスト

1542

1627

1650

リクエストあたりの平均時間(ミリ秒)

6.483

6.148

6.059

メトリックは、当然ながら、ベアボーンプロジェクトの代表であることに注意してください。独自のアプリケーションのメトリックは、ほとんど確実に異なります。

6. ベンチマークディスカッション

サーバー実装の徹底的な比較を実行するための適切なベンチマークテストの開発は、複雑になる可能性があります。 最も関連性の高い情報を抽出するために、it’s critical to have a clear understanding of what’s important for the use case in question

この例で収集されたベンチマーク測定値は、アクチュエータエンドポイントへのHTTPGETリクエストで構成される非常に特定のワークロードを使用して取得されたことに注意することが重要です。

It’s expected that different workloads would likely result in different relative measurements across container implementations。 より堅牢で正確な測定が必要な場合は、実稼働ユースケースにより厳密に一致するテスト計画を設定することをお勧めします。

さらに、JMeterGatlingなどのより洗練されたベンチマークソリューションは、より価値のある洞察をもたらす可能性があります。

7. コンテナの選択

Selecting the right container implementation should likely be based on many factors that can’t be neatly summarized with a handful of metrics alone。 快適レベル、機能、使用可能な構成オプション、およびポリシーは、それほど重要ではないにしても、同様に重要であることがよくあります。

8. 結論

この記事では、Tomcat、Jetty、およびUndertowの組み込みサーブレットコンテナの実装について説明しました。 起動時の各コンテナの実行時特性を、デフォルトの構成を使用して、アクチュエータコンポーネントによって公開されるメトリックを調べて調べました。

実行中のシステムに対して人為的なワークロードを実行し、Apache Benchを使用してパフォーマンスを測定しました。

最後に、この戦略のメリットについて説明し、実装ベンチマークを比較する際に留意すべき点をいくつか挙げました。 いつものように、すべてのソースコードはover on GitHubで見つけることができます。