一、短连接风暴
短连接:执行很少的 SQL 语句就断开,需要再连。高峰期可能连接数暴涨
成本高。除三次握手,需登录权限、读写权限。
max_connections控制连接数,超过报“Too many connections”。
调高max_connections 有风险。改太大,让更多的连接都可以进来,系统负载大,大量的资源耗费在权限验证等逻辑上,已经连线程拿不到 CPU 资源去执行业务的 SQL 请求。解决方法:
2.1方法1:处理占连接不工作线程
max_connections 计算,不看谁running,占计数位 kill connection 主动踢掉。跟事先设置 wait_timeout 效果一样:空闲 wait_timeout 多少秒之后,断开连接。show processlist 踢掉sleep 线程,可能有损:
A 没有提交,回滚; B 没影响。哪些事务外空闲? C 在 T 时刻之后30 秒执行 show processlist
id=4 和 id=5 都是 Sleep。看事务具体状态: information_schema库的 innodb_trx 表。
trx_mysql_thread_id=4, id=4 事务中
kill connection + id 的命令, sleep主动断开,客户端不会马上知道。发起请求报错“ERROR 2013 (HY000): Lost connection to MySQL server during query”。
可能有损,不重连,直接用已经不能用句柄重试。从应用端看上“MySQL没恢复”。断开连接要通知到业务开发。
1.2 方法2:减少连接过程消耗
短时间大量申请连接备用,跳过权限验证:–skip-grant-tables重启数据库
“饮鸩止渴”,风险极高,不建议用(尤其库外网可访问)
默认--skip-networking 参数打开,只被本地客户端连接。
查询、更新导致性能问题:慢查询导致, QPS突增导致
二、慢查询性能问题
引发慢查询可能&解决方案:索引没设计好、SQL 没写好、选错索引
2.1索引没设计好
通过紧急创建索解决。高峰期被语句打挂,直接执行 alter table。主库 A、备库 B:
1. 在备库 B 上执行 set sql_log_bin=off,不写 binlog,执行 alter table 加索引;
2. 主备切换;
3. A 上执行 set sql_log_bin=off,执行 alter table 加索引。
“古老” DDL 方案。平时变更, gh-ost 更稳妥。紧急这个效率高。
2.2语句没写好
18 篇文章《为什么这些 SQL 语句逻辑相同,性能却差异巨大?》错误导致没用上索引。
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(); 这个存储过程,让插入新规则生效,“查询重写”。确认:
2.3选错索引
10 篇文章《MySQL 为什么有时候会选错索引?》查询重写功能,原语句加 force index解决
前两种实际上出现最多。预先发现问题(上线前的“额外”时间,会省下故障复盘时间):
1. 慢查询日志(slow log)打开,long_query_time = 0,确保每个语句都被记录
2. 模拟线上数据,回归测试;
3. 观察慢每类语句,Rows_examined是否与预期一致。
新增SQL不多,手动跑。修改表结构,全量回归测。开源工具pt-query-digest(https://www.percona.com/doc/percona-toolkit/3.0/pt-query-digest.html)。
三、QPS 突增问题
突然高峰,或者bug, QPS 暴涨,MySQL 压力大,影响服务。下功能,数据库端处理:
1. 白名单去掉:新bug 导致。DB 运维规范(白名单一个个加)。确定下功能,时间上没那么快。
2. 断开连接: 新功能单独库,删掉用户。新功能连接不成功,引发 QPS 0。
3. 处理语句(优先级低):新功能跟主体部署一起,查询重写功能,压力最大 SQL 语句写成"select 1"返回。副作用:
1. 别的也用误伤;
2. 很多业务不是靠这一个完成, select 1 导致后面失败。
1 和 2 依赖于规范运维:虚拟化、白名单机制、业务账号分离。
小结
粗暴地拒绝、断开连接,重写语句绕坑;
避免大量用短连接。连接异常断开常有,代码要有重连并重试机制。
DBA 通过语句重写处理,风险高,做好 SQL 审计可减少
解决方法主要在 server 层。
思考:业务高峰期临时救火场景?怎么处理?
评论1
delete大事务导致磁盘满,数据库hang住,连接不上,无法kill掉大事务.现象是:
binlog一个文件50G(说明事务已经执行完成,fsync相当copy,空间占满)
lsof | grep delete 该tmp文件100多G(binlog_cache不够用,binlog写进tmp,binlog完全落盘删除之前tmp)
redo log还是只有4个组,每个文件1G(循环写,redo log分为mtx落地到磁盘上。没有一次性暴增,还是原大小持续写.)
undo log大概有100来G
解决办法:切从库,kill主库进程。binlog缩小为原来。主库启recovery非常慢。后面kill掉,innodb_force_recovery=3(不执行事务回滚操作)恢复,recovery半天没反应。不是重要库,新主库备份文件重做了之前的主库,从库启。
后续测试:还耗时,redo log一直变,binlog没变,recovery=3
Binlog 大是大事务,崩溃恢复处理redolog 多,耗时在这(通过redo log恢复数据页。)
最老binlog移动到别的盘(确定备份就删)。强制重启伤,做好监控,不让磁盘100%写满