重装Ubuntu Server后Docker部署的MySQL 8.0.27性能骤降求助
排查与解决方案
一、存储层瓶颈排查
- 检查存储介质:确认重装后是否更换了存储类型(比如从SSD换成HDD),HDD的随机写入性能远低于SSD,这是大表写入性能骤降的常见原因。用
iostat -x 1查看磁盘%util指标,若持续接近100%,说明磁盘IO已饱和。 - 检查Docker存储驱动与挂载参数:
- 确认Docker使用的存储驱动(
docker info | grep Storage Driver),优先使用overlay2,避免性能较差的devicemapper。 - 检查数据卷挂载参数,确保添加了
noatime(减少文件访问时间写入开销),挂载命令类似:docker run -v /host/path:/var/lib/mysql:rw,noatime ...
- 确认Docker使用的存储驱动(
- 检查文件系统:若使用XFS文件系统,确认是否开启了
discard(TRIM支持,针对SSD),挂载时添加discard参数。
二、MySQL关键配置调整
针对1.6亿条数据的大表,重点优化InnoDB核心参数(修改my.cnf或Docker启动参数):
innodb_buffer_pool_size:设置为服务器物理内存的70%-80%(例如32G内存服务器设为24G),这是InnoDB性能的核心参数,用于缓存表数据和索引。innodb_log_file_size:调整为1G-4G(默认可能仅48M),增大重做日志文件,减少频繁的checkpoint操作,提升写入性能。修改后需要删除旧日志文件并重启MySQL。innodb_flush_log_at_trx_commit:若业务允许最终一致性,将其设为2(默认1是强一致性),降低事务日志刷盘频率。innodb_write_io_threads/innodb_read_io_threads:调整为8或16,提升IO线程并发数。- 修正错误配置:
sort_buffer_size=1G完全冗余(当前业务无排序操作),且该参数是每个连接分配,会导致内存耗尽,改回默认值(256K-1M即可);max_connections=1500若实际连接数远低于此,建议调至实际峰值的1.2倍即可。
三、表结构优化
- 新增主键:当前表无显式主键,InnoDB会自动生成隐藏的6字节聚簇索引,严重影响大表写入性能。将唯一键
address设为主键:
(注意:大表执行此操作会锁表,建议在业务低峰期执行,或使用在线DDL工具)ALTER TABLE addressList ADD PRIMARY KEY (address); - 优化字段类型:
- 将
timestampReadable从varchar(32)改为datetime或timestamp,节省存储空间并提升查询/写入效率。 - 确认
showUpBlock是整数类型,当前为int足够(以太坊区块高度目前约2亿,int最大支持21亿,若后续超过可改为bigint)。
- 将
- 清理冗余索引:若业务中未使用
timestamp和firstTransactionHash的查询,可考虑删除对应的索引,减少写入时的索引维护开销。
四、写入逻辑优化
- 批量插入替代单条插入:将程序中的循环单条
INSERT改为批量插入,一次插入1000-5000条,大幅减少网络交互和事务开销,示例:
配合INSERT INTO addressList (timestampReadable, timestamp, showUpBlock, firstTransactionHash, address) VALUES ('2024-05-20 10:00:00', 1716189600, 20000000, '0x...', '0x...'), ('2024-05-20 10:00:01', 1716189601, 20000000, '0x...', '0x...'), ...;INSERT IGNORE或INSERT ... ON DUPLICATE KEY UPDATE address=address(忽略已存在的地址)。 - 控制事务粒度:批量插入时手动开启事务,避免自动提交的频繁事务日志写入:
const connection = await pool.getConnection(); try { await connection.beginTransaction(); // 执行批量插入 await connection.query(batchInsertSql); await connection.commit(); } catch (err) { await connection.rollback(); throw err; } finally { connection.release(); }
五、其他排查步骤
- 更新表统计信息:重装后MySQL可能未自动更新大表的统计信息,导致执行计划异常,执行:
ANALYZE TABLE addressList; - 检查MySQL错误日志:通过
docker logs <mysql-container-name>查看是否有磁盘IO错误、内存不足等异常信息。 - 验证程序端瓶颈:确认Web3.js获取交易的速度是否与之前一致,若交易获取变慢也会导致整体流程看似MySQL性能下降,可单独测试单条插入的耗时(排除网络或交易获取的影响)。
内容的提问来源于stack exchange,提问作者Pierogi
相关产品推荐
相关产品推荐

