记两次不同场景下遭遇的MySQL原数据锁

目录
  1. 问题描述
  2. 场景一
  3. 场景二
  4. 建议

问题描述

环境:MySQL 5.7,一主两从,pt-online-schema-change改表

MDL 全称为 metadata lock,即元数据锁,一般也可称为字典锁。MDL 的主要作用是为了管理数据库对象的并发访问和确保元数据一致性。元数据锁适用对象包含:table、schema、procedures, functions, triggers, scheduled events、tablespaces

场景一

一年前,晚上11点多开始执行,6千万级别的两个表,相差几分钟开始进行字段变更。

看着主库变更完毕,就去睡觉了,但其中一个从库,执行到第二天上班还没完成。

上班的时候发现其中一个从库延迟了,直接将请求杀掉,从新执行变更,恢复正常。

之前从来没碰到过原数据锁的情况,一直比较信任pt-online-schema-change,表变更比较随意。两表同时变更,数据库压力大了,凌晨0点的时候,一堆查询走了从库,其中不乏一些慢查询,查show processlist,一堆Waiting for table metadata lock,出原数据锁,卡住了。

后来严格串行执行表变更,大表变更尽量挑低峰期执行,再也没碰到过原数据锁的问题。

​ 

场景二

前两天,执行一个300W大小的表的字段增长语句,主库锁了。

杀掉后,show processlist 没看到什么慢查询。

从来,又连续锁了两次。

看来是代码有问题。

show processlist 查到该表有八百多个sleep,应该是改表的时候慢查询问题暴露出来了。

类似这样的语句:select * from aaa where gmt_created> xxxx order by id desc limit 5

优化方案:可以改成 order by gmt_created 防止file_sort

查询频次每秒十几次,也不是太高,正常不应该不容易这么高概率造成原数据锁死才对。

这是自动抢单的查询语句,前端没半秒轮询一次。

怀疑问题出在这。

问了前端,前端是通过setInterval的方式定期轮询的,这在服务端接口慢的情况下,会导致压力放大。

让做下调整,改成setTimeout,计时从上次响应结束开始计算。

数据库正常的情况下,抢单效率是一样的。

但接口平均耗时达到10秒的异常情况下,假设有10个审核员在线,并发请求将会由原先的200,降到10。

这里导致原数据锁的最大的原因,其实是setInterval。

建议

总体改善思路是:优化sql性能,降低查询频次,低峰执行大表变更