java - 连接到 Firebird 数据库时出现错误 "Insufficient memory to allocate page buffer cache"

标签 java tomcat jdbc firebird jaybird

我很难理解数据源如何运行验证。我有一个在 Firebird 数据库上运行查询的连接池,但是池中的连接很少会抛出类似

的错误
Insufficient memory to allocate page buffer cache [SQLState:HY013, ISC error code:335544691

我不确定为什么数据源不使用验证查询使它们无效。我创建的数据源不是容器管理的,所以不确定这是否是未调用验证查询的原因。

我创建了一个数据源 bean 并将其注册到 spring bean 上,如下所示。

builder.beans {
    "${beanName}"(org.apache.tomcat.jdbc.pool.DataSource) {

      driverClassName = "${configuration.driver}"
      url = configuration.connectionUrlPrefix
      username = configuration.userName
      password = configuration.password
      maxActive = properties.maxActive
      maxIdle = properties.maxIdle
      minIdle = properties.minIdle
      initialSize = properties.initialSize
      maxWait = properties.maxWait
      validationQuery = properties.validationQuery
      validationInterval = properties.validationInterval
      testWhileIdle = properties.testWhileIdle
      testOnBorrow = properties.testOnBorrow
      logAbandoned = properties.logAbandoned
      removeAbandoned = properties.removeAbandoned
      removeAbandonedTimeout = properties.removeAbandonedTimeout
      timeBetweenEvictionRunsMillis = properties.timeBetweenEvictionRunsMillis
      minEvictableIdleTimeMillis = properties.minEvictableIdleTimeMillis
    }
}

堆栈跟踪:

2018-05-02 11:30:52,766 [ajp-bio-8012-exec-7] ERROR StackTrace  - Full Stack Trace:
 java.sql.SQLException: Insufficient memory to allocate page buffer cache [SQLState:HY013, ISC error code:335544691]
    at org.firebirdsql.gds.ng.FbExceptionBuilder$Type$1.createSQLException(FbExceptionBuilder.java:498)
    at org.firebirdsql.gds.ng.FbExceptionBuilder.toFlatSQLException(FbExceptionBuilder.java:299)
    at org.firebirdsql.gds.ng.wire.AbstractWireOperations.readStatusVector(AbstractWireOperations.java:135)
    at org.firebirdsql.gds.ng.wire.AbstractWireOperations.processOperation(AbstractWireOperations.java:199)
    at org.firebirdsql.gds.ng.wire.AbstractWireOperations.readSingleResponse(AbstractWireOperations.java:166)
    at org.firebirdsql.gds.ng.wire.AbstractWireOperations.readResponse(AbstractWireOperations.java:150)
    at org.firebirdsql.gds.ng.wire.AbstractWireOperations.readGenericResponse(AbstractWireOperations.java:252)
    at org.firebirdsql.gds.ng.wire.version10.V10WireOperations.authReceiveResponse(V10WireOperations.java:52)
    at org.firebirdsql.gds.ng.wire.version10.V10Database.authReceiveResponse(V10Database.java:566)
    at org.firebirdsql.gds.ng.wire.version10.V10Database.attachOrCreate(V10Database.java:110)
    at org.firebirdsql.gds.ng.wire.version10.V10Database.attach(V10Database.java:80)
    at org.firebirdsql.jca.FBManagedConnection.<init>(FBManagedConnection.java:144)
    at org.firebirdsql.jca.FBManagedConnectionFactory.createManagedConnection(FBManagedConnectionFactory.java:520)
    at org.firebirdsql.jca.FBStandAloneConnectionManager.allocateConnection(FBStandAloneConnectionManager.java:65)
    at org.firebirdsql.jdbc.FBDataSource.getConnection(FBDataSource.java:117)
    at org.firebirdsql.jdbc.FBDriver.connect(FBDriver.java:137)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:278)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:182)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:712)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:646)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:468)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:145)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:116)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:103)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:127)
    at javax.sql.DataSource$getConnection.call(Unknown Source)
    at 

最佳答案

错误本身意味着 Firebird 试图为页面缓冲区缓存分配内存,但不能(因为操作系统内存不足,或者它达到了进程可用的最大内存量)。该问题与验证查询无关,堆栈跟踪显示它是在创建新连接时发生的。如果池无法分配新连接来为您的请求提供服务,它将放弃。

根据我们在评论中的交流,看起来这个 Firebird 服务器配置为经典服务器 (CS) 或 SuperClassic(SC) 模式。在这种模式下,页面缓冲区缓存是针对每个连接的,而不是针对每个数据库的(在 SuperServer (SS) 模式中,它是针对每个数据库的)。因此,连接越多,内存消耗就越高。

这表明您分配的连接太多,或者配置的缓存页数太高(最具体的配置 - 如果设置 - 适用):

  • firebird.conf 设置 DefaultDbCachePages) 设置得太高(CS/SC 的默认值为 75,SS 的默认值为 2048)
  • 特定于数据库的设置(参见 gstat -h 输出)
  • 连接属性isc_dpb_num_buffers/num_buffers

对于 Classic/SuperClassic,这会导致分配 NCachePages * Pagesize 字节的内存每个连接,其中 Pagesize 是数据库的页面大小(通常为 8 或 16千字节)。

例如,对于页面大小为 16kb 的 CS/SC,默认情况下有 75 个缓冲区,每个连接需要 1228800(1.2 MB)内存用于缓存),因此 100 个连接需要 122 MB(忽略其他内存需求缓存)。

另一方面,如果此设置已更改(全局、数据库或每个连接设置),例如,9999 页,则每个连接占用 163 MB 内存,而 100 个连接将需要 16GB .

要解决此问题,您需要执行以下一个或多个步骤:

  • 减少所需的连接数量(使用良好的连接池和小的工作单元,您可能会惊讶于您需要的连接数量如此之少)
  • 减少分配给缓存的页面数量
  • 增加 Firebird 进程可用的内存
  • 通过使用较小的页面大小备份和恢复数据库来减少页面大小
  • 切换到 SuperServer 模式而不是 Classic/SuperClassic

最后两个可能会导致性能发生重大变化(可能是正面的,也可能是负面的),因此应该仔细测试它们。

作为解决方法,如果您不能让所有者在短时间内更改配置,请考虑将连接属性 num_buffers=75(或类似的低数字)添加到您的连接属性。

关于java - 连接到 Firebird 数据库时出现错误 "Insufficient memory to allocate page buffer cache",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50142952/

相关文章:

java - dl4j 不包含文本和模型模块

java - 如何将参数从 Java Controller 传递到 Thymeleaf 模板

java - Spring 启动: how to update object efficently?

Tomcat:用于与 Tomcat 5.5 JNDI 树建立外部客户端连接的初始化上下文参数是什么?

html - Tomcat7 -> Tomcat8 - 服务器只打印一半的 html 页面

java - 无法在控制台输出中打印 SQL 语句

java - 连接到 Amazon RDS 时被阻止

java - 在java中将String转换为long

tomcat - 服务器中的错误 404 错误

java - 通过 JDBC 的 Postgres 连接 : org. postgresql.util.PSQLException: ERROR: relation "prescriptions"does not exist