джава приложениях совместно с pg_bouncer? столкнулись с проблемой, при работе с постгресом в кластере (patroni, keepalived, pg_bouncer), при переезде мастера и переключения коннектов на боунсер другой ноды - подключения задваиваются, тем самым забивая пул боунсера. через час они сами терминируются, возможно это параметр таймаута хикари. или спасает также перезагрузить боунсер после смены ноды мастера. все параметры боунсера я перепробовал, добиться результатов не вышло.
вроде, pg_bouncer изначально создавался как коннекшн пулер для бедных (например, для сайтов на php, которые каждый раз новое подключение открывают). Чтобы использовать его в системе, где есть свой коннекш пул, нужно обоснование. Например - у вас несколько нод на java используют одни и те-же подключения к БД когда нагрузки особой нет (сомнительный вариант, т.к. при пиковой нагрузке всё равно понадобятся все подключения).
относительно боунсера есть много мнений все же, но спасибо за аргументацию, приму к сведению.
Теоретически, pg_bouncer с pool_mode = transaction может позволить в непиковое время поддерживать суммарно меньшее число сессий. Если pool_mode = session, смысла ставить баунсер перед пулом в java вообще не понимаю. Только одни минусы (в частности, в БД будет видно адрес клиента 127.0.0.1 вместо реального IP).
если в базу ходят не только java но и другие приложения, которые в пул пока не умеют
вот можно другие приложения пускать через баунсер, а java пусть напрямую ходит
Два коннекшн пула это конечно не дело, но почему вы в таком случае отдаёте предпочтение hikaricp? При смене мастера джава приложение никак не узнает об этом (потому что по дефолту keepalive отключен в hikaricp), до тех пор пока какой-то поток не получит коннект из пула и не попытается им воспользоваться, упав при этом с ошибкой. С другой стороны, если оставить только pgbouncer, его в момент файловера можно пнуть через хук и заставить переконнектиться. Что вы об этом думаете?
Я обычно пулы настраиваю так, чтобы перед получением коннект тестировался
ну это же лишний roundtrip в базу и обратно. как минимум дороговато, а для высоких rps просто неприемлемо.
И кстати, как это сдeлать для HikariCP ? Не помню чтоб он предоставлял такую возможность. Периодический keepalive можно включить, но вот именно тестирование коннекта каждый раз перед использованием - как?
Другого способа гарантированно (ну пусть будет 99.9%) получить рабочий коннект. Либо писать код, чтобы он повторял попытку, если падает первый запрос. Есть вариант с проверкой коннектов в фоне, но он не даёт таких гарантий (при высоких rps вы наткнётесь на половину битых подключений до того, как maintenance thread их удалит сам). По поводу возможностей hikaricp надо смотреть, я последний раз его настраивал 3 года назад.
https://github.com/brettwooldridge/HikariCP#gear-configuration-knobs-baby connectionTestQuery
это не то. во первых, это для фоновых keepalive запросов по таймеру (см. keepaliveTime), который по умолчанию отключен. а во вторых, там ведь жирным текстом написано "we strongly recommend not setting this property"
Как я понял, этот запрос выполняется перед выдачей подключения из пула. При этом, если этот параметр не установлен, значит он должен вызывать Connection.isValid(), по идее
Да, проверяется при выдаче, но не чаще чем 1 раз в 500 мс. Есть недокументированный параметр "aliveBypassWindowMs". Если хотите проверять каждый раз, то установите его в ноль. https://github.com/brettwooldridge/HikariCP/blob/ed2da5f1f4ef19f871fac12effc0b199706905dc/src/main/java/com/zaxxer/hikari/pool/HikariPool.java#L170
> Два коннекшн пула это конечно не дело, но почему вы в таком случае отдаёте предпочтение hikaricp? Отвечу более развёрнуто. Передо мной не стояла задача автопереключения, но если бы стояла, то hikaricp предоставляет на каждый датасорс по два бина доступных по JMX (один для мониторинга, второй для настройки). Там, правда, именно переключение не сделать (мб. потому что я внутри подсовываю Datasource из jdbc-драйвера PostgreSQL), но никто не мешает сделать такую переключалку самому. С другой стороны, при использовании баунсера, в момент, когда мне понадобилось подключение, нужно было бы тратить время на собственно установку TCP-подключения (если настроено шифрование - это еще доп.затраты на SSL), аутентификацию и начальную настройку сессии. В случае пула работающего в JVM, у меня уже пачка готовых подключений. По итогу, даже если делать тестовый запрос перед отдачей подключения из пула, локальный пул получается выгоднее.
Пачка готовых соединений в пуле может быть и преимуществом и недостатком. Например, если у вас множество микросервисов, и у каждого свой собственный пул, то у вас точно будет висеть впустую множество idle коннектов на всякий случай. Топикстартер изначально спрашивал как раз про авто-переподключение к БД после смены мастера. Мне кажется, что с внешним пулером это сделать проще, потому что можно отработать событие смены мастера и автоматом сбросить весь пул. И приложение про это даже не узнает. Хотя, смена мастера тоже происходит не мгновенно, так что приложение, весьма вероятно, успеет нахватать ошибок коннекта к БД. Опять же, зависит от конкретного сетапа. А ещё бывает схема с несколькими pgbouncer и перед ними фронт-балансер (haproxy), который слушает сразу два порта (read-write, read-only) и делает роутинг, т.к. всегда знает где мастер и где hot standby реплики. Это позволяет в приложении сделать умную фабрику (AbstractRoutingDataSource в спринге), чтобы она в зависимости от флага readOnly транзакции получала коннекты через правильный порт haproxy и таким образом снимала read-only нагрузку с мастера. При таком раскладе понадобилось бы целых 2 пула в джаве, а это еще больше накладных расходов и еще больше проблем при смене мастера. Что думаете?
если у нас пачка микросервисов, которые смотрят в одну бд, им самое место в одном сервере приложений (всё равно бд - общая точка отказа всех этих микросервисов) с централизованно настраиваемыми датасорсами (соответственно, пул будет единый). Если же бд разные, то сделать меньше коннектов не получится и с баунсером. Если же требуется прям по отдельной машине на каждый сервис выделять, то опять-же, hikaricp хорош тем, что его не обязательно настраивать на использование больших значений постоянно поддерживаемых подключений, т.к. он достаточно быстро выдаёт новые подключения при увеличении запросов (не дожидаясь, пока очередная пачка подключений создастся). С другой стороны, idle-подключения особо ресурсов не жрут (помимо памяти на процесс, которую всё равно пришлось бы зарезервировать для пиковых нагрузок). В любом случае, есть какое-то количество микросервисов, после которого вариант локальных пулов будет проблемным, но мне кажется, что раньше потребуется их на разные сервера БД рассаживать (хотя, конечно, тут абстрактно судить нет смысла, все проекты разные). Что касается схемы со снятием read-only нагрузки, не вижу принципиальной проблемы держать два пула, пока они смотрят на разные сервера БД. Какие сложности при этом могут быть у spring-ов с ними не в курсе, предпочитаю немного другой стек в jvm.
но замечу, что я больше базист, в java выношу то, что неудобно/трудно/нежелательно делать в хранимках, так что работать с десятков разрозненных сервисов на одной бд не приходилось. Знаю только то, что проблемы использования двух пулов (один в java, второй рядом с БД) возможны, но проявятся ли они при использовании конкретно hikaricp+bouncer покажет только тестирование. У нас было развёрнуто приложение на прод-стенде как раз с такой комбинацией, но там в случае проблем с БД тупо всё откатывалось и затем повторялась попытка (это был не онлайн-сервис, а обработчик очереди задач), какие-то проблемы заметили только когда сконфигурировали число потоков большее, чем предел числа коннектов в пуле, но гарантировать, что там не было других проблем я не смогу, т.к. мы тупо могли не заметить в силу офлайновости приложения.
Спасибо за ответ! По поводу объединения микросервисов в один монолит из-за общей БД не могу с вами согласиться. Их пилят разные команды, со своим собственным релмзным циклом. Какие-то микросервисы лишь иногда взаимодействуют с БД, а по большей части общаются через mq, или же проводят сложные расчёты требующие множества ядер, оттого их могут прямо на живом проде скейлить по разному. По остальному тоже есть что возразить, но не вижу смысла, ведь мы не спорим, а высказываем мнения. Конечно же нужно сначала знать все нюансы дизайна чтобы углубиться в детальное обсуждение.
👍 Идея каскадного пула звучит как потенциальная проблема
Ну для офлайновых сервисов, которые с внешним миром напрямую не контактируют, а с БД работают лишь иногда, по идее, скорость получения подключения к БД не должна играть большого значения, а значит действительно можно попробовать обойтись без своего пула прямым подключениям к БД. Локальный пул используют когда подключение к БД обязательная часть обработки каждой исполняемой задачи (будь то элемент очереди или веб-запрос). Если такого нет - просто берётся простой datasoure, без пула, либо настраивается минимальный таймаут, чтобы невостребованное подключение через пол минуты закрывалось. Что касается каскадного пула - по идее, если эти пулы спроектированы с учетом возможности каскада, то проблем не должно быть (собственно, я сходу не назову возможную причину проблем, но читал о проблемах двух конкретных реализаций (одна из них была в wls вроде)). Пулинг на сервере бд вполне применяемая практика (pgbouncer, у oracle есть своё решение, правда не уверен, что оно используется для jdbc), так что, по идее, в пулах общего назначения это должно учитываться. Но как на деле - не знаю. Да, спасибо за беседу. Очень познавательно узнать о примерах предусловий, заставляющих принимать решения отличные от тех, которые сам принимаешь
Обсуждают сегодня