最近发现一个在线问题,一个表DDL 添加一个字段,添加字段完成后,php程序异常报错,具体错误信息如下: Packets out of order. Expected 1 received 13. Packet size=5 `后面所有数据都为线下模拟数据。` 表结构如下: CREATE TABLE `sbtest1` ( `id` int(10) unsigned NOT NULL, `k` int(10) unsigned NOT NULL DEFAULT '0', `c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '', `pad` char(60) COLLATE utf8mb4_bin NOT NULL DEFAULT '', `d` varchar(500) COLLATE utf8mb4_bin NOT NULL DEFAULT 'a', PRIMARY KEY (`id`), KEY `idx_d` (`d`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin 报错一段时间后就恢复了,异常期间有上线操作:添加了字段。并在proxysql的日志中也能看到异常日志: 2020-05-20 15:59:41 MySQL_Session.cpp:2887:handler(): [ERROR] Detected a broken connection during query on (1,10.200.131.4,3306) , FD (Conn:43 , MyDS:43) : 2057, The number of parameters in bound buffers differs from number of columns in resultset 2020-05-20 15:59:43 MySQL_PreparedStatement.cpp:315:update_metadata(): [WARNING] Updating metadata for stmt 1 , user sbtest_rw, query SELECT * FROM sbtest1 WHERE id =? 2020-05-20 15:59:43 MySQL_Session.cpp:2452:handler(): [ERROR] RECEIVED AN UNKNOWN COMMAND: 28 -- PLEASE REPORT A BUG 初步整理信息: * 异常时间点对sbtest1做了ddl,增加了一个字段。SQL为`alter table sbtest1 add column daa varchar(2) not null default 'd' after k;` * php执行SQL采用的是预处理 * proxysql提示有明显报错,有可能是proxysql的bug * php使用的pdo访问MySQL 如下是问题复现过程: * 首先,确认的是不是proxysql的bug,在issue中并没有找到具体信息,虽然也有人提过issue。于是尝试复现。 通过proxysql执行如下SQL: sbtest_rw 15:13: [sbtest]> PREPARE stmt1 FROM 'select * from sbtest1 where id=?'; Query OK, 0 rows affected (0.02 sec) Statement prepared sbtest_rw 15:13: [sbtest]> set @a=30; Query OK, 0 rows affected (0.02 sec) sbtest_rw 15:13: [sbtest]> EXECUTE stmt1 USING @a; 另一个session同步修改表结构:`alter table sbtest1 add column daa varchar(2) not null default 'd' after k;` 再执行时并没有异常: sbtest_rw 15:13: [sbtest]> EXECUTE stmt1 USING @a; 通过直接在proxysql手动执行prepare,无法复现,表示可能不是proxysql的问题。还有一种可能是pdo的版本bug。 继续复现,准备php以及pdo环境。并编写如下脚本: $ cat prepare.php <?php $dsn = 'mysql:dbname=sbtest;host=10.200.131.3;port=6033'; $user = 'sbtest_rw'; $password = 'sbtest_rw_123'; //链接数据库 try { $params = [ PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8", //设置编码 PDO::ATTR_EMULATE_PREPARES => false, //使用预处理 ]; $db = new PDO($dsn, $user, $password, $params); } catch (PDOException $e) { echo $e->getMessage(); exit; } //查询多条数据 $sth = $db->prepare('SELECT * FROM sbtest1 WHERE id =?'); $sth->execute([28]); $res1 = $sth->fetchAll(PDO::FETCH_ASSOC); //有多种方式可以设置返回的值 print_r($res1); ?> 这次果然完整复现了问题,如下是复现步骤: 1、先执行脚本:`php prepare.php` Array ( [0] => Array ( [id] => 28 [k] => 4971 [daa] => d [da] => d [dc] => d [ddd] => d [dd] => dd [d] => d [a] => a [c] => 40783119738-56118100649-59405854784-01609403334-31427251764-63910168355- 67527844925-29768547496-01835772584-19294175703 [pad] => 24254594429-63006752771-86115602773-26630920715-27676864358 [b] => b [dk] => d ) ) 2、执行加字段 alter table sbtest1 add column daa varchar(2) not null default 'd' after k; 3、再执行`php prepare.php` PHP Warning: PDOStatement::execute(): MySQL server has gone away in /data/dbadir/20200520/prepare.php on line 21 PHP Warning: PDOStatement::execute(): Error reading result set's header in /data/dbadir/20200520/prepare.php on line 21 Array ( ) 4、继续执行`php prepare.php ` PHP Warning: Packets out of order. Expected 1 received 13. Packet size=5 in /data/dbadir/20200520/prepare.php on line 22 Array ( ) 后面继续执行就恢复正常了 复现了问题了就好了,说明是通过pdo才能出现,很明显,这里pdo的`ATTR_EMULATE_PREPARES`配置默认设置成了`false`。改成true后,测试如上步骤就没有报错了。 到这里可以得出,由于pdo的预处理关闭了,导致proxysql处理这种情况时会异常。 总结+扩展测试结论:(如下测试都是在有增加字段的情况下) * ATTR_EMULATE_PREPARES为false,通过proxysql请求`异常`(在proxysql中提了个issue确认下这个场景的问题,https://github.com/sysown/proxysql/issues/2812) * ATTR_EMULATE_PREPARES为true,通过proxysql请求`正常` * ATTR_EMULATE_PREPARES为false/true直连MySQL`正常` * select * 改为指定列,通过proxysql访问测试正常(ATTR_EMULATE_PREPARES为true和false都`正常`) 后续优化: * 避免使用select *,程序中需要什么列必须明确出来。 * pdo的ATTR_EMULATE_PREPARES配置设置为true(需要测试,在网上有人提到查询结果会把整型转成字符串) 补充: * PDO::ATTR_EMULATE_PREPARES 启用或禁用预处理语句的模拟。 有些驱动不支持或有限度地支持本地预处理。使用此设置强制PDO总是模拟预处理语句(如果为 TRUE ),或试着使用本地预处理语句(如果为 FALSE)
文章最后更新时间: 2020年05月20日 17:07:39
分类文章统计
Django(5)
Flask(1)
Python常见错误(3)
Python基础(10)
linux排障(4)
虚拟化(1)
Consul(3)
Linux基础(5)
shell(11)
oracle(10)
MySQL(64)
ProxySQL(7)
SequoiaDB(2)
TiDB(4)
Redis(2)
常用软件(2)
硬件排障(2)
HTML(1)
JavaScript(1)
我们的作品(18)
windows(1)
总结(1)
按年文章统计
2013(43)
2014(19)
2015(25)
2016(6)
2017(30)
2018(7)
2019(17)
2020(4)
2021(4)
2023(1)
2024(2)
老版入口
亲,扫我吧!
友情链接
飞哥的:imbusy.me/
冰川的:www.mindg.cn
海洋的:hiaero.net
宏斌的:techindeep.com
若水的:nosa.me
段郎的:sixther.me
肥客联邦:fk68.net