数据库相关
热更新
在事务里热更新同一条数据容易引发锁等待造成慢 SQL,常见于一些 update count,update quota 类的业务场景。
● 故障案例1:某次压测对 DB 产生瞬时 60w+ QPS 的压力,期间同一条数据(更新 count 字段)在事务里大量热点更新导致了行锁争抢产生慢 SQL。
● 故障案例2:几个大用户高并发操作,其中涉及单条热点数据在事务里的更新,排查发现单次更新耗时高达5-6秒,积压的线程引起 Dubbo 对外服务线程池堆积,最终线程池满导致无法对外服务。
○ 线下模拟测试发现 1200 并发进行热点数据的更新(在特定的数据库版本和配置下),开启事务需要1分钟,不开启事务需要3秒。
大表加字段
DDL 变更有多种方式,最原始的方式会造成锁表问题进而引发大量相关联 SQL 锁等待产生慢 SQL;DDL 变更建议走 Online DDL。历史上出现过的一些锁表的 Case 应该是没有走 Online DDL,也可能当时数据库版本不支持 Online DDL。
● 故障案例:大表添加字段未采用 Online DDL,在最后阶段会对表加 Metadata Lock 原子锁,使得大量相关 SQL 锁等待产生慢 SQL,进而快速打满应用线程池。
索引没走对(走了主键全表扫描)
常见于 order by id limit 场景,就算 where 条件里的字段有索引还是有可能走全表扫描。可以通过 IGNORE INDEX(PRIMARY),FORCE INDEX(idx_xxx) 等方式来解决。
● 故障案例:凌晨 3 点多突然收到报警数据库 CPU 100%,排查发现某查询 SQL 走了主键索引触发了全表扫描(SQL 样例为:where a= and b= and c= and d= order by id desc limit 20,当时只有 idx_a_b_e 的联合索引),期间在数据库运维平台手工无差别限流 SQL 有所缓解但很快 CPU 又会飚上来,也尝试了物理删除一些无效数据减少数据量,多管齐下,最后通过临时增加一个 idx_a_b_c_d 新的全字段覆盖的索引止血。
深分页
数据量大时深分页引发慢 SQL 也是个常见的经典问题。解法可以是使用 NexToken 或者叫游标的方式查询,目前阿里云有很多 OpenAPI 已经提供了 NextToken 的查询方式。
● 故障案例:某账号(数据量巨大)调用某查询接口分页查询引发慢 SQL 导致数据库连接池满进而导致 Dubbo 线程池满无法对外服务,紧急限流该账号对该接口的调用后恢复。