MySQL集群在承接高并发业务时,读写性能直接决定了系统的吞吐上限和响应延迟。很多团队在搭建完一主多从或者使用中间件做分片之后,发现实际压测数据和预期差距很大,这往往不是机器性能不够,而是压测方法不对、集群配置没有贴合业务模型。要让MySQL集群真正发挥出价值,必须先搞清楚自己的业务是读密集型、写密集型还是混合负载,再用科学的压测手段去暴露瓶颈,最后做有针对性的调优。

压测工具与场景建模
做MySQL集群读写性能压测,第一步是选对工具并构建贴近真实的业务模型。sysbench是最常用的开源压测工具,它可以模拟OLTP场景下的点查、范围查、索引更新和事务写入。但如果你的业务有大量复杂join或者批量insert,原生sysbench脚本就需要改写。另一个选择是tpcc-mysql,它实现了标准的TPC-C模型,适合检验写多读少且事务链条长的电商类负载。压测时不能只跑只读或者只跑只写,应该按业务真实比例混合,比如八成读两成写,否则得出的QPS和TPS没有参考意义。
在集群环境下,压测客户端要分散部署,避免压测机本身成为瓶颈。同时需要区分直连主库、直连从库、通过ProxySQL等代理层三种访问路径分别压测。直连能测出数据库真实能力,经过代理层则包含了路由开销和连接复用收益。下面是一段使用sysbench做读写混合压测的示例,其中线程数、表数量、表大小都可按集群规格调整:
# 准备测试数据,10张表每张100万行 sysbench oltp_read_write --db-driver=mysql --mysql-host=192.168.0.1 --mysql-port=3306 --mysql-user=test --mysql-password=test --tables=10 --table-size=1000000 prepare # 运行压测,64线程,时长300秒,读写混合 sysbench oltp_read_write --db-driver=mysql --mysql-host=192.168.0.1 --mysql-port=3306 --mysql-user=test --mysql-password=test --tables=10 --table-size=1000000 --threads=64 --time=300 --report-interval=10 run
压测过程中要同步采集主库和从库的show global status中的Threads_running、Innodb_row_lock_waits、Handler_commit等指标,以及磁盘util、CPU us和sys占比。只盯平均延迟会被长尾请求误导,建议记录p99和p999。当从库出现较大复制延迟时,读流量若被路由到从库就会导致数据不一致感知,这也是压测读写分离集群时必须监控的点。
集群拓扑对读写性能的影响
MySQL集群常见拓扑有一主一从、一主多从、双主、以及基于中间件的分库分表。不同拓扑在读写压测中的表现差异明显。一主多从能把读流量分散到多个节点,写仍然受单主限制,因此写性能天花板就是主库的单机能力。如果业务写压力持续走高,加从库毫无帮助,必须引入分片或者升级主库硬件。双主架构看似能写两边,但实际常配成互为主从且只写其中一个,另一个做容灾,并不能真正水平扩展写能力。
使用ProxySQL或者MySQL Router做读写分离时,查询规则要小心。如果把带临时表的查询、事务内的读请求错误路由到从库,就会报错或者读到旧数据。压测时要验证路由规则是否命中预期,代理层本身的线程模型和连接池大小也会限制总吞吐。以下示例展示ProxySQL中一个简单的读写分离规则配置思路,将事务外的SELECT发往从库组:
-- 定义后端主机组:10为主库,20为从库组 INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'192.168.0.1',3306); INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (20,'192.168.0.2',3306); -- 将非事务内的SELECT路由到从库组 INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*',20,1); -- 其他请求默认走主库 INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) VALUES (2,1,'^.*',10,1); LOAD MYSQL SERVERS TO RUNTIME; LOAD MYSQL QUERY RULES TO RUNTIME;
除了拓扑本身,网络延迟对集群写性能影响很大。主从异步复制下,主库提交不需要等从库,但半同步复制会要求至少一个从库ACK,这会增加写事务的响应时间。压测时要对比异步、半同步、组复制(MGR)三种模式的写TPS,结合业务对数据可靠性的要求做取舍。MGR在多数节点正常时能提供强一致,但跨机房部署时网络往返会让写延迟显著上升,需要控制在同可用区内部署。
核心参数与架构层调优
压测暴露瓶颈后,调优要从数据库参数、操作系统、架构三层入手。数据库侧最关键的InnoDB参数包括innodb_buffer_pool_size、innodb_flush_log_at_trx_commit、sync_binlog和innodb_io_capacity。缓冲池应设为物理内存的七成左右,让热数据尽量留内存。写密集场景若可以容忍宕机丢少量事务,将innodb_flush_log_at_trx_commit设为2、sync_binlog设为0能大幅提升TPS,但需评估数据安全风险。
操作系统层要确认磁盘调度算法用noop或deadline,文件系统挂载加noatime,并且避免NUMA内存分配失衡导致跨节点访问变慢。使用SSD时innodb_io_capacity可设到2000以上,让刷脏页更积极,减少突发写时的阻塞。以下Java代码片段演示了在应用侧使用连接池HikariCP时,如何根据压测结果调整最大连接数,避免过多连接压垮数据库:
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://192.168.0.1:3306/test");
config.setUsername("test");
config.setPassword("test");
// 压测显示数据库活跃连接峰值约40,池上限设为80留余量
config.setMaximumPoolSize(80);
config.setMinimumIdle(10);
// 连接最长存活与超时,防止代理层断开后应用持无效连接
config.setMaxLifetime(1800000);
config.setConnectionTimeout(3000);
HikariDataSource ds = new HikariDataSource(config);
架构层调优往往收益最大。当单主写瓶颈明确时,可按用户ID或者订单ID做一致性哈希分片,把写分散到多个MySQL实例。读流量除了依赖从库,还可以引入本地缓存如Redis,挡掉重复查询。对于报表类重查询,应单独丢到分析型从库或者列式存储,不和高并发交易集群抢资源。经过压测、监控、调优的闭环迭代,MySQL集群才能稳定支撑业务增长,而不是在故障来临时才发现容量早已不足。