事发情况
当天晚上生产服务一直在告警,刚刚开始只是一个数据保存接口耗时过长,紧接着整个服务接口都耗时,对外表现为整个服务不可用。
于是优先排查宽带情况,其次看代码逻辑,看错误日志(无一例外都是接口耗时过长报警)。
接着看监控发现goroutine明显增多,依然没有头绪。于是想到重启服务。
重启服务过程中,弹出一个告警日志-db连接数过多,已经超过筏值。这个时候问题才确定。
问题原因
是最初的那个数据保存接口,逻辑很简单,接口拿到请求时,insert或者update进入db内。问题在于update时未对where的条件加上索引,导致数据量大时,会锁住全表,导致整个服务不可用。
该接口上线一个多月稳定,事发晚上数据量达到某一临界点,update时锁住全表,后面该接口的请求一直在等待前面的响应。随着请求数量不断增多,从而引发雪崩效应。
定位原因后排查日志,发现错误信息:
Lock wait timeout exceeded; try restarting transaction
为什么改表被锁会影响到服务其他业务响应
一个服务内有配置数据库的连接数上限,而这个接口因为锁表了,导致把连接数占光。从而影响服务其他正常业务的响应。
同时go中每个http请求底层都会new一个goroutine出来,当大量请求访问时,也就解释了为什么goroutine数量会暴涨。
反思
- 先从排查方向来说,当时排查带宽时思路是错误的,如果带宽有问题那么其他服务应该也是异常的,而不只