Pull to refresh

Comments 20

Почему не pqxx: для С++ логичнее было бы его использовать? На STL думаю проще было бы pool организовать:
http://stackoverflow.com/questions/12528199/libpqxx-connection-pool

Он вроде даже когда-то был в этой библиотеке:
http://bazaar.launchpad.net/~jtv/libpqxx/connection-pool/view/head:/src/connection_pool.cxx

Can I have two or more simultaneous transactions?

Not within the same connection. Even if you use nested transactions (see the subtransaction class), a connection is always dealing with just one transaction at a time. Of course you can create a new transaction on the same connection once the previous one has completed.

If you want to have multiple concurrent transactions, let them work on different connections. An easy way to do this is to set up a connection pool: create a bunch of lazyconnection objects, all initialized with the same connection string. Connections of this type will set themselves up only when they are actually used, so there is no big cost to creating more than you're going to use.
http://pqxx.org/development/libpqxx/wiki/FaqFeatures
Она отстаёт по возможностям. Мне нужен был 9.5 c UPSERT, и на тот момент libpqxx не имел этой возможности.
Документация была гораздо хуже. С libpq работать одно удовольствие, там весьма простой Си с очень хорошими примерами.

На STL думаю проще было бы pool организовать

А я его на чём реализовал? Что здесь не из STL?
std::mutex m_mutex;
std::condition_variable m_condition;
std::queue<std::shared_ptr<PGConnection>> m_pool;


Простите, недоглядел. Глянул, что С и не увидел дальше. Хорошая у вас реализация и простая. Надо будет себе утянуть. Я бы только добавил ещё map<string, queue>, для группировки пулов по строкам подключения, если полноценный пул делать, когда не знаешь будут ли строки одинаковыми. А для REST-сервиса, при нехватке соединений m_pool.empty() создавал бы новое подключение.

Мне нужен был 9.5 c UPSERT, и на тот момент libpqxx не имел этой возможности.
А сейчас он там разве есть?

Мне pqxx когда-то понравился, что он С++ и работал просто реактивно, по примерам разобрался как работает. Опять же lazy_connection.

Мне казалось, что pgpool и иже — это штуки, ставящиеся возле сервера БД (между сервером и многими клиентами) и не решающие проблем, решаемых в статье (дорогое установление соединения от клиента к удалённому серверу).


В общем, мне кажется, лучше всегда иметь собственный пул соединений в приложении.

Да, лучше — но Вы не можете учесть все ситуации и Вам придется потратить время на разработку и отладку модуля объединения сессий.

Сразу говорю я не программер, админ

На первый взгляд:
— надо объединять в пул не все сессии, а какое-то количество, по превышении порога открывать второй коннекшин
— надо иметь механизм мониторинга коннектов, нужна какая-то статистика подключений
— надо выставлять лимит в количество подключений — обязательно, иначе постгрес можно легко уложить какой-нибудь один лок

Это все есть в пгбаунсере и еще много чего другого
В C# npgsql всё это есть, жаль, что реализации для С++ нет, в pqxx, например, надо самому делать. Был вариант для версии 2009 года.

— надо объединять в пул не все сессии, а какое-то количество, по превышении порога открывать второй коннекшин
Не обязательно, если помнишь, что все действия нужно выполнить в одном логическом блоке. Для какого-нибудь RESTful сервиса будет прекрасно работать.

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

Тем более пгбаунсер очень нетяжелая штука, если у него еще конфиги были не в виндовозных .ini-файлах, а в привычных .conf-ах — вообще бы было чудесно
да много чего можно сделать — просто стоит ли на это тратить время, если есть готовый продукт. Вы же не писали библиотеку обращения к постгресу — а взяли готовую, почему не взять готовое приложение.
Да потому, что на уровне приложения он не сработает. В многопоточном приложении необходимы раздельные объекты connection и pgBouncer здесь не поможет. Он может разве, что оптимизировать количество процессов postgres — физических подключений. Только libpq об этом ничего знать не будет.
Так с приложением можно делать чего угодно — пгбаунсер работает полностью для него прозрачно, хоть 500 коннекшинов от одного клиента, ему то какая разница. Если написать полностью аналогичный функционал для Вашего пула — то и это позволит уменьшить количество процессов постгреса. Другой вопрос зачем делать пгбаунсер с порезаным функционалом и потом его поддерживать.
Ну вот не понимаю зачем изобретать велосипед
Если pgbouncer будет управлять пулом коннектов, а многопоточное приложение к нему подключается к примеру «одним соединением», то мы просто переносим проблему на один уровень выше — потоки в приложении будут ждать, пока один из них отправит данные pgbouncer-у и отдаст соединение. Т.е. придётся создавать такой же пул коннектов к pgbouncer. Предполагаю, что там эта возможность есть, но для моих задач подход описанный в статье оказался достаточным и весьма эффективным.
Это радует, но чем меньше у клиента происходит процессов — тем проще их контролировать.
Потому, что для libpq и pqxx его не изобрели. Напиши многопоточное высоконагруженное приложение на C++ и поймёшь зачем :)

Во всех наших проектах мы стараемся делать как можно проще и обычно одно приложение ходит в базу под одним и тем же пользователем, так что все подключения в пуле по факту одинаковые. И когда какой-то поток хочет поработать с базой, он просит в пуле любой свободный коннект или ждёт до 5 секунд, пока таковой освободится, делает, что ему надо с базой и возвращает соединение в пул. Количество соединений в пуле ограничивается эмпирически (в зависимости от того, сколько в процентах времени в среднем код проводит, работая с базой, а сколько — с чем-то другим), но в простых случаях просто ставится равным количеству потоков.

Хотелось минимизировать зависимости, чтобы всё было в комплекте «из коробки».
Вот как раз установка пгбаунсера и уменьшает количество проблем, как минимум из-за того, что он себя ведет для всех клиентов одинаково, потому что установлен на сервере, а не на клиенте. Да и его наличие для клиентов полностью прозрачно.
Еще нужно быть внимательным к выдаче сессий из пула. В любом инициализированном соединении будут временные таблицы, prepared query, переменные типа search_path и т.д.
Для этого (и для безопасности) pgBouncer создает пулы per user.
Ну для идеала можно было бы объединить оба подхода: одним pgBouncer в данном случае не обойдёшься. Но сохранение сессии не всегда нужно, а вернее редко.

Выложите, пожалуйста, код на GitHub / BitBucket / GitLab.com — гораздо проще и смотреть и компилировать.

Sign up to leave a comment.

Articles