設定 WebLogic 的 memory 參數

這是第二次吃虧了, 把他記下來, 免得下次又忘記了…

問題的起源在於記憶體不足, 通常訊息如下. 一次是某個單一 XML 訊息太大, 另一次是 ear 檔案太大, re-deploy 的時候會出問題.

java.lang.OutOfMemoryError: PermGen space

如果是簡單的 Java 程式, 那解法很簡單, 改參數就好了, 把 -XX:PermSize=** 放大即可. 不過在 WebLogic 裡面, script 包了好幾層, 就很容易漏掉了. 這次就是因為呆呆的直接在最外層設定 MEM_ARGS, 然後被裡層的 script 蓋掉了, 所以當然沒作用…

建議的作法是修改 USER_MEM_ARGS, 可參考 Modifying JVM Parameters in Server Start Scripts

最後, 在 WebLogic 10, 設定環境變數的程式在 domains//bin/setDomainEnv.sh, 可以看出不同平台, 甚至 production/develop mode 的不同也會導致參數不同, 不過不建議改這裡.

if [ “${JAVA_VENDOR}" = “Sun" ] ; then
if [ “${PRODUCTION_MODE}" = “" ] ; then
MEM_DEV_ARGS="-XX:CompileThreshold=8000 -XX:PermSize=48m "
export MEM_DEV_ARGS
fi
fi

# Had to have a separate test here BECAUSE of immediate variable expansion
on windows

if [ “${JAVA_VENDOR}" = “Sun" ] ; then
MEM_ARGS="${MEM_ARGS} ${MEM_DEV_ARGS} -XX:MaxPermSize=128m"
export MEM_ARGS
fi

if [ “${JAVA_VENDOR}" = “HP" ] ; then
MEM_ARGS="${MEM_ARGS} -XX:MaxPermSize=128m"
export MEM_ARGS
fi

# IF USER_MEM_ARGS the environment variable is set, use it to override ALL
MEM_ARGS values

if [ “${USER_MEM_ARGS}" != “" ] ; then
MEM_ARGS="${USER_MEM_ARGS}"
export MEM_ARGS
fi

JDBC Leaked Connection in WebLogic

最近發現某個 WebLogic 的 JDBC connection 只會增加, 不會減少, 意思是說, 程式和 WebLogic 拿了很多 JDBC connection, 但是都沒有還給系統. 在程式執行一段時間之後, 就會拿不到 JDBC connection 了, 然後就掛了. WebLogic 的 console 可以看到, connection 的數字一直增加.

jdbc_monitor

WebLogic 的 log 如下, 整個 stack trace 就不全列出來了, 重點在於, 當 WebLogic 的 JDBC connection pool 的 connection 都被要光之後, 後面的程式就無法和 database 連線了.

java.sql.SQLException: Internal error: Cannot obtain XAConnection
weblogic.common.resourcepool.ResourceDeadException

因為在上圖中的 WebLogic 的 console 看到的 “leaked connection count" 一直都是 0, 所以我也沒有往這個方向思考過. 不過後來才發現需要做一些設定才能偵測 leaked connection, 如下

1. 設定 WebLogic 的 “Inactive Connection Timeout", 這個參數的意義是, 如果有個 JDBC connection 被拿走之後, 超過一段時間沒有使用 (如下圖, 代表 10 分鐘), 則系統就會自動收回. (其實設定這個之後, 這個問題基本上就已經暫時解決了)

jdbc_connection_pool

2. 打開偵測的工具, 如下圖, 系統就會在 log 顯示 leaked connection 的資訊

jdbc_diagnostics

設定好之後 (不用重開 WebLogic) , 觀察系統一段時間, 結果如下, 看到 “leaked connection count" 的值不再是 0 了, 而 active connection 在沒人使用時, 也會降到 0 了.

jdbc_monitor_leaked

之後 WebLogic 的 log (放在 user_projects/domains/%domainname%/%servername%/logs, 而不是自己 AP 的 log) 如下, 整個 stack trace 滿大的, 重點在第 28 行, 問題發生在 “com.test.dao.getStatus" 這個 method, 意思就是說, 有某個 JDBC connection 在這個程式被拿走之後, 一直沒有還給系統, 於是就找到兇手了.

  1. ####<Mar 11, 2009 11:14:36 PM CST> <Warning> <JDBC> <testserver1> <Server1> <[ACTIVE] ExecuteThread: ‘4’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <<WLS Kernel>> <> <> <1236748476017> <BEA-001153> <Forcibly releasing inactive connection “[weblogic.jdbc.wrapper.JTAConnection_weblogic_jdbc_wrapper_XAConnection_oracle_jdbc_driver_LogicalConnection-TEST_DS-311, oracle.jdbc.driver.LogicalConnection@42a794]" back into the connection pool “TEST_DS", currently reserved by: java.lang.Exception
  2.         at weblogic.jdbc.common.internal.ConnectionEnv.setup(ConnectionEnv.java:291)
  3.         at weblogic.common.resourcepool.ResourcePoolImpl.reserveResource(ResourcePoolImpl.java:314)
  4.         at weblogic.common.resourcepool.ResourcePoolImpl.reserveResource(ResourcePoolImpl.java:292)
  5.         at weblogic.jdbc.common.internal.ConnectionPool.reserve(ConnectionPool.java:425)
  6.         at weblogic.jdbc.common.internal.ConnectionPool.reserve(ConnectionPool.java:316)
  7.         at weblogic.jdbc.common.internal.ConnectionPoolManager.reserve(ConnectionPoolManager.java:93)
  8.         at weblogic.jdbc.common.internal.ConnectionPoolManager.reserve(ConnectionPoolManager.java:61)
  9.         at weblogic.jdbc.jta.DataSource.getXAConnectionFromPool(DataSource.java:1474)
  10.         at weblogic.jdbc.jta.DataSource.refreshXAConnAndEnlist(DataSource.java:1303)
  11.         at weblogic.jdbc.jta.DataSource.getConnection(DataSource.java:426)
  12.         at weblogic.jdbc.jta.DataSource.connect(DataSource.java:383)
  13.         at weblogic.jdbc.common.internal.RmiDataSource.getConnection(RmiDataSource.java:339)
  14.         at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
  15.         at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
  16.         at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
  17.         at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:139)
  18.         at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1547)
  19.         at org.hibernate.loader.Loader.doQuery(Loader.java:673)
  20.         at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
  21.         at org.hibernate.loader.Loader.doList(Loader.java:2220)
  22.         at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
  23.         at org.hibernate.loader.Loader.list(Loader.java:2099)
  24.         at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:289)
  25.         at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1695)
  26.         at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142)
  27.         at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:152)
  28.         at com.test.dao.getStatus(dao.java:194)
  29.         at sun.reflect.GeneratedMethodAccessor755.invoke(Unknown Source)
  30.         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  31.         at java.lang.reflect.Method.invoke(Method.java:585)
  32.         at org.apache.axis2.rpc.receivers.RPCUtil.invokeServiceClass(RPCUtil.java:194)
  33.         at org.apache.axis2.rpc.receivers.RPCMessageReceiver.invokeBusinessLogic(RPCMessageReceiver.java:102)
  34.         at org.apache.axis2.receivers.AbstractInOutMessageReceiver.invokeBusinessLogic(AbstractInOutMessageReceiver.java:40)
  35.         at org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:100)
  36.         at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:176)
  37.         at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:275)
  38.         at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:133)
  39.         at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
  40.         at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
  41.         at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:226)
  42.         at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:124)
  43.         at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:283)
  44.         at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
  45.         at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3395)
  46.         at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
  47.         at weblogic.security.service.SecurityManager.runAs(Unknown Source)
  48.         at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2140)
  49.         at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2046)
  50.         at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1366)
  51.         at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200)
  52.         at weblogic.work.ExecuteThread.run(ExecuteThread.java:172)

使用環境: WebLogic 10.0 MP1, JDBC driver 使用的是內建的 Oracle thin driver. 另外也發現一件事情, 如果改用 Bea 的 Oracle driver, 則 connection 成長的速度會放慢, 但最後還是一樣會爆掉的啦