PHP activerecord MySQL сервер ушел

я использую PHP-ActiveRecord на короткое время, и я очень люблю это. Php-activerecord — это ORM-библиотека с открытым исходным кодом, основанная на Шаблон ActiveRecord. Тем не менее, я недавно пытался использовать его в сочетании с приложением веб-сокета на основе Гаечный ключ.

Это прекрасно работает, но для запуска скрипта приложение должно запускаться в Linux как демон, чтобы веб-сокеты всегда были доступны. Через некоторое время, когда приложение не используется, а затем снова пытается его использовать, оно выдает некоторые исключения из базы данных:

Сначала это дает предупреждение:

PHP Warning: Error while sending QUERY packet. PID=XXXXX in /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Connection.php on line 322

Тогда это приводит к фатальной ошибке:

PHP Fatal error: Uncaught exception 'ActiveRecord\DatabaseException' with message 'exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2006 MySQL server has gone away' in /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Connection.php:322

Трассировки стека:

#0 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Connection.php(322): PDOStatement->execute(Array)

#1 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Table.php(218): ActiveRecord\Connection->query('SELECT * FROM ...', Array)

#2 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Table.php(209): ActiveRecord\Table->find_by_sql('SELECT * FROM `...', Array, false, NULL)

#3 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Model.php(1567): ActiveRecord\Table->find(Array)

#4 in /home/user/domains/example.com/public_html/vendor/php-activerecord/lib/Connection.php on line 325

Похоже, что php-activerecord поддерживает подключение mysql все время, пока работает сервер веб-сокетов, это конечно не должно быть проблемой, если затем он автоматически попытается переподключиться и снова выполнить запрос. Но это не так.

Я читал кое-что о настройке MYSQL_OPT_RECONNECT, Но я не уверен, что это работает или как установить эту опцию, используя php-activerecord. У кого-нибудь здесь есть опыт в этой области?

Изменить: Вот мои глобальные переменные конфигурации тайм-аута

VARIABLE_NAME                   VARIABLE_VALUE
DELAYED_INSERT_TIMEOUT          300
WAIT_TIMEOUT                    28800
CONNECT_TIMEOUT                 10
LOCK_WAIT_TIMEOUT               31536000
INNODB_ROLLBACK_ON_TIMEOUT      OFF
THREAD_POOL_IDLE_TIMEOUT        60
NET_WRITE_TIMEOUT               60
INNODB_LOCK_WAIT_TIMEOUT        50
INTERACTIVE_TIMEOUT             28800
DEADLOCK_TIMEOUT_LONG           50000000
SLAVE_NET_TIMEOUT               3600
DEADLOCK_TIMEOUT_SHORT          10000
NET_READ_TIMEOUT                30

12

Решение

PHP ActiveRecord использует PDO. Нет абсолютно никакого способа закрыть соединение PDO, это неправильный уровень БД для длительных фоновых задач.

Вы можете попробовать влияние разъединение соединения PDO с помощью следующего фрагмента.

//if not using ZF2 libraries, disconnect in some other way
$db->getDriver()->getConnection()->disconnect()
$db = NULL;
gc_collect_cycles();

Отключите, установите вашу ссылку на ноль, затем запустите сборщик мусора. Надеюсь, что это вызовет внутренний метод __destruct PDO, чтобы фактически закрыть соединение.

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

Реальное решение состоит в том, чтобы не использовать PDO, а также отключать и повторно подключать нормально.

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

РЕДАКТИРОВАТЬ: У меня действительно была именно эта проблема и использовал это точное решение на работе в прошлом году. Это решило 99% моих проблем. Но все же время от времени возникало случайное исключение соединения, которое я не мог поймать и попытаться восстановить. Я просто перезапускаю процессы один раз в день, чтобы избавиться от этих случайных ошибок подключения. Вот почему мой ответ: не используйте PDO. Переключитесь сейчас и получите реальный контроль над отключениями и повторными подключениями.

5

Другие решения

Самая распространенная причина того, что MySQL-сервер исчез из-за ошибки, заключается в том, что сервер отключил время и закрыл соединение.

Попробуйте сделать следующее изменение.

max_allowed_packet=64M

Если у вас много запросов, установите это и не устанавливайте больше, потому что это связано с вашей средой.

max_connections=1000

Добавление этой строки в my.cnf файл может решить вашу проблему. Перезапустите службу MySQL, как только вы закончите с изменением.

Читать дальше на Сервер MySQL ушел

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

1

Как уже говорилось, сценарии MySQL в PHP истекают, когда между ними в течение некоторого времени нет связи.
Это хорошо, так как простаивающие соединения пожирают ресурсы вашего сервера.

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

Чтобы предотвратить это, вы можете

  • Периодически выполнять SELECT 1 запрос во время исполнения
  • Создайте оболочку вокруг ваших запросов, которая проверяет правильность соединения перед выполнением
  • Используйте ответ от эта почта

Тем не менее, я считаю, что перенастройка MySQL для поддержания открытого соединения на более длительный период поощряет небрежное программирование и дает советы против этого.

1

Это также может быть размер запроса, так как иногда ORM объединяют запросы для повышения производительности.

Попробуйте установить max_allowed_packet = 128M, по крайней мере, это может быть полезно для диагностики.

1

Если ваша БД не обрабатывает несколько одновременных соединений и запросов, вы можете установить «бесконечные» тайм-ауты. Это существенно не повлияет на ресурсы БД. Наилучшим подходом является отправка пакетов ping (SELECT 1), чтобы возобновить тайм-аут и поддерживать соединение в активном состоянии.

1

Чтобы решить такую ​​проблему, я предлагаю вам:

  1. Распределите ваши процессы с помощью сервера заданий Gearman (http://gearman.org/)
  2. Управляйте этими процессами легко, используя Supervisor (http://supervisord.org/)

Вот как.

Запустите приложение веб-сокета как демон, как вы уже сделали (возможно, с помощью cron). Или, что еще лучше, управляйте им с помощью Supervisor. Настройте его так, чтобы Supervisor запускал его при запуске Supervisor и автоматически перезапускал демона, если он умирает.

Пример конфигурации:

[program:my-daemon]
command=/usr/bin/php /path/to/your/daemon/script
autostart=true
autorestart=true

Затем, вместо запуска обработки запросов внутри демона приложения, создайте Gearman Worker для его обработки. После регистрации работник будет ждать запуска / вызова. Вы должны вызвать Worker из приложения websocket вместе с необходимым параметром рабочей нагрузки, если необходимо (см. Объяснение термина рабочей нагрузки на веб-сайте Gearman).

В Worker установите его для остановки / выхода, когда он уже завершит работу, запрошенную демоном. При этом у вас не возникнет «проблема с сервером mysql», потому что соединение немедленно закрывается.

Наконец, мы должны сделать Worker доступным постоянно, как демон. Итак, аналогично демону, настройте Supervisor на автоматический запуск и автоматический перезапуск, когда Worker умирает / останавливается, вот так:

[program:my-worker]
command=/usr/bin/php /path/to/your/worker/script
autostart=true
autorestart=true

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

numprocs=9 #change it to any number
process_name=%(program_name)s_%(process_num)02d #to identity worker number

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

Вот еще одно объяснение этой стратегии: http://www.masnun.com/2011/11/02/gearman-php-and-supervisor-processing-background-jobs-with-sanity.html

Надеюсь, это поможет!

0
По вопросам рекламы [email protected]