2010-07-26 3 views
153

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

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

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

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

+0

Ничего себе, вы заплатили 1000 баллов за этот простой вопрос? – Pacerier

+0

@Pacerier, [нет, это был кто-то еще] (http://meta.stackexchange.com/q/175402/135887). – Charles

ответ

248

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


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

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

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

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

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

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


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

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

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

+4

Добавлен анекдот, чтобы проехать по дому. Наслаждайтесь! – Charles

+1

Надеюсь, что я прочитал этот ответ, прежде чем запускать 'SELECT orders. * FROM orders LEFT JOIN items USING (item_id)' –

+28

Я знаю большой веб-сайт, который использует постоянные подключения уже почти десять лет. Трюк использует слой над расширением DB, и он помнит вещи, которые необходимо очистить, используя 'register_shutdown_function()'. Если процесс умирает, соединение также умирает. Если это не так, соединение сбрасывается в чистое состояние (например, откат открытых транзакций). Если это не удается, соединение закрывается, и новый запрос будет открыт следующим запросом к тому же процессу. Нет необходимости демонизировать постоянные соединения. –

2

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

+0

IT всегда является торговым o фон ресурсом для другого ... – DGM

+0

Часто торговля большим количеством человеческих времен для микросекунд компьютерного времени – andychase

6

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

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

+2

Через год я понимаю, но для записи: моя история исходит из базы данных, состоящей из * полностью * таблиц InnoDB, за исключением лишь нескольких денормализованных клонов, застрявших в болоте MyISAM для поддержки полнотекстового индексирования. – Charles

+0

Sphinx полнотекстовый поиск - это победа .... – Stephen

+0

Pfft, Sphinx старый и разоренный, [ElasticSearch] (http://www.elasticsearch.org/) - новая жара. В один прекрасный день мы фактически будем использовать его для наших старых приложений, а не только для новых ... – Charles

38

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

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

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

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

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

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

+0

+1, если бы не тот факт, что мы очистили путаницу другими способами, я бы с удовольствием посмотрел, будет ли [ручное вызов change_user] (http://php.net/mysqli.change-user) исправили наши странные проблемы с неизвестным государством. – Charles

+0

Что такое эквивалент для постоянных соединений PDO Postgres? У меня есть аналогичные проблемы, такие как @Charles, где через некоторое время пользователи получат ошибку, например, выборка sql-server неожиданно закрыл соединение. Это, вероятно, означает, что сервер завершил ненормально При запуске простого запроса SELECT (даже транзакции). – Carmageddon

+1

@Carmageddon, это больше подходит для нового вопроса, но tl; dr - это то, что Postgres не выполняет pconnect, и вместо этого вы должны использовать один из внешних пулов соединений. – Charles

1

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

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

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

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

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

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

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

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

9

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

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

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

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

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


ресурсов Ссылка: link

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

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

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

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

NO, не используйте стойкие если:

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

  • У вас есть много, много веб-серверов с доступом одного сервера базы данных

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

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

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

+3

После строки ваш ответ будет скопирован с http://stackoverflow.com/a/51583/718224 –

+0

@AdvaitAmin добавил ссылку ресурса для этого. –

+1

«ДА, используйте постоянные соединения, если: [...] Есть только несколько приложений/пользователей, обращающихся к базе данных » противоречит« Использовать только для приложений с большим количеством запросов ». Последнее, однако, верно. Ситуация: тысячи запросов в секунду приведут к сотням активных соединений с базой данных. Когда система масштабируется линейно, она также линейно масштабирует количество подключений к базе данных. Таким образом, больше запросов (больше пользователей) приведет к большему количеству подключений. Таким образом, вы * нуждаетесь * ограничены (!), Но многие активные соединения, когда у вас много запросов (пользователей) –

11

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

Результатов тестирования в секундах (измеренное с помощью 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)); 
+0

Похоже, что PDO испытывает трудности при переводе доменных имен! Спасибо, мне было интересно, почему каждое соединение длится долго на моей четырехъядерной машине! – Mustafa

+0

@ Gunnar Bernstein +1 хорошая находка. «localhost», конечно, занимает больше времени, и это немного улучшило скорость моего веб-приложения (он делает много соединений). – imperium2335

+1

Это замечательно. Что-то не так с разрешением на моей машине разработки ... с использованием IP взял мой скрипт от 6.1s до 1.1s – Pete

0

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