我有一个 Java (Tomcat) 应用程序,它使用 MySQL(带 Hibernate)作为数据库。
这是一个简单的 Java JSF 应用程序,只有三个用户同时使用该系统。 (有两种大表,有 20k 行 - 通常在它卡住时就在那里。)
系统一直死机,需要重启Tomcat和MySQL才能正常工作。
在我的日志中:
[WARN] 2017-11-08 16:53:02,438 com.zaxxer.hikari.pool.PoolBase isConnectionAlive - HikariPool-1 - Failed to validate connection com.mysql.jdbc.JDBC4Connection@33dc5260
还有:
[WARN] 2017-11-08 17:04:32,200 com.zaxxer.hikari.pool.HikariPool run - HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m22s40ms97µs73ns).
和(90 倍):
[WARN] 2017-11-08 17:04:35,438 com.zaxxer.hikari.pool.PoolBase isConnectionAlive - HikariPool-1 - Failed to validate connection com.mysql.jdbc.JDBC4Connection@2c365a2e (No operations allowed after connection closed.)
还有:
java.lang.OutOfMemoryError: GC overhead limit exceeded
后来我还得到:“java.lang.OutOfMemoryError: Java heap space”,但系统只使用了 760Mb。
(是的,有很多错误,这就是为什么我很难弄清楚如何修复它!)
有什么建议吗?
我在setenv.sh设置:
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx512m"
export CATALINA_OPTS="$CATALINA_OPTS -server"
当我验证正在使用的内存时,显示:
mysqld = 165.3 MiB
java = 662.0 MiB
我正在使用 Hikari 连接池,如下所示:
<property name="hibernate.hikari.maximumPoolSize" value="200" />
<property name="hibernate.hikari.idleTimeout" value="30000" />
<property name="hibernate.hikari.maxLifetime" value="600000" />
<property name="hibernate.hikari.dataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" />
<property name="hibernate.connection.provider_class" value="org.hibernate.hikaricp.internal.HikariCPConnectionProvider" />
MySQL 最大连接数设置为 152。
MySQL my.cnf 设置:
wait_timeout = 360
interactive_timeout = 420
服务器在具有 1Gb Ram 和 1 个 vCPU 的 DigitalOcean Droplet 中运行。此服务器的最佳 Tomcat + MySQL + Hikari 配置是什么?
我删除了 Xms512m 和 Xmx512m 参数并将 maximumPoolSize 减少到 20,服务器运行正常几个小时后,我得到:
ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - HikariPool-1 - Connection is not available, request timed out after 30004ms. javax.persistence.PersistenceException:
org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
Caused by: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
最佳答案
其中一个清晰可见的问题:
java.lang.OutOfMemoryError: GC overhead limit exceeded
表示您没有足够的堆内存,JVM 花费大量时间进行垃圾收集。
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx512m"
告诉 JVM,Tomcat 和它正在运行的所有应用程序最初应该保留 512 Mb 的内存,并且它们最多可以分配 512 Mb 的内存。
从上面的错误可以看出,512 Mb 显然对您的应用来说不够。
供您考虑的选项:
- 在您的 Tomcat
Connector
中定义了什么maxThreads
值。默认为200
。每个线程占用内存。如果只有 3 个用户,我希望您可以将其减少到 5 个以节省内存。 hibernate.hikari.maximumPoolSize
似乎也太大了。同样,5
应该足够了。- Hibernate 加载的每个@Entity 都存储在first level cache 中.这会减慢 Hibernate 的速度并消耗内存。考虑使用 stateless session (如果可能)减少 session 大小。
- 使用VisualVM或其他一些分析器进行内存转储以分析您的内存去向。
关于java - Apache Tomcat 8 + MySQL 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47186214/