生产环境MySQL优化实战:从100QPS到10000QPS

张工

· 阅读 712

分享
MySQL优化实战

MySQL从100 QPS到10000 QPS的优化之路

我们的MySQL数据库在生产环境跑了一年多,随着业务增长,QPS从最初的100逐渐攀升,数据库开始出现响应变慢、连接超时等问题。经过系统性的优化,我们成功将QPS从100提升到10000,同时保持了稳定的响应时间。以下是完整的优化过程。

第一阶段:慢查询优化

首先开启慢查询日志(long_query_time = 1),分析TOP 20慢SQL。发现几个典型问题:

缺少索引:一个用户查询SQL没有索引,全表扫描500万行数据。添加联合索引后,查询时间从12秒降到5毫秒。

SELECT *:很多查询使用了SELECT *,返回了大量不需要的字段,增加了网络传输和内存占用。改为只查询需要的字段后,网络带宽降低40%。

深分页SELECT * FROM orders LIMIT 1000000, 20 这种深分页查询需要扫描100万行然后丢弃。改为基于游标的分页:SELECT * FROM orders WHERE id > last_id LIMIT 20,性能提升100倍。

第二阶段:架构优化

读写分离:使用阿里云RDS的只读实例,写操作走主实例,读操作走只读实例。通过Spring的AbstractRoutingDataSource实现动态数据源切换。读写分离后,主实例CPU从85%降到40%。

引入Redis缓存:热点数据(用户信息、商品详情、配置数据)缓存到Redis。缓存命中率约85%,大部分请求在Redis层就被拦截了,根本不会打到MySQL。

连接池优化:使用HikariCP连接池,配置最大连接数50、最小空闲10、连接超时30秒。之前用的Druid连接池在高并发下表现不如HikariCP。

第三阶段:分库分表

当单表数据量超过5000万时,即使有索引查询也开始变慢。我们对订单表做了分表处理:按用户ID取模分成16张表(orders_00到orders_15)。使用ShardingSphere-JDBC做分表中间件,对应用层透明。

分表后单表数据量降到300万左右,查询性能恢复到毫秒级。但分表也带来了新的问题:跨表JOIN、分布式事务、全局唯一ID。我们用Snowflake算法生成全局ID,用Seata处理分布式事务。

优化效果

经过三个阶段的优化,系统QPS从100提升到10000+,P99响应时间从2秒降到50毫秒,数据库CPU利用率稳定在50%以下。整个过程历时6个月,不是一蹴而就的。

#MySQL#性能优化#数据库