Які недоліки використання стійкого з'єднання в PDO


181

У PDO з'єднання може бути стійким за допомогою PDO::ATTR_PERSISTENTатрибута. Відповідно до посібника з php -

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

Посібник також рекомендує не використовувати стійке з'єднання під час використання драйвера PDO ODBC, оскільки це може перешкоджати процесу об'єднання з'єднання ODBC.

Тому, мабуть, не існує недоліків використання стійкого з'єднання в PDO, за винятком останнього випадку. Однак я хотів би знати, чи є інші недоліки використання цього механізму, тобто ситуація, коли цей механізм призводить до погіршення продуктивності чи чогось подібного.


Нічого, ви заплатили 1000 репутаційних грошей за це просте запитання?
Pacerier

Відповіді:


287

Будь ласка, не забудьте прочитати цю відповідь нижче , де детально описано способи пом'якшення проблем, викладених тут.


Такі ж недоліки існують і в PDO, як і в будь-якому іншому інтерфейсі баз даних PHP, який підтримує стійкі з'єднання: якщо ваш скрипт несподівано припиниться посеред операцій з базою даних, наступний запит, який отримує з'єднання, що залишився, підбере там, де залишився мертвий сценарій. З'єднання утримується відкритим на рівні менеджера процесів (Apache для mod_php, поточний процес FastCGI, якщо ви використовуєте FastCGI тощо), а не на рівні PHP, і PHP не повідомляє батьківському процесу відпускати з'єднання вмирати, коли сценарій закінчується аномально.

Якщо таблиці з мертвим сценарієм заблоковані, ці таблиці залишаться заблокованими, поки з'єднання не вмирає або наступний сценарій, який отримує з'єднання, розблокує самі таблиці.

Якщо сценарій мертвого опинився в середині транзакції, він може блокувати безліч таблиць, поки не вступить таймер тупикового блоку, і навіть тоді таймер тупикового блоку може вбити новіший запит замість старого запиту, що викликає проблему.

Якщо мертвий сценарій опинився в середині транзакції, наступний сценарій, який отримує це з'єднання, також отримує стан транзакції. Дуже можливо (залежно від дизайну програми) наступний сценарій насправді ніколи не намагатиметься здійснити існуючу транзакцію, або здійснить, коли її не повинно бути, або відкотити назад, коли її не повинно бути.

Це лише верхівка айсберга. Це все може бути пом’якшене, якщо завжди намагатися очистити після брудного з'єднання з кожного запиту сценарію, але це може бути болем залежно від бази даних. Якщо ви не визначили створення підключень до бази даних як єдине, що є вузьким місцем у вашому сценарії (це означає, що ви зробили профілювання коду за допомогою xdebug та / або xhprof ), ви не повинні розглядати стійкі з'єднання як рішення чогось.

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


Для уточнення моменту ми використовуємо стійкі зв’язки на моєму робочому місці, але не за вибором. Ми стикалися з дивною поведінкою підключення, де початкове підключення від нашого сервера додатків до нашого сервера баз даних займало рівно три секунди, коли це повинно було зайняти частку частки секунди. Ми думаємо, що це помилка ядра. Ми відмовилися від її усунення, оскільки це сталося випадковим чином і неможливо було відтворити на вимогу, а наші аутсорсингові ІТ не мали конкретної можливості відстежити це.

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

Ця приказка має сенс: вона порушила речі, які ми ніколи не розраховували порушити, все в ім'я виконання. Компроміс не вартував цього, і ми з нетерпінням чекаємо того дня, коли ми зможемо перейти до нормальних з’єднань без нападів наших користувачів.


2
Я сподіваюся, що я прочитав цю відповідь перед тим, як бігтиSELECT orders.* FROM orders LEFT JOIN items USING(item_id)
Аст Дерек

31
Я знаю великий веб-сайт, який використовує стійкі зв’язки вже майже десять років. Трюк полягає у використанні шару над розширенням БД, а також його запам'ятовування речей, які потрібно очистити за допомогою register_shutdown_function(). Якщо процес вмирає, з'єднання також вмирає. Якщо цього не відбувається, з'єднання повертається до чистого стану (наприклад, відкриті транзакції повертаються назад). Якщо це не вдалося, з'єднання буде закрито, і наступним запитом до того ж процесу буде відкрито нове. Не потрібно демонізувати стійкі зв’язки.
Вальтер Трос

Мені цікаво @Charles ... чи вирішувались Ваші питання?
Цалалака

@MichaelDibbets Кілька місяців тому ми замінили сервер додатків і повернули pconnect, щоб перевірити, чи три третій помилки все ще є. Це не було. Я думаю, це було вирішено проксі. Відповідь нижче щодо mysqli_change_userцього, мабуть, є найкращим вирішенням для людей, які мають підтримувати стійкі зв’язки у додатку, не призначеному для вирішення державних проблем.
Чарльз

5
У нас була 5-секундна затримка підключення, яку нам вдалося виділити як проблему DNS + IPv6. Сервер шукав адресу v6, не працював, а потім використовував адресу IPv4.
Найджел Аткінсон

45

У відповідь на проблему Чарльза вище,

Від: http://www.php.net/manual/en/mysqli.quickstart.connections.php -

Поширена скарга на стійкі зв’язки полягає в тому, що їх стан не скидається до повторного використання. Наприклад, відкриті та незавершені транзакції не повертаються автоматично. Але також зміни авторизації, що відбулися в період між введенням з'єднання в пул і його повторним використанням, не відображаються. Це може розглядатися як небажаний побічний ефект. Навпаки, ім’я, що є стійким, можна розуміти як обіцянку збереження держави.

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

mysqli_change_user()Функція є дорогою операцією. Для кращої продуктивності користувачі можуть захотіти перекомпілювати розширення із встановленим прапором компіляції MYSQLI_NO_CHANGE_USER_ON_PCONNECT.

Користувачеві залишається вибрати між безпечною поведінкою та найкращою продуктивністю. Обидва є дійсними цілями оптимізації. Для зручності використання безпечна поведінка була зроблена за замовчуванням за рахунок максимальної продуктивності.


+1, якби не той факт, що ми очистили безлад іншими способами, я хотів би побачити, чи виправляв би вручну заміну change_user виправлені наші химерні проблеми з невідомою державою.
Чарльз

Що еквівалентно стійким з'єднанням PDO Postgres? У мене є подібні проблеми, як-от @Charles, де через деякий час користувачі отримуватимуть помилки, як-от fetch sql - сервер несподівано закрив з'єднання. Це, ймовірно, означає, що сервер припиняється аномально, коли виконується простий SELECT-запит (навіть не транзакції).
Carmageddon

1
@Carmageddon, це більше підходить для нового запитання, але tl; dr - це те, що Postgres не робить pconnect і вам слід використовувати один із зовнішніх пулів підключення.
Чарльз

@Charles, що ти розумієш під цим? використання постійного з'єднання PDO не еквівалентно використанню "зовнішніх пулів підключення"? чи що ви мали на увазі?
Кармагедон

@Carmageddon, я маю на увазі те, що спільнота Postgres влаштувалася на об'єднання з'єднань як краще рішення, ніж pconnect. Ознайомтеся з pgbouncer або pgpool-II. Я не впевнений, що PDO так чи інакше підключиться Postgres, але я, можливо, зовсім не мою рокер.
Чарльз

13

Стійкі з'єднання - це гарна ідея лише тоді, коли потрібен (відносно) тривалий час для підключення до вашої бази даних. Сьогодні це майже ніколи не буває. Найбільшим недоліком стійких з'єднань є те, що він обмежує кількість користувачів, які можуть переглядати ваш сайт: якщо MySQL налаштований дозволяти відразу 10 одночасних підключень, то тоді, коли 11-а людина намагається переглядати ваш сайт, він не буде працювати для них .

PDO не керує наполегливістю. Драйвер MySQL робить. Він повторно використовує з'єднання, коли: a) вони доступні і хост / користувач / пароль / база даних збігаються. Якщо будь-яка зміна, то з'єднання не буде використане повторно. Найкращий чистий ефект полягає в тому, що ці з'єднання, які у вас є, будуть запускатися та припинятися так часто, тому що у вас є різні користувачі на сайті, і зробити їх стійкими не приносить користі.

Ключове, що потрібно розуміти про стійкі з'єднання, це те, що НЕ слід використовувати їх у більшості веб-додатків. Вони звучать привабливо, але вони небезпечні і майже марні.

Я впевнений, що в цьому питанні є інші теми, але стійке з'єднання небезпечно, оскільки воно зберігається між запитами. Наприклад, якщо ви заблокуєте таблицю під час запиту, а потім не вдаєтеся розблокувати, ця таблиця залишатиметься заблокованою на невизначений термін. Постійні з’єднання також дуже корисні для 99% ваших додатків, оскільки ви не можете знати, чи буде використовуватися одне і те ж з'єднання між різними запитами. Кожна веб-нитка матиме власний набір стійких з'єднань, і ви не можете контролювати, який потік буде обробляти, які запити.

Процедурна бібліотека mysql PHP має особливість, згідно з якою наступні виклики до mysql_connect повернуть те саме посилання, а не відкриють інше з'єднання (як можна було очікувати). Це не має нічого спільного з стійкими зв’язками і є специфічним для бібліотеки mysql. PDO не проявляє такої поведінки


Посилання на ресурс: посилання

Загалом, ви можете використовувати це як грубо "набір правил" ::

ТАК , використовуйте стійкі з'єднання, якщо:

  • Є лише кілька додатків / користувачів, які мають доступ до бази даних, тобто ви не матимете 200 відкритих (але, ймовірно, непрацюючих) з'єднань, оскільки на одному хості є 200 різних користувачів.
  • База даних працює на іншому сервері, до якого ви отримуєте доступ через мережу

  • (Одна) програма дуже часто звертається до бази даних

НІ , не використовуйте стійкі з'єднання, якщо:

  • Вашій програмі потрібно отримати доступ до бази даних лише 100 разів на годину.

  • У вас є багато, багато веб-серверів, які мають доступ до одного сервера баз даних

Використання стійких з'єднань значно швидше, особливо якщо ви отримуєте доступ до бази даних по мережі. Це не має великої різниці, якщо база даних працює на одній машині, але це все-таки трохи швидше. Однак - як говорить назва - з'єднання стійке, тобто воно залишається відкритим, навіть якщо воно не використовується.

Проблема в тому, що в "конфігурації за замовчуванням" MySQL дозволяє лише 1000 паралельних "відкритих каналів". Після цього нові з'єднання відмовляються (Ви можете налаштувати цю настройку). Тож якщо у вас, скажімо, - 20 веб-серверів із кожними 100 клієнтами на них, і кожен з них має лише один доступ до сторінки на годину, проста математика покаже вам, що вам потрібно 2000 паралельних підключень до бази даних. Це не спрацює.

Ergo: Використовуйте його лише для програм із великою кількістю запитів.


4
Після рядка ваша відповідь - копіювати пасту з stackoverflow.com/a/51583/718224
Тоні Старк

1
"ТАК, використовуйте стійкі з'єднання, якщо: [...] Є лише кілька додатків / користувачів, які отримують доступ до бази даних" суперечить "Використовувати його лише для додатків з великою кількістю запитів." Останнє, однак, правильно. Ситуація: тисячі запитів в секунду призведуть до сотень активних підключень до бази даних. Коли система масштабується лінійно, вона також буде лінійно масштабувати кількість підключень до бази даних. Таким чином, більше запитів (більше користувачів) призведе до більше з'єднань. Тож вам потрібно обмежено (!), Але багато активних зв’язків, коли у вас багато запитів (користувачів)
Ken Van Hoeylandt

12

На моїх тестах у мене був час підключення до секунди до мого локального господаря, таким чином, припускаючи, що я повинен використовувати стійкий зв’язок. Подальші тести показали, що це проблема з "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));

Здається, PDO має труднощі з перекладом доменних імен! Дякую, мені було цікаво, чому на моїй чотирьохядерній машині кожне з'єднання тривало чорт!
Мустафа

@Gunnar Bernstein +1 приємна знахідка. "localhost", безумовно, займає більше часу, і це дещо покращило швидкість мого веб-програми (це робить безліч з'єднань).
imperium2335

1
Це чудово. Щось не так з роздільною здатністю на моїй машині розвитку ... за допомогою IP-адреси взяли мій сценарій з 6.1s до 1.1s
Піт

localhostвикористовує роз'єм підключення, гніздо підключення знаменито до неуспіху на великій кількості з'єднань
Мент

@mente Будь-яка посилання, ресурс, який може довести цей факт? Я схиляюсь до думки, що UDS віддають перевагу над TCP. Дякую.
Nuxwin

6

Стійкі з'єднання мають підвищити продуктивність. Я не згоден із твердженням, що слід "уникати" наполегливості.

Схоже, наріканнями зверху керує хтось, хто використовує таблиці MyIASM і хакує власні версії транзакцій, захоплюючи столові блоки. Ну, звичайно, ви йдете в тупик! Скористайтеся PDO startTransaction () та перенесіть таблиці на InnoDB ..


2
Я розумію, що на рік пізніше, але для запису: моя розповідь походить із бази даних, що складається повністю з таблиць InnoDB, за винятком кількох денормалізованих клонів, застряглих у трясовині MyISAM для підтримки повнотекстової індексації.
Карл

Pfft, Сфінкс старий і розпалений , ElasticSearch - нова гарячість. Одного прекрасного дня ми фактично використовуватимемо його для своїх старих додатків, а не лише для нових ...
Чарльз

Повний текст пошуку в PostgreSQL - справжній переможець. Це дивовижно. Не потрібен інший інструмент / сервер, що працює, щоб виконувати свою роботу. Не потрібно турбуватися про збереження синхронізації даних. Дуже зернисті елементи управління. Кілька словників або написати свій власний. А оскільки PostgreSQL автоматично використовує багатоіндексні запити, ви можете просто залишити його будь-яким іншим запущеним запитом.
яскравий бал

2
MySQL 5.6 пропонує повну текстову підтримку таблиць InnoDB.
час

2

мені здається, що постійний зв'язок з'їсть більше системних ресурсів. Можливо, банальна сума, але все ж ...


Часто торгівля великою кількістю людського часу за мікросекунди комп'ютерного часу
Енді Чейз

1

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

Найперша проблема зі стійкими зв’язками ...

Якщо ви створюєте 1000 підключень в секунду, ви зазвичай не гарантуєте, що вони залишаються відкритими дуже довго, але Операційна система робить. На основі протоколу TCP / IP порти неможливо миттєво переробити, а також доведеться вкласти час у стадії “FIN”, чекаючи, перш ніж вони можуть бути перероблені.

2-я проблема ... використання багатьох підключень сервера MySQL.

Багато людей просто не усвідомлюють, що ви в змозі збільшити змінну * max_connections * та отримати понад 100 одночасних з'єднань з MySQL, інші були побитими старими проблемами Linux, неможливими передати більше 1024 з'єднань з MySQL.

Дозволяє зараз поговорити про те, чому стійкі з’єднання були відключені в розширенні mysqli. Незважаючи на те, що ви можете зловживати стійкими з'єднаннями та отримувати низьку продуктивність, що не було головною причиною. Справжня причина - ви можете отримати набагато більше проблем з цим.

Постійні з'єднання вводилися в PHP протягом усіх випадків роботи MySQL 3.22 / 3.23, коли MySQL не був таким складним, що означає, що ви можете легко переробляти з'єднання без проблем. У пізніших версіях, однак, виникло кількість проблем - Якщо ви переробляєте з’єднання, яке має невдалі транзакції, ви потрапляєте у проблеми. Якщо ви переробляєте з'єднання за допомогою спеціальних конфігурацій набору символів, вам знову загрожує небезпека, а також можливі перетворення змінних за сеанс.

Одна проблема при використанні стійких з'єднань - це насправді не так масштабно. Для тих, у кого підключено 5000 людей, вам знадобиться 5000 постійних з'єднань. Якщо ви не вимагаєте наполегливості, ви можете мати можливість обслуговувати 10000 людей із подібною кількістю з'єднань, оскільки вони можуть спільно використовувати спільні зв’язки, коли вони не з ними.


0

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.