在实际生产中可能会碰到这样的情景:业务高峰期,MySQL压力太大,没法正常响应,需要短期内、临时地提升一些性能。
短连接问题
短连接模式就是连接到数据库后,执行很少的SQL语句就断开,下次需要的时候再重连,如果使用的是短连接,在业务高峰期的时候就会出现频繁的建联和断连操作。
问题
建立连接耗费资源
MySQL建立连接的成本很高,除了TCP的三次握手外还要进行一系列验证。
连接数过多超过最大连接数
最大连接数参数为:max_connections,超过这个值系统就会拒绝接下来的连接请求,并提示“Too many connections”,这时我们可以适当调整增加最大连接数,但最大连接数也不宜设置过大
连接过多导致资源竞争
大量的资源耗费在验证逻辑上,并且连接过多,资源不够,已经连接的线程拿不到CPU资源去执行业务的SQL请求
处理方法
1、先处理掉占着连接但不工作的线程
使用kill 命令主动踢除这些线程,那怎么查看哪些线程是空闲的呢?
- 首先使用show processlist命令查看当前正在执行的线程,挑选处于Sleep的线程,但是处于Sleep的线程并不一定是空闲的
查看
infomation_schema库的inodb_trx表,这张表中的数据表示仍在事务中的线程,除去这些线程,那processlist中其他的线程就是空闲的,可以kill掉2、减少连接过程中的消耗
如果有业务会在短时间内申请大量的连接,可以让数据库跳过权限验证阶段,需要重启数据库并使用
-skip-grant-tables参数启动。整个MySQL会跳过所有的权限验证阶段,包括连接过程和语句执行过程在内。
这种方式风险极高,特别不建议使用。MySQL8.0版本开启此参数会默认把--skip-networking参数打开,表示这时候数据库只能被本地的客户端连接。慢查询性能问题
索引没设计好
解决方案:一般就是通过紧急创建索引来解决,因为MySQL5.6版本以后,创建索引支持Online DDL了。理想状态下是能够在从库先执行,假如目前是一主一从,A主B从,人工操作流程如下
在从库B上执行set sql_log_bin=off,关闭写binlog,然后在B上增加索引
- 执行主从切换
- 主库为B,从库为A,关闭A的binlog,在A上增加索引
SQL语句没写好
如果不能对系统进行重启,那么可以在线将SQL语句进行改写,MySQL5.7提供了query_rewrite功能,可以把输入的一种语句改写成另外一种模式。
比如我们把语句错误的写成了select * from t where id + 1 = 10000,这会导致全索引扫描,可以通过下边的方式,增加一个语句改写规则:
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();
call query_rewrite.flush_rewrite_rules()是让插入的新规则剩下,也就是“查询重写”。
验证:
MySQL选错索引
可以使用force index强制指定某个索引(但也不一定会走)。
总结
慢查询问题我们还是要在上线前及时发现,预先发现问题
- 上线前,在测试环境,将慢查询日志打开,设置long_query_time=0,确保每个语句都会被记录入慢查询日志
- 在测试表里插入模拟线上的数据,做一遍回归测试
- 观察慢查询日志里每类语句的输出,流域Rows_exmined字段是否与预期一致
可以使用pt-query-digest检查所有的SQL语句的返回结果
QPS突增问题
有时由于业务突然出现高峰,或者应用程序bug,导致某个语句的QPS突然暴涨,也可能导致MySQL压力过大,影响服务。
之前碰到过同事做的一个服务的读写分离功能上线后出现问题,导致MySQL性能出现问题。
最理想的状态就是把这个功能下掉,服务自然就会恢复,但是下掉一个功能,如果从数据库端处理的话,对于不同的背景,处理方法不同:
- 一种是由全新业务的bug导致的,如果DB运维是比较规范的,白名单是一个一个加的,如果确定业务方会下掉这个功能,只是时间上没有那么快,那就可以从数据库端直接把白名单去掉
- 如果这个新功能使用的是单独的数据库用户,可以用管理员账户把这个用户删掉,然后断开现有的连接,这样,这个新功能的连接不成功,也就没办法消耗数据库的资源
- 方案1、2都要依赖于规范的运维体系:虚拟化、白名单机制,业务账号分离,由此可见,更多的准备,旺旺意味着更稳定的系统
- 如果这个新增的功能跟主体功能是部署在一起的,那么我们只能通过处理语句来限制,比如使用上面讲过的查询重写功能,把压力最大的SQL直接重写成”select 1”,但这个操作的风险很高,会有以下两个问题
- 如果别的功能里面也用到了这个SQL语句模板,会有误伤
- 大多数业务是需要对个语句完成的,因此把某一个语句重写可能会到最后后面的业务逻辑一起失败
