用 mysqldump | mysql 在同一个 mysql server 中复制数据库有时会出现死锁, show processlist会看到mysql命令的connection在执行第一个drop function的sql, 但状态是waiting for table lock, mysqldump命令卡在sleep状态, 没在执行什么操作, 查看information_scheme.INNODB_LOCKS又是空的.
先mysqldump 到文件, 再用mysql命令执行文件就不会出现这样的死锁.
原因
shell的管道缓冲区(pipe buffer)容量是有限的, 当缓冲区满的时候, mysqldump 命令会阻塞在标准输出流上, 同时mysqldump 命令还占用了某些表的锁(不是目标库里表, 可能information_scheme里的表?), 而mysql命令也需要获取此锁才能继续执行sql, 为缓冲区腾出空间, 于是死锁就发生了.
参考:MySQL Bugs: #77774: deadlock or something when piping mysqldump | mysql
解决方法
只要缓冲区容量是有限的, 这种死锁就可能发生, 虽然不能从根本上解决问题, 但还是可以通过调大缓冲区解决我们当前的需求.
1 用 ulimit -p N 修改系统管道缓冲区大小, 但缓冲区上限可能受系统限制, 且修改了之后影响范围是整个系统, 不推荐
2 用 mbuffer 命令提供一个可调整的缓冲区, 用法大概是这样 :
mysqldump | mbuffer -m 2G | mysql