Каковы недостатки использования постоянного соединения в PDO

В PDO соединение может быть выполнено постоянно, используя атрибут PDO::ATTR_PERSISTENT. Согласно руководству php -

Стойкие соединения не закрываются в конце script, но кэшируются и повторно используются, когда другой script запрашивает соединение, используя те же учетные данные. Постоянный кеш подключений позволяет избегайте накладных расходов при установлении нового соединения каждый раз, когда script необходимо поговорить с базой данных, что приведет к ускорению работы в Интернете приложение.

В руководстве также рекомендуется не использовать постоянное соединение при использовании драйвера PDO ODBC, поскольку это может помешать процессу объединения соединений ODBC.

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

Ответ 1

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


Те же недостатки существуют с использованием PDO, как и с любым другим интерфейсом базы данных PHP, который выполняет постоянные соединения: если ваш script неожиданно заканчивается в середине операций с базой данных, следующий запрос, который получает соединение слева, будет подниматься там, где мертвые script прекращено. Соединение открыто на уровне диспетчера процессов (Apache для mod_php, текущий процесс FastCGI, если вы используете FastCGI и т.д.), А не на уровне PHP, а PHP не сообщает родительскому процессу, чтобы соединение замирало, когда script заканчивается ненормально.

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

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

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

Это только верхушка айсберга. Все это можно смягчить, пытаясь очистить после грязного соединения каждый запрос script, но это может быть болью в зависимости от базы данных. Если вы не определили создание соединений с базой данных как одну вещь, которая является узким местом в вашем script (это означает, что вы выполнили профилирование кода с помощью xdebug и/или xhprof), вы не должны рассматривать постоянные соединения как решение чего-либо.

Кроме того, большинство современных баз данных (включая PostgreSQL) имеют свои собственные предпочтительные способы выполнения пула соединений, которые не имеют непосредственных недостатков, которые делают простые постоянные соединения на основе ванильных PHP.


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

Независимо от того, когда люди на складе обрабатывают несколько сотен входящих частей, и каждая часть занимает три с половиной секунды вместо половины секунды, мы должны были принять меры, прежде чем они похитили всех нас и помогли им, Таким образом, мы перевернули несколько бит в нашем самодельном оригинале ERP/CRM/CMS и испытали все ужасы постоянных соединений из первых рук. Нам потребовались недели, чтобы отследить все тонкие небольшие проблемы и причудливое поведение, которое казалось случайным образом. Оказалось, что эти раз в неделю фатальные ошибки, которые наши пользователи усердно выдавливали из нашего приложения, оставляли заблокированные столы, оставленные транзакции и другие неудачные неуклюжие состояния.

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

Ответ 2

В ответ на проблему Чарльза выше,

От: http://www.php.net/manual/en/mysqli.quickstart.connections.php -

Обычные жалобы на постоянные подключения заключаются в том, что их состояние не является reset перед повторным использованием. Например, открытые и незавершенные транзакции автоматически не откатываются. Но также, изменения авторизации, которые произошли во время между подключением в пул и повторным использованием, не отражаются. Это можно рассматривать как нежелательный побочный эффект. Напротив, имя постоянное может пониматься как обещание, что государство сохраняется.

Расширение mysqli поддерживает как интерпретации постоянного соединения: состояние сохраняется, так и состояние reset перед повторным использованием. По умолчанию используется reset. Перед повторным использованием постоянного соединения расширение mysqli неявно вызывает mysqli_change_user() to reset состояние. Постоянное соединение появляется пользователю так, как будто оно только что открыто. Нет видимых артефактов предыдущих применений.

Функция mysqli_change_user() является дорогостоящей операцией. Для лучшей производительности пользователи могут захотеть перекомпилировать расширение с установленным флагом компиляции MYSQLI_NO_CHANGE_USER_ON_PCONNECT.

Пользователю предоставляется возможность выбора между безопасным поведением и максимальной производительностью. Оба являются действительными целями оптимизации. Для удобства использования безопасное поведение было сделано по умолчанию за счет максимальной производительности.

Ответ 3

В моих тестах у меня было время подключения более секунды к моему локальному хосту, поэтому, предполагая, что я должен использовать постоянное соединение. Дальнейшие тесты показали, что это проблема с "localhost":

Результаты тестов в секундах (измеренные микропрограммой php):

  • веб-сайт: connectDB: 0.0038912296295166
  • localhost: connectDB: 1.0214691162109 (более одной секунды: не используйте localhost!)
  • 127.0.0.1: connectDB: 0.00097203254699707

Интересно: следующий код работает так же быстро, как 127.0.0.1:

$host = gethostbyname('localhost');
// echo "<p>$host</p>";
$db = new PDO("mysql:host=$host;dbname=" . DATABASE . ';charset=utf8', $username, $password,
    array(PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Ответ 4

Стойкие соединения - хорошая идея только тогда, когда требуется (относительно) долгое время для подключения к вашей базе данных. В наши дни это почти никогда не бывает. Самый большой недостаток постоянных подключений заключается в том, что он ограничивает количество пользователей, которых вы можете просматривать на своем сайте: если MySQL настроен на одновременное использование только 10 одновременных подключений, то когда 11-й человек пытается просмотреть ваш сайт, он не будет работать для них.

PDO не справляется с сохранением. Драйвер MySQL делает это. Он повторно использует соединения, когда они доступны, и совпадение между хостом/пользователем/паролем/базой данных. Если какое-либо изменение, то оно не будет повторно использовать соединение. Лучший сетевой эффект - это то, что эти соединения, которые у вас есть, будут запущены и остановлены так часто, потому что у вас есть разные пользователи на сайте и их постоянство не приносит пользы.

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

Я уверен, что в этом есть другие потоки, но постоянное соединение опасно, потому что оно сохраняется между запросами. Если, например, вы блокируете таблицу во время запроса и затем не можете разблокировать, тогда эта таблица будет оставаться заблокированной на неопределенный срок. Стойкие соединения также практически бесполезны для 99% ваших приложений, потому что у вас нет способа узнать, будет ли одно и то же соединение использоваться между различными запросами. Каждый веб-поток будет иметь собственный набор постоянных соединений, и у вас нет способа контролировать, какой поток будет обрабатывать какие запросы.

В процедурной библиотеке mysql PHP есть функция, при которой последующие вызовы mysql_connect возвращают ту же ссылку, а не открывают другое соединение (как и следовало ожидать). Это не имеет ничего общего с постоянными подключениями и специфично для библиотеки mysql. PDO не проявляет такого поведения.


Ссылка ресурса: ссылка

В целом вы можете использовать это как грубый "набор правил"::

ДА, используйте постоянные соединения, если:

  • Доступ к базе данных осуществляется только несколькими приложениями/пользователями. вы не получите 200 открытых (но, возможно, незанятых) соединений, потому что на одном и том же хосте имеется несколько разных пользователей.
  • База данных работает на другом сервере, к которому вы обращаетесь сеть

  • Приложение (одно) очень часто обращается к базе данных

НЕТ, не используйте постоянные соединения, если:

  • Вашему приложению требуется только доступ к базе данных 100 раз в час.

  • У вас много, многие веб-серверы, обращающиеся к одному серверу базы данных

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

Проблема заключается в том, что в "конфигурации по умолчанию" MySQL допускает только 1000 параллельных "открытых каналов". После этого новые соединения будут отклонены (вы можете настроить эту настройку). Поэтому, если у вас есть - скажем, 20 веб-серверов с каждым 100 Клиентами на них, и каждый из них имеет только один доступ к странице в час, простая математика покажет вам, что вам потребуется 2000 параллельных подключений к базе данных. Это не сработает.

Ergo: используйте его только для приложений с большим количеством запросов.

Ответ 5

Постоянное подключение должно дать значительное повышение производительности. Я не согласен с тем, что вы должны "избегать" настойчивости.

Похоже, что жалобы, приведенные выше, управляются кем-то, использующим таблицы MyIASM, и взламывают их собственные версии транзакций, захватывая блокировки таблиц.. Ну, конечно, вы зашли в тупик! Используйте PDO beginTransaction() и переместите ваши таблицы в InnoDB..

Ответ 6

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

Ответ 7

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

Самая первая проблема с постоянными соединениями...

Если вы создаете 1000 подключений в секунду, вы обычно не гарантируете, что он остается открытым в течение очень долгого времени, но работает система операций. На основе протокола TCP/IP порты не могут быть переработаны мгновенно и также должны инвестировать некоторое время в стадию "FIN", прежде чем они могут быть переработаны.

Вторая проблема... использование большого количества серверных соединений MySQL.

Многие люди просто не понимают, что вы можете увеличить * max_connections * переменную и получить более 100 параллельных соединений с MySQL, другие были избиты более старыми проблемами Linux из-за невозможности передать более 1024 подключений к MySQL.

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

Постоянные соединения были помещены в PHP на протяжении всего времени MySQL 3.22/3.23, когда MySQL не был таким сложным, что означает, что вы можете легко перерабатывать соединения без проблем. В более поздних версиях возникло множество проблем. Если вы переработаете соединение, в котором есть незавершенные транзакции, вы попадаете в неприятности. Если вы повторно подключаете соединения с настраиваемыми настройками набора символов, вы снова окажетесь в опасности, а также о возможно преобразованных переменных сеанса.

Одна проблема с использованием постоянных подключений - это не очень хорошо масштабируется. Для тех, кто подключен к 5000 человек, вам понадобятся 5000 постоянных подключений. Чтобы избежать необходимости сохранения, вы можете иметь возможность обслуживать 10000 человек с одинаковым количеством соединений, потому что они могут обмениваться личными связями, когда они не с ними.

Ответ 8

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