スプリングブートアプリケーションで奇妙な動作があります。
バックエンドを再起動した後、コントローラへの最初の呼び出しには約5秒かかります。次の同じリクエストには50msしかかかりません。これは90%のケースで再現可能であり、場合によっては最初の呼び出しでも高速です。
確かに、問題はクライアントではなくサーバーにあります。ブラウザで、TTFB時間(最初のバイトまでの時間)が5秒に増加しているのがわかります。次のリクエストに必要なのは、TTFBに10ミリ秒のみです。
サーバー上の監視ツール(アプリダイナミクス)を使用すると、このような遅いサーバーコールを収集でき、コールグラフで次のことがわかります。
org.Apache.catalina.webresources.JarWarResourceSet:getArchiveEntries:117
4916msが必要です。ここが私のボトルネックです。しかし、私はそれを修正する方法がわかりません。
私がすでに試したこと:
サーバーの遅延に影響を与えないすべてのもの。
更新
Warファイルが複数回スキャンされるため、時間が失われます。
org.Apache.catalina.webresources.CachedResource.validateResourceは、warファイル(isPackedWarFile)およびこのチェックはfalseを返します。たとえwarファイルであっても。この誤動作のために、回避策があります。 Tomcat.resource.cache-ttを高い値に設定します。
しかし今org.Apache.catalina.webresources.Cache.getResourceにはnoCache 方法。このメソッドでは、classおよびjarファイルはキャッシュから除外されます。そして、これがwarファイルが再びスキャンされる理由です。
戦争ファイル全体のスキャンには約5秒かかります。そして、この休憩は世界の休憩の停止です。そして、このスキャンは、warファイルが展開されず、その内容を変更できないため、絶対に不要です。
更新
WarファイルをTomcatインストールに配置すると、すべてが高速になります。組み込みTomcatが問題です。
すでに行っていると思いますが、まだ行っていない場合は、 https://wiki.Apache.org/Tomcat/HowTo/FasterStartUp をご覧になり、そこで提案されている修正を実装してください。
埋め込みTomcatを使用したスキャンを無効にするには、ここのコメントに提案があります https://github.com/spring-projects/spring-boot/issues/161
上記の提案のどれもが遅延の修正に役立たない場合、考えられる回避策は、サーバーの起動時にその最初の要求を行うことです(そしてそこから遅延をトリガーします)。
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private RestTemplate template;
public static void main (String args[]){
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... strings) throws Exception {
// do an initial request from here to trigger scanning the war
template.exchange(...);
}
}
これにより、クライアントは5秒の遅延を経験しなくなります。私はこれがハックであることを知っていますので、よりクリーンな方法を見つけた場合は代わりにそれを使用してください。
CPU使用率が高く、応答が遅れるという同様の問題に直面していました。 org.Apache.catalina.webresources.JarWarResourceSet:getArchiveEntries
はwarファイルのスキャン中に約5秒かかっていました。スキャン中、リクエストは処理されませんでした。
この問題を解決したSpring boot version
を1.4.2.RELEASE
から1.5.12.RELEASE
に更新しました。実際、問題は埋め込みTomcat
にあり、それは後のバージョンで修正されたようです。
実行可能[〜#〜] jar [〜#〜]ファイル(WARの代わりに)を使用して組み込みTomcatで実行すると、問題が解決しました。これは、実行可能なアーカイブからのリソースの読み込みを高速化するための 推奨方法 です。
あなたが説明しているのは、重いDB接続プーリングを使用するインフラストラクチャの再起動の典型的な効果です。
データに基づくと、最初の2つのステップは遅く、DBプールがウォームアップされるまで、非常に遅いクエリが発生するでしょう。潜在的な改善は次のとおりです。