原创

故障处理系列-mysql引起的服务雪崩

1、背景

  • 多个服务出现告警,服务超时504
  • 经排查是由于某个底层服务的数据库存在mysql慢查引起的
  • 进一步排查这个mysql的慢查是由于某个开发使用客户端查询数据,但是出现失误造成的
  • 这个sql执行了70分钟,未使用索引,使用了group by。表数据超20亿。表空间约1T

2、思考

  • 客户端执行的错误sql,发现了错误,但是无法强制杀掉。只能依赖dba进行处理。问题是开发以为自己客户端操作取消 了。告警是后续执行到某一时间段才出现。不细心的话,没有联想到这个问题。mysql的为什么不能增加一个慢sql的监控,当sql的执行时长超过某个阈值的时候,直接kill。有效的保护系统。比如设定为60s。正常来说超过60s的sql在系统的业务中是不应该出现的。排除数仓的这种系统
  • 客户端为什么路由代理进行数据访问,代理层缺少sql的执行计划的审核,sql超时的情况的处理
  • 业务中还有一个情况是因为drds是比较贵的,而目前配置是足够的,然后好几个服务公用了drds。最终导致的结果是一个服务的rds出现了问题。影响到了全局的drds。这个是需要考虑。
  • 开发查询数据用于排查日常的问题这个是没法避免的。但是人工操作失误是没法避免的。为了解决误操作带来的风险。sql执行时长控制是一个手段,还有另一个方式是数据库读写分离,使用从库、备库供业务查询和数仓同步。
  • 增加必要的告警,慢sql执行到超过阈值需要kill。同时告警出来,提示对应的开发核实事务的合理性。

3、拓展

3.1、max_execution_time

mysql5.6可以使用pt-kill
https://www.percona.com/doc/percona-toolkit/LATEST/pt-kill.html

mysql 5.6 及以后,有语句执行超时时间变量,用于在服务端对 select 语句进行超时时间限制;
mysql 5.6 中,名为: max_statement_time (毫秒)
mysql 5.7 以后,改成: max_execution_time (毫秒)

超过这个时间,mysql 就终止 select 语句的执行,客户端抛异常:
1907: Query execution was interrupted, max_execution_time exceeded.

3.2、三种设置粒度:

--全局设置
SET GLOBAL MAX_EXECUTION_TIME=1000;
--对某个session设置
SET SESSION MAX_EXECUTION_TIME=1000;

3.3、最后一种--对某个语句设置

SELECT max_execution_time=1000 SLEEP(10), a.* from test a;执行会报如下错误:

[SQL]SELECT max_execution_time=10000 SLEEP(10), a.* from ai_ecg a;
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(10), a.* from ai_ecg a' at line 1

找遍全网,都是这样的设置,我想问下你们有具体去执行过没有?曾经尝试对该SQL进行修改,然而并不生效,只好暂时作罢。

3.4、设置

-- 默认是0,没有超时时间
-- 查询
show variables  like 'max_execution_time';
set global max_execution_time=30;

-- 重新登陆客户端,一定要退出重新连接才会生效
show variables  like 'max_execution_time';
-- 查询验证
mysql> select count(*) from user where name like '%b%';
ERROR 3024 (HY000): Query execution was interrupted, maximum statement execution time exceeded
-- 还原为0
set global max_execution_time=0;
mysql> select count(*) from user where name like '%b%';
ERROR 3024 (HY000): Query execution was interrupted, maximum statement execution time exceeded
-- 退出当前连接,重新登陆,再次执行
mysql> select count(*) from user where name like '%b%';
+----------+
| count(*) |
+----------+
|    32017 |
+----------+
1 row in set (0.06 sec)
正文到此结束
本文目录