添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

事情起因于一次生产的错误日志,日志的主要内容是sql执行超时, update product set num = num -1 where id=xx 这是一条根据索引更新商品表数据的sql语句,商品表product有1千多万数据,设置的数据库连接的读取超时时间是3秒,一般情况下,按照主键更新记录只需要10ms,那为什么会导致update超时呢?

首先排除了偶尔的网络问题,因为我们发现这个根据主键更新记录超时的日志经常出现凌晨2点左右,而且经过最近5天的观察,其他时间段并没有这个超时错误日志,而且运维反馈这段时间内并没有网络的问题。
在排除了网络问题后,想到了是否是Mysql数据库负载的问题,查看数据库cpu使用率才10%,再次排除是数据库负载高的问题,答案开始变得迷茫起来
再经过前面几步的排除后,我们又重新回到了 update product set num = num -1 where id=xx 这个sql本身的问题,如果数据库当时没有压力,但是执行时间又很久,那么数据库在执行这个sql时肯定在等待什么资源,一说到等待什么资源,我们立马想到了,这个根据主键更新记录需要获取到id=xx的主键索引的锁,会不会这个id=xx的锁被某个其他的长时间运行的事务持有而导致等待锁资源呢?
想到这一点之后,我们才想到查看一下数据库这个时间点的慢查询日志,突然一条根据时间字段更新记录的sql映入眼帘,

update product set buynum = 100 where update_time > xx

这条导致问题的update语句没有走索引的操作,会锁全表(也就是说会锁定所有的主键索引),而且耗时很长,所以真相也随之浮出水面,是因为有一条update的语句锁全表导致的另一条根据主键id来更新记录的update语句执行超时

那我们知道事情的真相,也就是update语句不通过索引更新记录时会长时间的锁定全表,那么如何解决这个问题呢?
方法1: 尽量的减少update全表记录时锁全表的时长,比如分批执行,虽然还是会锁全表,但是因为锁全表的时间短,可以很快释放
方法2:使用mysql安全模式set sql_safe_updates = 1;
在这种模式下,update或者delete数据要么带上索引字段(目的是为了不锁全表,而只需要锁定特定的记录)要么加上limit限制更新记录的数量(目的是为了减少锁全表的时间)

其实最重要就是要意识到update操作可能会锁表,导致其他的update语句等待,进而级联引起雪崩效应

当时的业务场景是要为从腾讯云队列拉取的数据做路由,分发到4个环境里(dev/test/preonline/online),先根据环境从不同的db里查询一条记录,如果记录满足条件则通过rest接口调用不同环境的接口修改该条记录。 排查过程: select * from information_schema.INNODB_LOCK_WAITS select * from information_... 开发中那些事儿:为啥update超时呢? 前一段时间,生产环境碰到一个异常,更新数据库的时候,提示等待超时(Lock wait timeout exceeded; try restarting transaction),超时时间是50秒,修改一条数据需要等待50秒+,我就有点纳闷了。异常如下: 第一时间没想太多,觉的是可能操作数据库太频繁了。代码中,一般的业务逻辑是,请求过来了,先数据入库,... 当你执行rosdep update,rosdep会尝试访问yaml文件网址,把yaml里的信息转存到本地,这样当你配置上述ros工具或者ros包时,ros会按照依赖关系自动把所需的依赖一并下载。网站https://ghproxy.com/支持github的资源代理,非常好用,我们将用此代理加速rosdep对Github的访问,进而解决rosdep update失败问题。我们要做的,是在rosdep的若干个脚本文件中,把 https://ghproxy.com/ 添加到相应URL前面即可。 在Mybatis-Plus官网当中并没有对于update进行针对性的详细讲解以及其使用,很多初级小白都用不明白,包括我有时候都迷迷糊糊的,基于这个问题我也是下定决心好好整理一篇。本篇文章重点是通过多个案例来进行讲解,每一个案例执行出来的sql我都会放到文章当中,方便大家快速掌握并使用! 线上mysqlupdate语句获取超时情况分析以及复盘 多租户项目生产环境下,需要进行数据修复,执行一条update语句。在执行过程中一直报获取超时,无法执行 有其他事务,将需要修改的数据上导致update获取超时。那么开始分析该租户是否有需要执行时间很长的事务。 发现另一个租户,正在异步的执行大方法,该方法有一个很大的事务。 初步分析结果:一个大的事务,将需要改的数据上了,一直没有释放,导致无法执行。 为什么我update一个租户的数据时,会去获取另一个租户的事务 之前生产出现过死超时现象,一个是生成编号的方法两个线程同时进来先查询再进行插入,导致;一个是查询某类信息,一个线程对已有的数据进行修改,第二个线程也对第一个线程查询到的数据进行修改,第二个线程在最大等待时间范围内,第一个线程没有提交事务或回滚事务,导致第二个线程出现超时,因为对数据进行修改,MySQL默认也会上的 当天晚上生产服务一直在告警,刚刚开始只是一个数据保存接口耗时过长,紧接着整个服务接口都耗时,对外表现为整个服务不可用。 于是优先排查宽带情况,其次看代码逻辑,看错误日志(无一例外都是接口耗时过长报警)。 接着看监控发现goroutine明显增多,依然没有头绪。于是想到重启服务。 重启服务过程中,弹出一个告警日志-db连接数过多,已经超过筏值。这个时候问题才确定。 问题原因 是最初的那个数据保存接口,逻辑很简单,接口拿到请求时,insert或者update进入db内。问题在于update