Каковы недостатки использования постоянных соединений в PDO - PullRequest
169 голосов
/ 26 июля 2010

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

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

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

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

Ответы [ 8 ]

273 голосов
/ 26 июля 2010

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


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

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

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

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

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

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


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

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

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

42 голосов
/ 12 июля 2012

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

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

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

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

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

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

12 голосов
/ 26 апреля 2013

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

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

  • веб-хостинг: 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));
12 голосов
/ 04 апреля 2013

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

6 голосов
/ 04 апреля 2011

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

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

2 голосов
/ 26 июля 2010

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

1 голос
/ 03 апреля 2013

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

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

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

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

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

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

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

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

0 голосов
/ 03 июля 2014

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...