MySQL三行记录的表更新还会有性能问题?
思想是气体,交流是液体,文字是固体。
项目背景
A服务的Task调用B服务的dubbo API接口发放活动券。B作为活动券的接收方,要做每日接收数量限制,整场活动接收数量的限制。我作为B项目的开发者,JAVA语言。
问题现象
A服务的同学反馈接收券的pqs才30接口很慢,RT达到400多ms,偶尔超时。
问题查找
1、我先得确定到底是不是我这里的问题,通过内部工具查找,得出确实现象如同反馈的那样。
2、分析接收券接口的代码,首先我怀疑调用第三方项目C的接口慢了,去内部工具查询,发现C项目接口RT正常。
3、我怀疑B项目中操作MySQL的语句慢了。结果发现确实有个sql执行平均耗时400ms左右。伪SQL如下:
UPDATE 接收限制表 SET 今日接收 = 今日接收 + 1, 总接收 = 总接收 + 1 where 今日接收 < 每日接收上限 and 总接收 < 总接收上限 and 活动=活动1;
问题分析
业务逻辑里根据SQL结果返回是否为1判断是否更新成功,继而决定是否可以接收券。其中‘活动=活动1’决定了每次接收券都是更新这一行。目前只做过几次活动,从而整张表只有3行记录。因为MySQL更新时会对该行加锁,每次更新该行都必须等前一次更新完毕释放锁才能加锁,就算单次更新需10多ms,30次也得400ms左右。
问题解决
解决方案1:本次活动其实没有实际的接收券数量限制,“每日接收上限 ”和“总接收上限”是一个实际上不可能达到的很大的值,所以最快速的方法是暂时去掉限制的代码,快速修复上线。不过不太优雅,得去说服技术leader和产品。
解决方案2:用Redis去实现该限制逻辑。incrby方法更新"今日接收"值,然后判断更新后的返回值是否大于“每日接收上限”,“总接收”接收限制的逻辑同理。同时满足这两个条件后才可以接收券。
后记:排查问题时发现“内部工具”很好用,极大提高了排查问题的效率,也减少了自己实现这些工具的时间,值得自己去继续深入学习,了解它的原理和实现。通常查找接口慢问题的方向:
1)网络慢?那么所有接口都会慢;
2)很大的for循环;
3)锁的使用不当;
4)调用第三方接口慢;
5)MySQL慢