Конфигурация источника данных для исключения взаимоблокировок требует новых методов
Во время стресс-тестирования моего слоя JPA
на основе DAO
(Запуск 500 одновременных обновлений одновременно в отдельном потоке). Я столкнулся со следующим-система всегда застревала, не в состоянии сделать какой-либо прогресс.
Проблема заключалась в том, что в какой-то момент не было доступных соединений для любого потока, поэтому ни один запущенный поток не мог добиться прогресса.
Я исследовал это некоторое время, и корень был REQUIRES_NEW
аннотацией на add
методе в одном из моих JPA DAO's
.
Так что сценарий:
- тест начинает получать новые
Connection
отConnectionPool
, чтобы начать транзакцию. - после некоторой начальной фазы, я вызываю
add
на мойDAO
, заставляя его запрашивать другойConnection
изConnectionPool
, которых нет, потому что всеConnections
к тому времени были взяты параллельными запущенными тестами.
Я пытался играть с конфигурациями источников данных
-
c3p0
stucks -
DBCP
stucks -
BoneCP
stucks -
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 секунды, пул прервется и выдаст исключение.
Также обратите внимание, что
REQUIRES
является более типичным. Часто вы хотите, чтобы цепочка вызовов совместно использовала транзакцию вместо того, чтобы начинать новую транзакцию для каждого нового вызова в цепочке.
Вероятно, любой из пулов соединений может быть настроен для решения этой проблемы любым количеством способов. В конечном счете, все, что требуется, - это, вероятно, заставить ваше приложение приобретать более одного соединения на клиента, что умножает напряженность ваших стресс-тестов. Если пулы висят, это, вероятно, потому, что у них заканчиваются соединения. Если вы установите достаточно большой размер пула, вы можете решить эту проблему. В качестве альтернативы, как предлагает Арджан выше, вы можете настроить пулы на "быстрый сбой" вместо того, чтобы висеть бесконечно, если клиенты должны ждать соединения. С c3p0 конфигурационный параметр для этого будет checkoutTimeout.
Без дополнительной информации о том, что именно происходит, когда вы говорите пул соединений "stucks", это обязательно догадки. Но при очень высокой параллельной нагрузке, с любым пулом соединений, вам либо нужно будет сделать много доступных ресурсов (высокий maxPoolSize + numHelperThreads в c3p0), выгнать лишних клиентов (checkoutTimeout), либо пусть клиенты просто терпят долго (но не бесконечно!) время ожидания.