я использую 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
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. Переключитесь сейчас и получите реальный контроль над отключениями и повторными подключениями.
Самая распространенная причина того, что MySQL-сервер исчез из-за ошибки, заключается в том, что сервер отключил время и закрыл соединение.
Попробуйте сделать следующее изменение.
max_allowed_packet=64M
Если у вас много запросов, установите это и не устанавливайте больше, потому что это связано с вашей средой.
max_connections=1000
Добавление этой строки в my.cnf
файл может решить вашу проблему. Перезапустите службу MySQL, как только вы закончите с изменением.
Читать дальше на Сервер MySQL ушел
Если это не работает, попробуйте этот функция автоматического переподключения.
Как уже говорилось, сценарии MySQL в PHP истекают, когда между ними в течение некоторого времени нет связи.
Это хорошо, так как простаивающие соединения пожирают ресурсы вашего сервера.
Ошибка «Сервер ушел» чаще всего возникает, когда между двумя запросами происходит относительно длительное вычисление.
Чтобы предотвратить это, вы можете
SELECT 1
запрос во время исполненияТем не менее, я считаю, что перенастройка MySQL для поддержания открытого соединения на более длительный период поощряет небрежное программирование и дает советы против этого.
Это также может быть размер запроса, так как иногда ORM объединяют запросы для повышения производительности.
Попробуйте установить max_allowed_packet = 128M, по крайней мере, это может быть полезно для диагностики.
Если ваша БД не обрабатывает несколько одновременных соединений и запросов, вы можете установить «бесконечные» тайм-ауты. Это существенно не повлияет на ресурсы БД. Наилучшим подходом является отправка пакетов ping (SELECT 1), чтобы возобновить тайм-аут и поддерживать соединение в активном состоянии.
Чтобы решить такую проблему, я предлагаю вам:
Вот как.
Запустите приложение веб-сокета как демон, как вы уже сделали (возможно, с помощью 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
Надеюсь, это поможет!