把MySQL搬上AWS EC2之后,很多团队都会遇到同一个疑问:这台云主机到底能撑住多少并发连接、多少每秒事务量?云主机的CPU、内存、磁盘IO都是虚拟化资源,实际表现和本地物理机差别不小,直接照搬物理机的调优经验往往达不到预期效果。本文基于一次完整的高并发压测,记录了不同实例规格、不同并发压力下MySQL的真实表现,并整理出一套可复用的调优思路。

一、实例选型:EC2规格对MySQL性能的影响
本次测试选用了三款常见的实例规格:m5.xlarge(4 vCPU / 16GB内存,通用型)、c5.xlarge(4 vCPU / 8GB内存,计算优化型)和r5.xlarge(4 vCPU / 32GB内存,内存优化型)。三者搭配的EBS均为gp3类型,初始基线性能3000 IOPS、125MB/s吞吐量。
从理论上讲,MySQL属于典型的内存敏感型负载,innodb_buffer_pool_size如果能容纳绝大部分热数据,就能减少大量磁盘IO。因此r5这类大内存实例在数据库场景中往往表现更好。实测也印证了这一点:在数据集总量约为8GB的情况下,r5.xlarge可以把缓冲池设为24GB,热数据几乎全部命中内存,磁盘IO压力极小;而c5.xlarge只有8GB内存,缓冲池最多设6GB,压测中后期频繁出现磁盘读,TPS明显下滑。
另一个容易被忽视的因素是EBS与实例之间的网络带宽限制。gp3卷的默认性能虽然标称3000 IOPS,但实际能跑满多少还取决于实例本身的EBS带宽配额。小规格实例的EBS带宽上限较低,如果需要更高IOPS,要么升级实例规格,要么对gp3卷单独预置性能指标。测试中对m5.xlarge的gp3卷提升到9000 IOPS后,写密集场景的TPS提升了约35%,说明磁盘IO才是这类场景的真正瓶颈。
二、压测环境搭建与sysbench测试流程
压测工具选择sysbench,这是MySQL社区最常用的基准测试工具。测试前需要准备一套标准化的环境,避免无关变量干扰结果。数据库使用MySQL 8.0,关闭查询缓存(8.0已移除该功能),开启独立表空间,事务隔离级别保持默认的REPEATABLE READ。
初始化测试数据的方式如下,创建一个包含20张表、每表100万行的测试库:
# 安装sysbench sudo yum install -y sysbench # 准备测试数据 sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=sbtest \ --mysql-password=yourpassword \ --mysql-db=sbtest \ --tables=20 \ --table-size=1000000 \ prepare
准备完成后,依次以不同线程数执行压测。线程数从16开始,逐步提升到32、64、128、256、512,每个梯度持续运行10分钟,取后半段的稳定数据作为结果,避免冷启动阶段的抖动干扰判断:
# 执行读写混合压测,256并发 sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=sbtest \ --mysql-password=yourpassword \ --mysql-db=sbtest \ --tables=20 \ --table-size=1000000 \ --threads=256 \ --time=600 \ --report-interval=10 \ --percentile=95 \ run
压测过程中建议同时开启监控,用iostat -x 1观察磁盘util和await指标,用vmstat 1观察CPU上下文切换,并在MySQL里执行SHOW GLOBAL STATUS关注Threads_running、Innodb_row_lock_waits等状态值。这些数据对后面定位瓶颈至关重要。
三、实测数据解读:并发与TPS的关系
以r5.xlarge为例,压测结果呈现出典型的抛物线形态。并发从16提升到64时,TPS几乎线性增长,从约4200提升到15800;并发128时TPS达到峰值17600;继续加到256并发,TPS反而回落到16200左右;512并发时跌至14000以下,同时95分位响应时间从7ms恶化到48ms。
这个拐点说明了一个关键结论:并发并不是越高越好,超过CPU处理能力之后,多余的连接只会排队等待,白白消耗上下文切换开销。MySQL的innodb_thread_concurrency参数默认为0(不限制),在高并发下可以尝试设为vCPU数量的2倍左右,让InnoDB内部做一层线程调度,实测在512并发场景下能减少约15%的响应时间波动。
三款实例的峰值TPS对比如下:r5.xlarge约17600,m5.xlarge约15200,c5.xlarge约12100。表面上c5的计算能力并不弱,但受限于内存不足导致的缓冲池偏小,成绩垫底。这再次验证了选型原则:数据库主机优先保证内存能装下热数据集,其次才是CPU主频。如果你的数据集规模持续增长,内存选型的优先级要更高。
四、高并发场景下的关键调优手段
压测暴露问题之后,针对性的调优能带来可观收益。以下是实测中效果最明显的几项配置。
第一是连接池的合理配置。应用侧应使用连接池而不是每次新建连接,推荐让连接池的最大连接数略高于实测TPS峰值对应的并发数,而不是盲目调大max_connections。max_connections设成几千看似保险,实际上每个连接都会消耗内存,且高连接数下线程调度开销会拖垮整个实例。本次测试中,max_connections设为800、连接池控制在300以内,表现最佳。
第二是InnoDB核心参数。以下配置在r5.xlarge上经过了验证:
[mysqld] # 缓冲池设为物理内存的60%-70% innodb_buffer_pool_size = 24G # 高并发下降低刷新频率压力,交给更大的日志文件 innodb_log_file_size = 2G innodb_flush_log_at_trx_commit = 1 # 脏页刷新比例,写密集场景适当调高 innodb_max_dirty_pages_pct = 60 # 每次IO请求的块大小,SSD场景建议16K innodb_io_capacity = 6000 innodb_io_capacity_max = 12000 # 行锁等待超时,避免长事务拖垮连接 innodb_lock_wait_timeout = 10
需要注意innodb_flush_log_at_trx_commit设为1是保证事务不丢失的最安全配置,如果业务能容忍极端情况下丢失1秒事务,可以改成2换取约20%的写入吞吐提升,但要清楚这是在用可靠性换性能。
第三是监控慢查询与锁等待。高并发下最容易恶性循环的场景是:一条慢SQL持有行锁,后续请求堆积,连接数飙升,最终整库卡死。建议开启慢查询日志并把long_query_time设为0.5秒,配合performance_schema中的data_locks表定期排查锁热点。压测中我们发现某张表缺少联合索引导致范围扫描,加上索引后TPS直接提升了22%,这一项的收益超过所有参数调优的总和。
五、生产环境的落地建议
综合这次实测数据,给出几条可以直接落地的建议。实例选型上,如果热数据集在20GB以内,r5.xlarge或r5.2xlarge是性价比很高的选择;数据集更大时优先考虑r5.4xlarge并配合读写分离,而不是在单机上硬扛。
存储层面,生产环境不要使用gp2,至少选择gp3并根据写入压力预置IOPS。对写入非常频繁的核心库,io2卷提供的性能一致性更好,代价是成本上升,需要结合业务预算权衡。另外,务必启用EBS快照做基础备份,再配合MySQL自身的逻辑备份形成双保险。
最后要强调压测的局限性:sysbench的oltp模式是相对理想的均匀读写负载,真实业务中往往存在热点行、长事务、复杂JOIN等场景,实际承载能力通常低于压测数值的70%。建议在上线前用真实业务流量回放做一轮验证,并用CloudWatch结合MySQL自身状态指标持续监控,把innodb_row_lock_time_avg、Threads_running、buffer pool命中率这三项作为日常巡检的核心指标,才能在业务量增长时提前发现问题,而不是等到数据库被打挂了再救火。