E_WARNING: Ошибка при отправке пакета STMT_PREPARE.PID = * - PullRequest
0 голосов
/ 25 ноября 2018

По состоянию на 2019-01-30 14:52 UTC вы все равно можете выиграть 500-балльную награду, потому что ни один из ответов не помог!

На моем веб-сайте Laravel 5.7 возникло несколько проблем, с которыми я столкнулся.думаю, связаны друг с другом (но происходят в разное время):

  1. PDO::prepare(): MySQL server has gone away
  2. E_WARNING: Error while sending STMT_PREPARE packet. PID=10
  3. PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry (Моя база данных часто кажетсяпопробуйте написать одну и ту же запись дважды в одну и ту же секунду. Мне не удалось понять, почему или как ее воспроизвести; похоже, она не связана с поведением пользователя.)
  4. Каким-то образом эти первые2 типа ошибок только когда-либо появляются в моих журналах Rollbar, но не в текстовых журналах на сервере или в моих уведомлениях Slack, как предполагается, все ошибки (и все другие делают).

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

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


Я пытался изменить свою конфигурацию MySQL, чтобы использовать max_allowed_packet=300M (вместо по умолчанию из 4M), но все же часто получаю эти исключения в те дни, когда у меня более пары посетителей на мой сайт.

Я также установил (изменено с 5M и 10M) следующее из-за этого совета :

innodb_buffer_pool_chunk_size=218M
innodb_buffer_pool_size = 218M

В качестве дополнительной справочной информации:

  • На моем сайте есть работник очереди, который выполняет задания (artisan queue:work --sleep=3 --tries=3 --daemon).
  • Существует множество заданий в очереди, которые могут быть запланированы на одно и то же время в зависимости от времени регистрации посетителей.Но самое большее, что я вижу, происходит одновременно: 20.
  • В журнале медленных запросов MySQL нет записей.
  • У меня есть несколько заданий cron, но я сомневаюсь, что они проблематичны.Один работает каждую минуту, но это действительно просто.Другой запускается каждые 5 минут для отправки определенных запланированных электронных писем, если они ожидаются.А другой запускается каждые 30 минут для запуска отчета.
  • Я выполнил различные mysqlslap запросы (хотя я совершенно новичок) и не нашел ничего медленного даже при моделировании сотен одновременно работающих клиентов.
  • Я использую Laradock (Docker).
  • Мой сервер - DigitalOcean 1 ГБ ОЗУ, 1 vCPU, 25 ГБ SSD.Я также попробовал 2 ГБ ОЗУ без разницы.
  • Результаты от SHOW VARIABLES; и SHOW GLOBAL STATUS; здесь .

Мой my.cnf есть:

[mysql]

[mysqld]
sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
character-set-server=utf8
innodb_buffer_pool_chunk_size=218M
innodb_buffer_pool_size = 218M
max_allowed_packet=300M
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow_query_log.log
long_query_time = 10
log_queries_not_using_indexes = 0

Есть идеи о том, что мне следует изучить, чтобы диагностировать и исправить эти проблемы?Спасибо.


Ответы [ 3 ]

0 голосов
/ 26 января 2019

Re Slowlog: Покажите нам свой my.cnf.Были ли изменения в разделе [mysqld]?Протестируйте его с помощью SELECT SLEEP(12);, а затем просмотрите файл и таблицу.

Альтернативный способ найти запрос: поскольку запрос занимает несколько минут, выполните SHOW FULL PROCESSLIST;, если считаете, что он выполняется.

Сколько у вас оперативной памяти?У нет max_allowed_packet=300M, если у вас не менее 30 ГБ ОЗУ.В противном случае вы рискуете обменом (или даже крахом).Оставьте этот параметр ниже 1% ОЗУ.

Для дальнейшего анализа настроек укажите, пожалуйста, (1) размер ОЗУ, (2) SHOW VARIABLES; и (3) SHOW GLOBAL STATUS;.

Redeleted_at: Ссылка, которую вы дали, начинается с "Колонка удален_ не является подходящим индексным кандидатом".Вы неверно истолковали это.Речь идет об одной колонке INDEX(deleted_at).Я предлагаю составной индекс, такой как INDEX(contact_id, job_class_name, execute_at, deleted_at).

158 секунд для простого запроса на небольшую таблицу?Может случиться так, что происходит много других вещей.Получите PROCESSLIST.

Re Отдельные индексы и составные: представьте себе два индекса: INDEX(last_name) и INDEX(first_name).Вы пролистываете индекс last_name, чтобы найти «Джеймса», тогда что вы можете сделать?Пролистав другой индекс «Рик», вы не найдете меня.

Анализ переменных и глобальное состояние

Наблюдения:

  • Версия: 5.7.22-log
  • 1,00 ГБ ОЗУ
  • Время работы = 16d 10: 30: 19
  • Вы уверены, что это былоa ПОКАЗАТЬ ГЛОБАЛЬНОЕ СОСТОЯНИЕ?
  • Вы не работаете в Windows.
  • Работает в 64-битной версии
  • Вы, кажется, работаете полностью (или в основном) с InnoDB.

Более важные проблемы:

innodb_buffer_pool_size - я думал, что у вас это было в 213M, а не 10M.10М это слишком мало.С другой стороны, кажется, что у вас меньше данных.

Поскольку оперативной памяти очень мало, я рекомендую сбросить tmp_table_size и max_heap_table_size и max_allowed_packet до 8M.И более низкие table_open_cache, table_definition_cache и innodb_open_files до 500.

Что вызывает так много одновременных соединений?

Подробности и другие наблюдения:

( innodb_buffer_pool_size / _ram ) = 10M / 1024M = 0.98%-% оперативной памяти, используемой для InnoDB buffer_pool

( innodb_buffer_pool_size ) = 10M - InnoDB Data + Index cache

( innodb_lru_scan_depth ) = 1,024 - «InnoDB: page_cleaner: 1000 мсек, цикл, который должен был выполняться ...» можетбыть исправлено путем понижения lru_scan_depth

( Innodb_buffer_pool_pages_free / Innodb_buffer_pool_pages_total ) = 375 / 638 = 58.8% - Pct для buffer_pool в настоящее время не используется - innodb_buffer_pool_size больше необходимого?

( Innodb_buffer_pool_bytes_data / innodb_buffer_pool_size ) = 4M / 10M = 40.0% - Процент пула буферов, занятого данными- Небольшой процент может означать, что buffer_pool неоправданно велик.

( innodb_log_buffer_size / _ram ) = 16M / 1024M = 1.6% - Процент ОЗУ, используемый для буферизации записей журнала InnoDB.- Слишком большой отнимает от другого использования для оперативной памяти.

( innodb_log_file_size * innodb_log_files_in_group / innodb_buffer_pool_size ) = 48M * 2 / 10M = 960.0% - Отношение размера журнала к размеру buffer_pool.Рекомендуется 50%, но посмотрите другие расчеты, если это имеет значение.- Журнал не должен быть больше, чем пул буферов.

( innodb_flush_method ) = innodb_flush_method = - Как InnoDB должен запрашивать у ОС запись блоков.Предложите O_DIRECT или O_ALL_DIRECT (Percona), чтобы избежать двойной буферизации.(По крайней мере, для Unix.) См. Chrischandler для предостережения о O_ALL_DIRECT

( innodb_flush_neighbors ) = 1 - Незначительная оптимизация при записи блоков на диск.- Используйте 0 для SSD накопителей;1 для жесткого диска.

( innodb_io_capacity ) = 200 - число операций ввода-вывода в секунду на диске.100 для медленных дисков;200 для прядильных дисков;1000-2000 для твердотельных накопителей;умножить на коэффициент RAID.

( innodb_print_all_deadlocks ) = innodb_print_all_deadlocks = OFF - регистрировать ли все тупики.- Если вы страдаете от тупиков, включите это.Внимание: если у вас много взаимоблокировок, это может привести к записи большого количества данных на диск.

( min( tmp_table_size, max_heap_table_size ) / _ram ) = min( 16M, 16M ) / 1024M = 1.6% - процент оперативной памяти, выделяемой при необходимости таблицы MEMORY (для каждой таблицы), или временной таблицы внутри SELECT (длявременная таблица для некоторых SELECTs).Слишком высокая может привести к обмену.- Уменьшите tmp_table_size и max_heap_table_size, скажем, до 1% от оперативной памяти.

( net_buffer_length / max_allowed_packet ) = 16,384 / 16M = 0.10%

( local_infile ) = local_infile = ON - local_infile = ON - потенциальная проблема безопасности

( Select_scan / Com_select ) = 111,324 / 264144 = 42.1% -% выборок, выполняющих полное сканирование таблицы.(Может быть одурачен хранимыми процедурами.) - Добавить индексы / оптимизировать запросы

( long_query_time ) = 10 - Обрезание (секунды) для определения «медленного» запроса.- Предложить 2

( Max_used_connections / max_connections ) = 152 / 151 = 100.7% - Пиковый% соединений - увеличить max_connections и / или уменьшить wait_timeout

У вас есть полупериод кеша запросов.Вы должны установить и query_cache_type = OFF, и query_cache_size = 0.Существует (согласно слухам) «ошибка» в коде QC, которая оставляет некоторый код включенным, если вы не отключите обе эти настройки.

Аномально маленький:

( Innodb_pages_read + Innodb_pages_written ) / Uptime = 0.186
Created_tmp_files = 0.015 /HR
Handler_write = 0.21 /sec
Innodb_buffer_pool_bytes_data = 3 /sec
Innodb_buffer_pool_pages_data = 256
Innodb_buffer_pool_pages_total = 638
Key_reads+Key_writes + Innodb_pages_read+Innodb_pages_written+Innodb_dblwr_writes+Innodb_buffer_pool_pages_flushed = 0.25 /sec
Table_locks_immediate = 2.8 /HR
Table_open_cache_hits = 0.44 /sec
innodb_buffer_pool_chunk_size = 5MB

Аномально большой:

Com_create_db = 0.41 /HR
Com_drop_db = 0.41 /HR
Connection_errors_peer_address = 2
Performance_schema_file_instances_lost = 9
Ssl_default_timeout = 500

Аномальные строки:

ft_boolean_syntax = + -><()~*:&
have_ssl = YES
have_symlink = DISABLED
innodb_fast_shutdown = 1
optimizer_trace = enabled=off,one_line=off
optimizer_trace_features = greedy_search=on, range_optimizer=on, dynamic_range=on, repeated_subselect=on
session_track_system_variables = time_zone, autocommit, character_set_client, character_set_results, character_set_connection
slave_rows_search_algorithms = TABLE_SCAN,INDEX_SCAN
0 голосов
/ 02 апреля 2019

Я сталкивался с такой же ситуацией в длительном скрипте PHP CLI (он прослушивает список Redis; каждое действие выполняется быстро, но скрипт в основном выполняется вечно).

Я создаю объект PDO ивначале подготовил оператор, а затем повторно использовал их.

На следующий день после запуска сценария я получил те же самые ошибки:

PHP Warning:  Error while sending STMT_EXECUTE packet. PID=9438 in /...redacted.../myscript.php on line 39

SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

В моем случае это сервер разработки,нагрузка отсутствует, MySQL находится на том же компьютере ... так что вряд ли это будет связано с внешними факторами.Скорее всего, это связано с тем, что я использовал одно и то же соединение MySQL слишком долго, и время ожидания истекло.И PDO не беспокоит, поэтому любой последующий запрос просто вернет «Сервер MySQL ушел».

Проверка значения «wait_timeout» в MySQL:

mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.06 sec)

mysql> show local variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

Я вижу 28800секунд = 8 часов, что, по-видимому, согласуется со временем моих ошибок.

В моем случае перезапуск сервера MySQL или установка очень низкого значения wait_timeout при сохранении работоспособности того же самого PHP-оператора делает его очень простым для воспроизведенияпроблема.

В целом:

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

Чтобы вернуться к вашему делу

  • теоретически Laravel 5 невосприимчив к этой проблеме: https://blog.armen.im/en/laravel-4-and-stmt_prepare-error/;Вы используете что-то кроме Illuminate, или даже голый PDO напрямую?Кроме того, я не уверен, что делает Laravel, когда он обнаруживает потерянное соединение (он повторно соединяет и перестраивает подготовленные операторы?), Возможно, стоит покопаться дальше.
  • проверьте значение MySQL wait_timeout и увеличьте его, еслионо слишком низкое
  • , если это происходит не постоянно, посмотрите, не связаны ли ошибки с нагрузкой на сервер / БД.Высокая нагрузка может сделать вещи (особенно большие запросы SQL) в несколько раз медленнее, до некоторого другого тайм-аута MySQL, такого как max_execution_time, достигаемого.
  • посмотрим, обернули ли вы запросы PDO в блок try / catch и использовали его для повторной попыткизапрос;это может препятствовать возникновению ошибки подключения.
0 голосов
/ 10 декабря 2018

Если вы видите это сообщение случайным образом, возможны причины:

  1. Ваш MySQL находится за прокси-сервером, и они используют различные настройки timeout.

  2. Вы используете постоянное соединение PHP.

Вы можете попытаться разобраться в проблеме, выполнив следующие действия:

  1. Убедитесь, что ваши соединения с MySQL имеют достаточно длительный тайм-аут (например, настройка прокси, MySQL's wait_timeout / interactive_timeout)

  2. Отключите постоянное соединение на стороне PHP.

  3. Сделайте tcpdump, если сможете увидеть, что произошло, когда вы получили сообщение об ошибке.

...