用客户端导一个200兆的SQL文件,跑到一半断了,报ERROR 2006 (HY000): MySQL server has gone away。换成命令行mysql导入,同样的文件能过,看起来跟客户端有关。同一个文件两种结果,说明限制不在文件本身。
服务端有个上限,叫max_allowed_packet,限制单条SQL或者单个数据包的大小。5.7的默认值是4兆,8.0改成了64兆,两个版本差别很大。导库时报的错不一定是这个,但4兆这个值在带长文本、序列化字段的表上很容易撞到。查当前值用SHOW VARIABLES LIKE 'max_allowed_packet',单位是字节。这个上限管的是单个包,不是整个文件,大文件会切成很多包发过去,卡住的是其中某一条特别长的INSERT。一条INSERT里塞几万行的情况最典型,mysqldump默认就是这种写法,扩展插入一次拼很多行,包体很容易超。加上--skip-extended-insert能拆成单行插入,速度慢一些,但不会撞上限。
包超过上限、连接还能维持的,报Packet too large;连接被服务端直接断掉的,客户端看到的是server has gone away,错误号2006。后者更容易被误判成网络问题,其实日志里能看到对应的aborted connection。aborted connection那行带客户端地址,能对上哪台机器在导数据。
客户端也有上限,mysql命令行的默认值通常比服务端大,所以同一个文件在命令行能过、在程序里报错。程序用的驱动一般有自己的参数,JDBC是maxAllowedPacket,PHP的PDO要看驱动版本。两边取较小的那个生效。驱动的版本也会影响默认值,升级过依赖的要重新确认一次。
你要是改,就在my.cnf的mysqld段加一行max_allowed_packet=64M,重启生效。不想重启的可以SET GLOBAL max_allowed_packet=67108864,只对之后新建的连接有效。已经连着的还是旧值,长连接的应用改完得让应用重连。重启窗口自己挑,别在业务高峰做,出问题还能回滚。
主从环境里从库也要改。主库收下的大事务写进relay log,从库应用时同样受这个上限约束,SQL线程报Got a packet bigger than max_allowed_packet,同步停在那里。改完主库顺手把从库一起改掉,别等同步断了才发现。从库的报错不会传到主库,主库看着一切正常,实际上同步早就停了。
这个值不是越大越好,缓冲区按需增长,单条连接碰到大包时会一次涨到上限。1000条连接同时顶上去,内存账很吓人,遇到异常流量会把内存吃穿。按连接数乘上限估个最坏值,超过物理内存就别设。
真要传大对象,把二进制内容放对象存储,库里只存路径,比调大上限省事,也避免单条SQL长时间占着连接。拆分之后单条SQL的包体小,回滚也快。导出的时候也一样,mysqldump有对应的参数,别只改服务端。
A5创业网 版权所有