Конфигурация источника данных для исключения взаимоблокировок требует новых методов


Во время стресс-тестирования моего слоя JPA на основе DAO (Запуск 500 одновременных обновлений одновременно в отдельном потоке). Я столкнулся со следующим-система всегда застревала, не в состоянии сделать какой-либо прогресс.

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

Я исследовал это некоторое время, и корень был REQUIRES_NEW аннотацией на add методе в одном из моих JPA DAO's.

Так что сценарий:

  1. тест начинает получать новые Connection от ConnectionPool, чтобы начать транзакцию.
  2. после некоторой начальной фазы, я вызываю add на мой DAO, заставляя его запрашивать другой Connection из ConnectionPool, которых нет, потому что все Connections к тому времени были взяты параллельными запущенными тестами.

Я пытался играть с конфигурациями источников данных

  1. c3p0 stucks
  2. DBCP stucks
  3. BoneCP stucks
  4. MySQLDataSource потерпеть неудачу некоторые запросы, с ошибкой - количество подключений превысило допустимое.

Хотя я решил его, прочитав REQUIRES_NEW, с которым все источники данных работали отлично, все же лучший результат, кажется, из MySQLDataSource, так как он не застрял и просто провалился:)

Таким образом, кажется, что вы не должны использовать REQUIRES_NEW вообще, если вы ожидаете высокую пропускную способность.

И мой вопрос:

Существует ли конфигурация для любого источника данных, которая могла бы предотвратить это требует решения новой проблемы?


Я играл с checkout timeout в c3p0, и тесты начали проваливаться, как и ожидалось.

  • 2 сек-8% пройдено
  • 4 сек-12% пройдено
  • 6 сек-16% пройдено
  • 8 сек-26% пройдено
  • 10 сек-34% пройдено
  • 12 сек-36% пройдено
  • 14/16/18 сек-40% пройдено

Это, конечно, очень субъективно.

MySQLDataSource с равниной конфигурации давали 20% пройденных испытаний.

2 2

2 ответа:

Как насчет настройки тайм-аута для получения соединения? Если соединение не может быть получено, скажем, за 2 секунды, пул прервется и выдаст исключение.

Также обратите внимание, что REQUIRES является более типичным. Часто вы хотите, чтобы цепочка вызовов совместно использовала транзакцию вместо того, чтобы начинать новую транзакцию для каждого нового вызова в цепочке.

Вероятно, любой из пулов соединений может быть настроен для решения этой проблемы любым количеством способов. В конечном счете, все, что требуется, - это, вероятно, заставить ваше приложение приобретать более одного соединения на клиента, что умножает напряженность ваших стресс-тестов. Если пулы висят, это, вероятно, потому, что у них заканчиваются соединения. Если вы установите достаточно большой размер пула, вы можете решить эту проблему. В качестве альтернативы, как предлагает Арджан выше, вы можете настроить пулы на "быстрый сбой" вместо того, чтобы висеть бесконечно, если клиенты должны ждать соединения. С c3p0 конфигурационный параметр для этого будет checkoutTimeout.

Без дополнительной информации о том, что именно происходит, когда вы говорите пул соединений "stucks", это обязательно догадки. Но при очень высокой параллельной нагрузке, с любым пулом соединений, вам либо нужно будет сделать много доступных ресурсов (высокий maxPoolSize + numHelperThreads в c3p0), выгнать лишних клиентов (checkoutTimeout), либо пусть клиенты просто терпят долго (но не бесконечно!) время ожидания.