1

私には、断続的で再現が難しい、楽しい問題の1つがあります。

数分または数日の操作の後、テストサーバー上のgrailsアプリが失敗します。Devまたはローカルで複製できません。

ここでのスタックトレースパターンの例は、1000の行として中央を切り取っています(これは、Tomcatを再起動するまでこのようにダンプし続けます):

at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
Caused by: javax.servlet.ServletException: javax.servlet.ServletException: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at net.sf.ehcache.constructs.web.filter.Filter.logThrowable(Filter.java:143)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:91)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
......
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
Caused by: javax.servlet.ServletException: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at grails.plugin.cache.web.filter.AbstractFilter.logThrowable(AbstractFilter.java:116)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:70)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)

..................
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at grails.plugin.springcache.web.GrailsFragmentCachingFilter.doFilter(GrailsFragmentCachingFilter.groovy:66)
    at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
    at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:117)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:231)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
Caused by: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    ... 132 more
Caused by: java.lang.OutOfMemoryError: Java heap space

これは、アプリケーションエラーが発生した可能性があるように見えます。errorHandlerが呼び出され、それ自体が呼び出され続けます... kaboom!

環境

  • 穀物:2.0.4
  • Tomcat:apache-tomcat-7.0.28
  • OS:Red Hat Enterprise Linux Serverリリース5.8(Tikanga)

Java

java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.8) (rhel-1.27.1.10.8.el5_8-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)

開発中のJavaは(そしてこれは私がテストシステムでSAを変更させようとしている主な問題である可能性があります)

java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode)

サーバーには現在、0〜5人のユーザーがログオンしているだけですが、これは24時間にわたって増減します。

割り当てられるヒープスペースは5gで、通常は20%未満が使用されます。

テストでは発生し、開発では発生しない他の2つの奇妙なことがあります。

  • ログは、元々ログがほとんどありませんでしたが、問題のために、50日にロールオフするDEBUGおよびRollingFile100Megファイルに開かれました。ログは問題ありません。スタックが爆発するまでアプリ固有のものをログに記録します。その後、ログに含まれるのはスタックだけです。Tomcatのログにも同じことが言えます。これは、50番目のログがロールオフされるかなり前にサーバーをシャットダウンした場合でも同様です。したがって、これをトリガーするアプリ固有のフードゥーが発生しているかどうかはわかりません。

  • JavaMelodyプラグイン:グラフのラベルは、私の3歳の人が書いたように読めません。すべてのOSフォントがロードされていると思いますが、Javaバージョンを指している可能性があります。

スケジューラー: はい、2つ実行されていますが、問題なく実行されています

DB構成: レガシーDBには8つのデータソースがあり、それぞれが現在少し空腹に設定されている可能性があります。例:

def connectionPropertiesMedium = [
        maxActive: 100,
        maxIdle: 30,
        minIdle: 5,
        initialSize: 30,
        testOnBorrow: true,
        testWhileIdle: false,
        testOnReturn: false,
        validationQuery: "SELECT 1",
        minEvictableIdleTimeMillis: 600000,
        timeBetweenEvictionRunsMillis: 600000,
        numTestsPerEvictionRun: 3,
        maxWait: 10000,
        defaultTransactionIsolation: java.sql.Connection.TRANSACTION_READ_UNCOMMITTED
]

HeapDump: VisualVMを使用してReadingで 実行すると、-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof (とにかく)70%以上が上記のスタックトレースでいっぱいのchar[]であることがわかります。EclipseMATはそれをロードしません。

JVM引数:

CATALINA_OPTS="-server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof -XX:MaxPermSize=1024m -XX:MaxNewSize=256m -XX:NewSize=256m -Xms768m -Xmx1024m -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseTLAB -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSIncrementalMode -XX:-UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent

ストレステスト: アプリが実行できる強力なクエリがいくつかあります。これらは、最大200人のシミュレートされたJMeterユーザーによって問題なく数回ヒットされます...実際、DBは少し遅くなりました;)しかし、メモリの問題は多くの実行で複製されません。

したがって、誰かがこれまで読んだ場合、私は2つのリードを持っています(もっとオープン):

  • Javaバージョン-OpenJDKを終了して標準リリースに移行することを目指しています
  • エラーが発生したときに無限/再帰的な処理を引き起こしている私のGrailsセットアップの何か。

これらのマシン内のゴーストを核攻撃するプロトンパックが見つかるまで、このアプリは稼働しません。

何か案は?

乾杯...

アップデート#1

Java 1.7をインストールし、OpenJDKを削除しました。これにより、JavaMelodyの表示の問題が確実に修正されました。これで主要な問題が修正されたかどうかを確認するための待機中のゲームになりました。興味深いことに、このサイトは著しく高速に見えます。

4

1 に答える 1

1

ユーザーがログインフォームを(j_spring_security_checkに)複数回再送信すると、カスタムUserDetailsS​​erviceでUser.save()(最後のログイン時刻を更新するなど)が呼び出され、各ユーザーの後続の呼び出しでHibernateセッションが閉じられました。

User.save()をAuthenticationEventListener.onApplicationEvent(AuthenticationSuccessEvent event)に移動すると、正常に動作します。

このための基本的なセットアップは、Springセキュリティコアプラグインのドキュメントからのものです-イベント、私のものは次のようなものです:

構成に以下を追加します。grails.plugin.springsecurity.useSecurityEventListener = true

resources.groovy:

import security.AuthenticationEventListener
....
authenticationEventListener(AuthenticationEventListener)

AuthenticationEventListener.groovy:

class AuthenticationEventListener implements ApplicationListener<AuthenticationSuccessEvent> {

    void onApplicationEvent(AuthenticationSuccessEvent event) {
        if (event instanceof AuthenticationSuccessEvent) {
            UserDetails userDetails = (UserDetails) event.getAuthentication().getPrincipal()
            def httpSession = SecurityRequestHolder.request.session

            if (!httpSession.loggedIn) {
                httpSession.loggedIn = true
                synchronized (httpSession.loggedIn) {
                    httpSession.timeZone = userDetails.timeZone
                    User.withSession { session ->
                        if (session.isOpen()) {
                            User user = User.findByUsername(userDetails.username, [fetch: [roles: 'eager']])
                            user.lastLoggedIn = new Date()
                            user.save(flush: true)
                        }
                    }
                }
            }
        }
    }
}
于 2012-08-29T01:02:26.113 に答える