CPUを多用するタスクが多すぎる。DXP 7.0における一般的なパフォーマンスの問題

この記事では、Liferay DXP 7.0でのCPU集中タスクの実行に関連する一般的なパフォーマンスの問題について説明しています。 この問題についての必要な情報と、それをナビゲートする方法を発見するために読み続けてください。

以下に、より一般的な原因と解決策をご紹介します。

  1. ミニファイア
  2. ストリップフィルタ
  3. GZipFilter
  4. パスワードハッシュ化

決議

加入者によっては、多くのCPU集約的なタスクが同時に実行されている場合、パフォーマンスの問題が発生することがあります。 これは一般化したパターンで、様々なユースケースから出てくる可能性があります。 直面している問題の深刻度にもよりますが、スレッドダンプには数十から数百のスレッドが含まれている可能性があります。 お客様はCPU使用率が高くなり、応答時間が遅くなり、まれにLiferayプラットフォームが反応しないように見えることがあります。

より一般的な原因とその後の解決策について、以下の内容をご確認ください。

ミニファイア

Minifier は、ブラウザに送信する前に、CSS と Javascript リソースを最小化しようとします。 このアクションを実行すると、ファイルが小さくなるため、ネットワークの帯域幅を節約することができます。 ただし、CPUのパフォーマンスペナルティが発生します。

Minifierはデフォルトで有効になっていますが、 portal-ext.properties: minifier.enabled=falseに以下のプロパティを設定することでオフにできます。

スレッドダンプでは、以下の文字列を何十回、場合によっては何百回も見ていると、この問題に気づくことがあります。

com.liferay.portal.util.MinifierUtil._minifyCss

"http-/0.0.0.0:8280-336" daemon prio=10 tid=0x00007f8bfc282ea0 nid=0x2c0d runnable [0x00007f8aa6d27000]
   java.lang.Thread.State: RUNNABLE
    at java.util.regex.Pattern$CharProperty$1.isSatisfiedBy(Pattern.java:3689)
    at java.util.regex.Pattern$7.isSatisfiedBy(Pattern.java:5171)
    at java.util.regex.Pattern$7.isSatisfiedBy(Pattern.java:5171)
    at java.util.regex.Pattern$7.isSatisfiedBy(Pattern.java:5171)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3694)
    at java.util.regex.Pattern$Curly.match0(Pattern.java:4158)
    at java.util.regex.Pattern$Curly.match(Pattern.java:4132)
    at java.util.regex.Pattern$Start.match(Pattern.java:3408)
    at java.util.regex.Matcher.search(Matcher.java:1199)
    at java.util.regex.Matcher.find(Matcher.java:592)
    at java.util.regex.Matcher.replaceAll(Matcher.java:902)
    at java.lang.String.replaceAll(String.java:2162)
    at com.yahoo.platform.yui.compressor.CssCompressor.compress(CssCompressor.java:345)
    at com.liferay.portal.util.MinifierUtil._minifyCss(MinifierUtil.java:59)
    at com.liferay.portal.util.MinifierUtil.minifyCss(MinifierUtil.java:38)

Spotify の Online Thread Dump Analyzerを使用した同じスレッドダンプからの別の発生です。
Spotify-performance-02.png

このような場合、正確なスタックトレースが異なる可能性があることに注意してください。 これらのスレッドはすべて実行しているので、それらは彼らの人生の異なる段階にあります:それらのすべては、リソースの飢餓につながる進行することができるCPU時間を待っています。

これを解決するには、CSSやJavascriptの最小化が必要かどうかを評価する必要があります。 微細化が必要な場合は、さらなる資源が必要になるかもしれません。 加入者は、ウェブサーバによるキャッシングや、静的コンテンツを CDN サーバにオフロードすることで、プラットフォームの使用や追加リソースの使用をクラスタリングすることを検討すべきである。 最小化が不要な場合は、前述のminifier.enabledプロパティでオフにするだけで、CPUへの負担が軽減されるはずです。

ストリップフィルタ

StripFilter は Minifier と似ていますが、最終的には CPU の使用量と引き換えにファイルを小さくすることができます。 Liferay Portal 6.2 のコメントを参照してください: ストリップフィルタは、出力されたコンテンツから空行を削除します。 これにより、ダイヤルアップを使用しているユーザーのためにページのレンダリングが高速化されます。
com.liferay.portal.servlet.filters.strip.StripFilter=true

CPUのコストに比べて実質的なメリットがないので、最初からオフにすることをお勧めします。 レスポンスから改行を削除すると、いくつかのスペースを節約することができます。 しかし、内容の圧縮は非常に効率的で、ファイル内に改行があるかどうかは本当に問題ではありません(極端な端っこの場合を除いて)。 さらに、ブラウザがページをロードするのにかかる時間は微々たるもので、ページをロードするのにかかる時間の大部分は、とにかくダウンロードされるリソースを待つことに費やされています。

これは、ネットワークにとってもエンドユーザーにとってもメリットがないのに、CPUにパフォーマンスの影響を与えるということです。

そのようなスレッドを見つけるには、文字列 の StripFilter.stripを検索してください。 - どのスレッドダンプでも5回以上の発生がある場合は、そのためにあなたの応答時間が苦しくなっていることに注意してください。 実際にStripFilterを実行しているスタックトレースの先頭の下に含まれています。

"http-/0.0.0.0:8280-186" daemon prio=10 tid=0x00007f796c343250 nid=0x175e runnable [0x00007f7854134000]
   java.lang.Thread.State: RUNNABLE
    at java.nio.Buffer.checkIndex(Buffer.java:537)
    at java.nio.CharBuffer.charAt(CharBuffer.java:1238)
    at com.liferay.portal.kernel.util.KMPSearch.search(KMPSearch.java:218)
    at com.liferay.portal.kernel.util.KMPSearch.search(KMPSearch.java:200)
    at com.liferay.portal.servlet.filters.strip.StripFilter.processInput(StripFilter.java:410)
    at com.liferay.portal.servlet.filters.strip.StripFilter.strip(StripFilter.java:668)
    at com.liferay.portal.servlet.filters.strip.StripFilter.processFilter(StripFilter.java:399)

GZipFilter

GZipFilterの仕事は、ブラウザに戻るレスポンスを圧縮して帯域幅を節約し、最終的にはページのロード時間を短縮することです。 以下のプロパティで制御されます。
com.liferay.portal.servlet.filters.gzip.GZipFilter=true

GZipFilter は以前、StripFilter の影響について議論したときに紹介しましたが、そのセクションでは、レスポンスを GZIP したほうがより有益なので、StripFilter を有効にする必要はないと述べられています。 GZipFilter の代わりに GZIP という言葉を選んだのは意図的なものです。 例えば、Apache の mod_deflate は別のボックスにあることで、別のサーバの CPU がレスポンスを圧縮する作業をすることができるという利点があります。 GZipFilterの主な仕事は、レスポンスの準備ができたらすべてを圧縮することなので、キャッチするのは難しいです。 そのため、GZip関連のJavaクラスが最後に実行されているのを見て、例えば GZipResponse$1 オブジェクトがロックされているのを見ることで、実行プロセスを見ることができます。

"http-/0.0.0.0:8280-324" daemon prio=10 tid=0x00007f8bfc26f460 nid=0x2c01 runnable [0x00007f8aa7933000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Deflater.deflateBytes(Native Method)
    at java.util.zip.Deflater.deflate(Deflater.java:430)
    - locked <0x00000006dd9bf380> (a java.util.zip.ZStreamRef)
    at java.util.zip.Deflater.deflate(Deflater.java:352)
    at java.util.zip.DeflaterOutputStream.deflate(DeflaterOutputStream.java:251)
    at java.util.zip.DeflaterOutputStream.write(DeflaterOutputStream.java:211)
    at java.util.zip.GZIPOutputStream.write(GZIPOutputStream.java:146)
    - locked <0x00000006dd9bf2f8> (a com.liferay.portal.servlet.filters.gzip.GZipResponse$1)
    at com.liferay.portal.kernel.servlet.ServletOutputStreamAdapter.write(ServletOutputStreamAdapter.java:54)

前述したように、GZipFilterに起因する、あるいはGZipFilterに関連するパフォーマンスの問題が今のところないとしても、可能であればGZipFilterをオフにして、他のサービスに頼ることをお勧めします。

パスワードハッシュ化

パスワードの比較は、ユーザーがフォームで指定したパスワードをハッシュ化して、データベース内の既にハッシュ化されている(保存されている)パスワードと比較することで行われます。 デフォルトでは、Liferay プラットフォームは計算量の多いアルゴリズムを使用します。 PBKDF2 with HMAC SHA1 160 ビットのハッシュと 128,000 ラウンド。

以下は暗号化アルゴリズムを設定するポータルプロパティです。
passwords.encryption.algorithm=PBKDF2WithHmacSHA1/160/128000

CPUに負担がかかっているのは、それだけの理由がある。 これは、入力テキストの疑似ランダム関数とソルトを使用して-bitハッシュを作成し(デフォルトは160)、それを何度も繰り返します(デフォルトは128,000)。 その結果、多くのユーザーが同時にログインした場合、CPUがすべてのリクエストを処理できるようになるまでしばらくの間、ポータルをロックする可能性があります。 以下は、ユーザーログインを処理しているスレッドのスタックトレースの先頭です。

"ajp--127.0.0.1-8009-198" daemon prio=10 tid=0x00007fcef1575600 nid=0xfe4d runnable [0x00007fced4138000]
   java.lang.Thread.State: RUNNABLE
    at com.sun.crypto.provider.HmacSHA1.engineReset(HmacSHA1.java:118)
    at javax.crypto.Mac.doFinal(Mac.java:547)
    at javax.crypto.Mac.doFinal(Mac.java:589)
    at com.sun.crypto.provider.PBKDF2KeyImpl.deriveKey(PBKDF2KeyImpl.java:178)
    at com.sun.crypto.provider.PBKDF2KeyImpl.(PBKDF2KeyImpl.java:121)
    at com.sun.crypto.provider.PBKDF2HmacSHA1Factory.engineGenerateSecret(PBKDF2HmacSHA1Factory.java:71)
    at javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:335)
    at com.liferay.portal.security.pwd.PBKDF2PasswordEncryptor.doEncrypt(PBKDF2PasswordEncryptor.java:77)

このような複数のスレッドがパスワードの暗号化に取り組んでいるのを見ると、Liferayプラットフォームが苦しんでいることを示しており、ユーザーはログインしようとしているときに長い待ち時間を報告する(またはすでに報告している)ことになります。

この問題の解決策はいくつかあります。

  1. PBKDF2アルゴリズムのチューニング。
    1. 生成されるハッシュのサイズを小さくするか、ラウンド数を少なくします。
    2. これらの手順の両方が、しかし、同様に考慮する必要があるパスワードの暗号化の強度を低下させます。
    3. ユーザーパスワードを強制的にリセットする必要がある場合があります。
  2. 完全に別のアルゴリズムを使用しています。
    1. PBKDF2 から計算量の少ない別のアルゴリズムに移行すると、CPUへの影響も緩和されます。
    2. これは、安全性の低い暗号化に移行することのデメリットもあります。
    3. ユーザーパスワードを強制的にリセットする必要がある場合があります。
  3. LDAPやSSOソリューションのようなサードパーティの認証サービスを使用する。
    1. 認証のプロセスはオフロードされ、Liferayプラットフォームは、認証情報の送信やセッションの管理など、サードパーティのサービスとのネゴシエーションを行うだけです。
この記事は役に立ちましたか?
0人中0人がこの記事が役に立ったと言っています