在业务的高峰期,生成环境的mysql压力太大,没有办法正常响应,需要短期内、临时地提升一些性能。 下面就是一些解决方案,但是这些方案是存在一些风险的。
短链接风暴
正常的短链接模式就是连接到mysql之后,执行很少的语句然后断开,下次需要的时候再重连。使用短链接在业务高峰期的时候会造成连接数暴增的情况。
mysql有一个参数max_connections来控制一个mysql实例中能够同时存在的最大连接数,超过这个数的连接就会被拒绝,而在这些被拒绝的连接看来,数据库就是不可用的。
解决这个问题一个自然的想法就是调高max_connections的值,但是这个参数本身就是为了保护mysql的,如果将它调高允许更多的连接,那么就需要花费更多的资源去进行权限验证等逻辑,已建立的连接反而拿不到资源去执行业务的SQL,结果反而适得其反。
解决这个问题可以采用下面的方案。
先处理掉占着连接但不工作的线程
只要建立连接就占用一个计数,对于不需要保持的连接,可以使用kill connection主动踢掉。这个行为与设置的wait_timeout的行为是一样的,一个线程空闲wait_timeout秒之后就会被断开。
不过显示删除为sleep的线程是有损的。看下面的例子:

使用show processlist会显示A和B都是sleep状态,但是很明显应该优先断开B连接,因为它不会对业务造成任何影响。 查 information_schema 库的 innodb_trx 表可以查看连接的具体事务状态:
select * from information_schema.innodb_trx\G如果是连接数过多,你可以优先断开事务外空闲太久的连接;如果这样还不够,再考虑断开事务内空闲太久的连接。
减少连接过程的消耗
有的业务代码会在短时间内大量申请数据库连接做备用,如果确认现在数据库是被连接行为打挂了,那么一种可能的方法就是让数据库跳过权限认证阶段。
跳过权限验证的方法是:重启数据库,并使用–skip-grant-tables 参数启动。这样,整个 MySQL 会跳过所有的权限验证阶段,包括连接过程和语句执行过程在内。注意,这种方法风险很高。
慢查询性能问题
会引发性能问题的慢查询,大体上分为下面三种情况:
- 索引没有设计好
- SQL语句没有写好
- MYSQL选错了索引
索引没有设计好
就通过创建索引来解决,5.6之后,创建索引支持Online DDL,直接执行alter table语句就行了。
比较理想的是能够在备库先执行。假设你现在的服务是一主一备,主库 A、备库 B,这个方案的大致流程是这样的:
- 在备库 B 上执行 set sql_log_bin=off,也就是不写 binlog,然后执行 alter table 语句加上索引;
- 执行主备切换;
- 这时候主库是 B,备库是 A。在 A 上执行 set sql_log_bin=off,然后执行 alter table 语句加上索引。
平时变更的时候,应该考虑gh-ost这样的方法,但是紧急处理时,上面的方案更加高效。
SQL没有写好
mysql5.7提供了query_rewrite 功能,可以把输入的一种语句改写成另外一种模式。
mysql> insert into query_rewrite.rewrite_rules(pattern, replacement, pattern_database) values ("select * from t where id + 1 = ?", "select * from t where id = ? - 1", "db1");
call query_rewrite.flush_rewrite_rules();这样就可以将SQL语句在线上变更为另一条SQL语句。
选错了索引
应急方案就是给SQL加上force index。利用query_rewrite功能可以完成这一点。
QPS突增问题
有时候由于业务突然出现高峰,或者应用程序 bug,导致某个语句的 QPS 突然暴涨,也可能导致 MySQL 压力过大,影响服务。
紧急处理方式:
- 一种是由全新业务的 bug 导致的。假设你的 DB 运维是比较规范的,也就是说白名单是一个个加的。这种情况下,如果你能够确定业务方会下掉这个功能,只是时间上没那么快,那么就可以从数据库端直接把白名单去掉。
- 如果这个新功能使用的是单独的数据库用户,可以用管理员账号把这个用户删掉,然后断开现有连接。这样,这个新功能的连接不成功,由它引发的 QPS 就会变成 0。
- 如果这个新增的功能跟主体功能是部署在一起的,那么我们只能通过处理语句来限制。这时,我们可以使用上面提到的查询重写功能,把压力最大的 SQL 语句直接重写成”select 1”返回。 这样操作处理的风险很高:
- 如果别的功能里面也用到了这个 SQL 语句模板,会有误伤;
- 很多业务并不是靠这一个语句就能完成逻辑的,所以如果单独把这一个语句以 select 1 的结果返回的话,可能会导致后面的业务逻辑一起失败。