首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >E_WARNING:发送STMT_PREPARE数据包时出错。PID=*

E_WARNING:发送STMT_PREPARE数据包时出错。PID=*
EN

Stack Overflow用户
提问于 2018-11-25 17:02:53
回答 4查看 3.1K关注 0票数 12

我的Laravel5.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 (而不是400万的默认设置 ),但是当我有超过几个访问者访问我的站点的时候,仍然经常会遇到这些异常。

我还设置了(从5M到10M),因为这个建议

代码语言:javascript
运行
复制
innodb_buffer_pool_chunk_size=218M
innodb_buffer_pool_size = 218M

作为进一步的背景:

  • 我的站点有一个运行作业(artisan queue:work --sleep=3 --tries=3 --daemon)的队列工作者。
  • 根据访问者的注册时间,可以在同一时间安排一组排队的作业。但我所看到的最多的同时发生的是20。
  • MySQL慢速查询日志中没有条目。
  • 我有几份工作,但我怀疑它们是有问题的。每分钟跑一次,但很简单。另一个每5分钟运行一次,发送某些预定的电子邮件(如果有的话)。另一个每30分钟运行一次报告。
  • 我运行过各种mysqlslap查询(不过,我完全是新手),甚至在模拟数百个并发客户端时,我也没有发现任何慢的地方。
  • 我用的是拉拉多克(码头)。
  • 我的服务器是DigitalOcean 1GB内存,1 vCPU,25 1GB。我也尝试过2GB内存,没有差别。
  • SHOW VARIABLES;SHOW GLOBAL STATUS; 在这里的结果。

我的my.cnf是:

代码语言:javascript
运行
复制
[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

对于我应该探索什么来诊断和解决这些问题有什么想法吗?谢谢。

EN

回答 4

Stack Overflow用户

发布于 2019-01-26 01:40:02

Re Slowlog:向我们展示您的my.cnf。是[mysqld]部分的变化吗?通过SELECT SLEEP(12);测试它,然后查看文件和表。

找到查询的另一种方法:由于查询需要几分钟时间,所以当您认为它可能正在运行时,请执行SHOW FULL PROCESSLIST;

你有多少内存?除非您有至少30 at的内存,否则不要使用max_allowed_packet=300M。否则你就冒着交换的危险(甚至是崩溃)。将该设置保持在RAM的1%以下。

为进一步分析可调性,请提供(1)内存大小,(2) SHOW VARIABLES;和(3) SHOW GLOBAL STATUS;

Re deleted_at:您给出的链接以“列deleted_at不是很好的索引候选”开始。你曲解了。它指的是单列INDEX(deleted_at)。我建议采用像INDEX(contact_id, job_class_name, execute_at, deleted_at)这样的综合指数。

158秒用于对一个小表进行简单查询?可能还有很多其他的事情在发生。去拿PROCESSLIST

重新分离索引和复合索引:考虑两个索引:INDEX(last_name)INDEX(first_name)。你翻阅last_name索引找到“詹姆斯”,然后你能做什么呢?翻阅“瑞克”的另一个索引不会帮你找到我。

变量的分析与全局状态

Observations:

  • 版本:5.7.22-日志
  • 1.00GB内存
  • 正常运行时间= 16d 10:30:19
  • 你确定这是一场全球演出吗?
  • 您不在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数据+索引缓存

( 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% --目前还没有使用的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.)关于O_ALL_DIRECT的警告见chrischandler

( innodb_flush_neighbors ) = 1 --将块写入磁盘时的次要优化。- SSD驱动器使用0;HDD使用1。

( innodb_io_capacity ) = 200 --每秒可以在磁盘上执行I/O操作。100用于慢速驱动器;200用于旋转驱动器;1000-2000用于SSD;乘以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% --在需要内存表(每个表)时分配内存的百分比,或者在SELECT中分配临时表的百分比(每个临时表按某些选择)。过高可能导致交换。--把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代码中有一个'bug‘,除非你关闭这两个设置,否则会留下一些代码。

异常小的:

代码语言:javascript
运行
复制
( 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

异常大的:

代码语言:javascript
运行
复制
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

异常字符串:

代码语言:javascript
运行
复制
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
票数 5
EN

Stack Overflow用户

发布于 2019-04-02 08:05:21

我在一个长期运行的PHP脚本上遇到了同样的情况(它在Redis列表上侦听;每个动作都是快速的,但脚本基本上永远运行)。

我在开始时创建PDO对象和一个准备好的语句,然后再使用它们。

在我开始脚本的第二天,我得到了完全相同的错误:

代码语言:javascript
运行
复制
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”的值:

代码语言:javascript
运行
复制
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查询周围放置了try/catch,脚本就不会崩溃,并且会继续使用过时的PDO实例。
  • STMT_EXECUTE警告可能是附带的;仅仅因为连接超时的脚本使用准备好的语句,而第一个查询后超时恰好使用了准备好的语句。

回到你的案子

  • 从理论上讲,Laravel 5不受这个问题的影响:准备-错误/;您使用的不是照明,甚至是直接使用光的PDO吗?另外,我不确定Laravel在检测到丢失的连接时会做什么(它是否重新连接和重建准备好的语句?),它可能值得进一步挖掘。
  • 检查您的MySQL wait_timeout值,如果它太低,就增加它
  • 如果它不是一直都在发生,那么看看这些错误是否与服务器/ DB负载相关。高负载可以使事情(特别是大型SQL查询)慢几倍,到了达到其他一些MySQL超时(比如max_execution_time )的程度。
  • 查看是否将PDO查询包装在try / catch块中,并使用它重试查询;这可能会防止连接错误冒泡。
票数 2
EN

Stack Overflow用户

发布于 2018-12-10 06:09:16

如果您随机看到此消息,可能的原因如下:

  1. 您的MySQL位于代理后面,它们使用不同的timeout配置。
  2. 您正在使用PHP的持久化连接。

您可以尝试通过以下步骤深入研究这个问题:

  1. 确保与MySQL的连接有足够长的超时时间(例如:代理设置、MySQL的wait_timeout / interactive_timeout)
  2. 禁用PHP端的持久化连接。
  3. 如果可以的话,可以执行一些tcpdump来查看当您收到错误消息时发生了什么。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53469793

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档