Как DataSource вызывает validationQuery - PullRequest
0 голосов
/ 02 мая 2018

Я изо всех сил пытаюсь понять, как источник данных выполняет проверку. У меня есть пул соединений, который выполняет запрос к базе данных Firebird, но в пуле есть несколько соединений, которые выдают ошибку типа

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

Я не уверен, почему источник данных не делает их недействительными с помощью запроса проверки. Созданный мной источник данных не управляется контейнером, поэтому не уверен, что именно по этой причине не вызывается запрос проверки.

Я создал боб источника данных и зарегистрировал его на бобах Spring, как показано ниже.

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
    }
}

StackTrace:

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 

1 Ответ

0 голосов
/ 04 мая 2018

Ошибка сама по себе означает, что Firebird пытался выделить память для кэша буфера страниц, но не смог (потому что ОС исчерпала память или достигла максимального объема памяти, доступного для процесса). Проблема не связана с запросом проверки, трассировка стека показывает, что это происходит при создании нового соединения. И если пул не может выделить новое соединение для обслуживания вашего запроса, он откажется.

Исходя из нашего обмена в комментариях, похоже, что этот сервер Firebird настроен в режиме Classic Server (CS) или SuperClassic (SC). В этом режиме кэш буфера страниц относится к соединению, а не к базе данных (в режиме SuperServer (SS) - к базе данных). В результате, чем больше соединений, тем выше потребление памяти.

Это будет означать, что либо вы выделяете слишком много подключений, либо число настроенных страниц кэша слишком велико (применяется наиболее конкретная конфигурация - если установлена):

  • firebird.conf настройка DefaultDbCachePages) установлена ​​слишком высоко (по умолчанию 75 для CS / SC и 2048 для SS)
  • Настройка для базы данных (см. gstat -h вывод)
  • Свойство подключения isc_dpb_num_buffers / num_buffers

В случае Classic / SuperClassic это приводит к выделению NCachePages * Размер страницы байт памяти на соединение , где Pagesize - это размер страницы базы данных (обычно 8 или 16 килобайт) .

Например, при использовании по умолчанию 75 буферов для CS / SC с размером страницы 16 КБ каждое соединение занимает 1228800 (1,2 МБ) памяти для кэша), поэтому 100 подключений требуется 122 МБ (игнорируя другие потребности в памяти за пределами кэш).

С другой стороны, если этот параметр был изменен (либо глобально, в базе данных, либо с настройкой для каждого подключения), например, на 9999 страниц, то каждое подключение занимает 163 МБ памяти, а на 100 подключений потребуется 16 ГБ. .

Чтобы решить эту проблему, вам нужно выполнить одно или несколько из следующих действий:

  • Уменьшите количество необходимых соединений (при хорошем пуле соединений и небольших единицах работы вы можете быть удивлены тем, как мало соединений вам нужно)
  • Уменьшить количество страниц, выделенных для кеша
  • Увеличение памяти, доступной для процесса Firebird
  • Уменьшите размер страницы путем резервного копирования и восстановления базы данных с меньшим размером страницы
  • Переключение в режим SuperServer вместо Classic / SuperClassic

Последние два могут привести к значительным изменениям производительности (возможно, положительным, возможно, отрицательным), поэтому их следует тщательно проверить.

В качестве обходного пути, если вы не можете заставить владельца изменить конфигурацию в кратчайшие сроки, рассмотрите возможность добавления свойства соединения num_buffers=75 (или аналогичного небольшого числа) в свойства вашего соединения.

...