上一篇 下一篇 分享链接 返回 返回顶部

我们的小站并发增长后,低配服务器上的MySQL何时该升级内存?

发布人:Minchunlin 发布时间:2026-10-03 15:23 阅读量:10

小站从每天几百次访问增长到高峰期数百个并发请求后,数据库开始变慢,并不意味着第一步就该加内存。我们可以先看两个问题:MySQL是否长期缺少可用内存,以及慢查询、连接堆积或磁盘读写是否才是瓶颈。若业务高峰期间系统可用内存持续偏低、出现换页,同时InnoDB缓存命中情况变差,才更适合优先评估升级内存;如果内存仍充足,单纯扩容往往解决不了慢查询。

下面按“先留基线、再确认瓶颈、最后调整和验证”的顺序处理。操作前应确认数据库版本、当前配置文件位置、备份可用性和维护窗口;配置变更前保留原文件,并准备好恢复方案。文中的容量和阈值用于判断参考,不代表所有业务都适用。

先判断问题是否真由内存不足引起

以一台同时运行网站程序和MySQL的小型服务器为例:业务增长后,页面偶尔加载超过两秒,数据库高峰期查询变慢。我们先不改配置,在业务高峰时连续观察15至30分钟,并把结果和低峰期对比。只看一次free输出,或只看某个时刻的CPU占用,容易把瞬时波动误判为容量不足。

先判断问题是否真由内存不足引起配图

先记录服务器内存、换页和进程占用:

free -h
vmstat 1 10
ps -eo pid,comm,rss,%mem --sort=-rss | head

重点看以下信息:

  • free -h中的available比单独的free更适合判断系统还有多少可用内存。Linux会利用空闲内存做缓存,因此free偏低本身不等于内存不足。
  • vmstat的si和so分别表示每秒从磁盘换入和换出的内存量。若高峰期间持续非零,并伴随响应变慢,需进一步确认是否发生了内存压力;单次短暂波动不能直接作为扩容依据。
  • MySQL进程的常驻内存持续上升、系统available长期偏低,或日志中出现因内存不足被系统终止进程的记录,都值得关注。

可用下面的命令查看内核是否记录了内存不足事件:

journalctl -k --since "2 hours ago" | grep -Ei "out of memory|killed process"

不同发行版和日志权限可能导致查不到记录;没有匹配结果不等于一定没有内存问题。若怀疑MySQL异常退出,还要结合数据库错误日志和服务状态核对。

接着检查MySQL的运行数据。先用有权限的账户登录,再执行:

SHOW GLOBAL STATUS
WHERE Variable_name IN (
  'Threads_connected',
  'Threads_running',
  'Max_used_connections',
  'Created_tmp_disk_tables',
  'Uptime'
);

SHOW GLOBAL VARIABLES
WHERE Variable_name IN (
  'innodb_buffer_pool_size',
  'max_connections',
  'tmp_table_size',
  'max_heap_table_size'
);

Threads_connected表示当前已建立的连接数,Threads_running更接近当前正在执行工作的线程数;Max_used_connections则是自MySQL启动以来连接数曾达到的峰值。连接峰值高不代表这些连接一直同时消耗同等资源,也不意味着应直接把max_connections调得更大。连接数上限调高后,若应用突发建立大量连接,反而可能加重内存压力。

还要看InnoDB缓存是否有明显读取压力:

SHOW GLOBAL STATUS
WHERE Variable_name IN (
  'Innodb_buffer_pool_read_requests',
  'Innodb_buffer_pool_reads',
  'Innodb_buffer_pool_wait_free',
  'Innodb_buffer_pool_pages_dirty'
);

Innodb_buffer_pool_read_requests是逻辑读取请求,Innodb_buffer_pool_reads是需要从磁盘读取数据的次数。可在同一统计周期内计算近似缓存命中率:

命中率 ≈ 1 −(Innodb_buffer_pool_reads ÷ Innodb_buffer_pool_read_requests)

例如某个观察周期内逻辑读取约为1亿次,磁盘读取约为10万次,近似命中率约为99.9%。这个数字不能单独决定是否扩容:它依赖统计周期、缓存预热情况和工作负载。若磁盘读取增加与查询变慢同步发生,同时系统可用内存又长期偏低,才更支持“缓存容量不足”的判断。

用多项信号决定是否升级

我们可以把“该不该加内存”拆成四类信号,而不是用一个固定数值作决定。

观察结果更可能的原因建议动作
高峰期可用内存持续低于总内存的约10%至15%,并伴随持续换页或内存不足记录物理内存压力检查进程占用和MySQL配置;确认数据库缓存确实需要空间后再评估升级
InnoDB缓存读取压力高、磁盘读取增加,缓存空间接近上限,且系统仍有可分配内存数据集或工作集超出当前缓存能力先检查查询和索引,再考虑增加缓冲池或服务器内存
内存充足,但CPU长期较高、慢查询多或锁等待明显查询执行、索引、并发竞争等问题优先分析SQL和锁,不要先加内存
数据库响应正常,只有应用请求变多,连接数上涨但运行线程不多连接管理或应用侧并发模式检查连接池和请求排队,避免盲目扩大连接上限

上表中的比例是便于筛查的参考线,不是通用告警标准。对于数据库和网站程序共用的低配服务器,MySQL之外的进程也会争用内存;而专用数据库服务器可以把更多内存留给数据库。判断时要结合高峰期的持续情况,而不是把短暂突刺当成长期容量需求。

如果服务器本身没有明显内存压力,但查询仍慢,我们接着检查慢查询、执行计划、索引和锁等待。若慢查询日志尚未启用,应先确认当前版本支持的参数和日志位置,再在低风险时段配置;不要为了排查直接对生产库执行大量全表扫描。对代表性慢查询使用EXPLAIN查看访问方式、预估扫描行数和使用的索引。常见情况是缺少合适索引或一次读取远超需要的数据,此时增加内存只能暂时掩盖低效访问。

先做低风险优化,再计算内存需求

确认有优化空间后,我们先处理不需要扩容的部分:

  1. 找出高频慢查询,减少无必要的字段读取和重复请求,检查筛选、排序、关联条件是否有合适索引。
  2. 检查应用是否重复创建数据库连接。若已使用连接池,核对池大小、空闲连接和超时设置,避免连接数随访问量无上限增长。
  3. 检查临时表和排序相关指标。Created_tmp_disk_tables增长较快可能与查询形态、临时结果大小和相关参数有关,不能简单通过大幅提高临时表内存上限解决;并发增加时,单连接可能使用的内存也会累加。
  4. 复查MySQL内存配置是否与机器总内存相符,尤其要关注缓冲池、连接数上限和每连接可能使用的缓冲区。

之后再估算可用于MySQL的内存。对运行在专用服务器上的InnoDB数据库,缓冲池常以物理内存的约50%至70%作为初始估算区间;这是起点,不是必须达到的比例。若同一台机器还运行网站服务、任务进程或监控组件,MySQL应留出更多空间给系统和其他进程,缓冲池比例可能需要更低。低配机器上尤其不能只按数据文件总大小决定缓冲池大小:数据文件可能包含冷数据,实际工作集不一定等于总数据量。

例如,一台总内存为4GB、同时承载网站程序和MySQL的服务器,若系统和应用在高峰期约需1.5GB,MySQL连接及其他开销还需预留空间,就不应直接把缓冲池设置到接近4GB。可以先检查当前使用量与高峰余量,再以较小幅度调整;若计算后缓冲池已无安全增长空间,且高峰时持续换页,就比单纯调大参数更适合升级物理内存。

调整前准备与变更步骤

以下操作以Linux系统、MySQL服务运行正常、具备数据库管理权限为前提。命令中的服务名、配置路径会因发行版和安装方式不同而变化,先确认实际环境,不要直接照抄路径。

1. 确认版本、配置和服务名称

mysql --version
systemctl status mysqld
systemctl status mysql

两个服务名不一定同时存在,以能查到实际服务状态的名称为准。登录数据库查看运行参数:

SELECT VERSION();

SHOW VARIABLES
WHERE Variable_name IN (
  'innodb_buffer_pool_size',
  'max_connections',
  'datadir'
);

配置文件可能位于发行版的默认目录、安装目录或自定义路径。可通过以下命令查看MySQL识别的配置文件搜索位置,再逐个核对:

mysqld --verbose --help 2>/dev/null | head -n 30

如果服务由容器或其他管理方式启动,应以实际启动参数和挂载配置为准,不要在未确认生效路径时修改系统中的同名配置文件。

2. 备份配置并保留数据库恢复能力

在编辑配置之前,先备份实际生效的配置文件。下面路径仅作格式示意,应替换为已确认的文件路径:

sudo cp -a /etc/mysql/my.cnf /etc/mysql/my.cnf.before-memory-change

如果配置由多个文件包含而成,也要备份实际包含的相关配置。数据库配置调整通常不修改数据文件,但重启会中断数据库连接;因此要在允许短暂中断的维护窗口操作,并确认已有可用、可恢复的数据库备份。不能只确认“备份任务成功”,还应了解最近备份时间和恢复流程。配置备份用于回退参数,不替代数据库备份。

3. 小幅调整缓冲池,不同时改多个变量

在确认服务器余量后,调整innodb_buffer_pool_size。例如,若评估后计划把缓冲池设为1G,可在实际生效的[mysqld]配置段设置:

[mysqld]
innodb_buffer_pool_size = 1G

编辑前确认配置文件中没有重复定义该参数,避免不同配置项加载顺序导致结果不符合预期。不要同时大幅调整max_connections、临时表上限和多种每连接缓冲区;一次改一类变量,才容易判断影响来自哪里。

部分MySQL版本支持运行时调整缓冲池大小,但具体支持情况和生效方式应以当前版本为准。若选择运行时修改,可先检查变量是否动态可调;若不确定,采用配置文件变更并在维护窗口重启,避免将版本差异误当成配置失败。配置变更后确认语法和服务状态,重启命令中的服务名按实际环境替换:

sudo systemctl restart mysqld
sudo systemctl status mysqld

重启失败时先查看服务日志和MySQL错误日志,不要连续重复重启:

sudo journalctl -u mysqld --since "15 minutes ago"

若服务名实际为mysql,应将命令中的mysqld替换为已确认的名称。

4. 验证配置生效与业务表现

服务恢复后,检查缓冲池的实际值和数据库可用性:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW GLOBAL STATUS LIKE 'Uptime';

随后用同一套观测方法覆盖至少一个业务高峰,比较调整前后的可用内存、换页、磁盘读取、慢查询和请求延迟。判断成功不应只看缓冲池数值变大,而要确认:

  • MySQL正常运行,应用连接和核心读写请求通过;
  • 高峰期可用内存留有余量,换页没有持续恶化;
  • 数据库磁盘读取或查询等待有所缓解,且CPU、锁等待等没有出现新的明显瓶颈;
  • 业务延迟改善能够在相近负载下重复观察,而不是只在低峰期出现。

若配置已生效但慢查询和延迟没有改善,或系统开始频繁换页,说明调大缓冲池可能没有解决根因,甚至挤占了其他进程的内存。此时应恢复原配置,并继续检查查询、并发和资源分配。

5. 失败时按原配置回滚

若重启失败或应用连接异常,先停止继续扩大变更范围。将备份配置恢复到原路径,再检查服务日志;恢复操作会覆盖当前配置,因此先保留变更后的文件供排查:

sudo cp -a /etc/mysql/my.cnf /etc/mysql/my.cnf.after-memory-change
sudo cp -a /etc/mysql/my.cnf.before-memory-change /etc/mysql/my.cnf
sudo systemctl restart mysqld
sudo systemctl status mysqld

实际文件路径和服务名称应替换为前面核实的值。若回滚后仍无法启动,检查配置文件语法、权限、磁盘空间和错误日志;不要删除数据库文件或随意修改数据目录权限。确认服务恢复后,再核对应用读写和数据库版本、参数是否回到变更前状态。

什么时候从调参转向升级内存

我们可以把升级判断落到一条可复用的标准上:在代表性高峰下,内存压力持续出现,且查询与连接层面的明显问题已经排查,才考虑升级;升级后的内存还要能给系统和同机应用留出余量。

例如,某台小站服务器总内存为2GB,网站程序和数据库共用资源。高峰期间系统可用内存持续很低,换页反复发生,InnoDB磁盘读取也随请求量增加;检查后发现查询已有合适索引,连接池没有异常放大,缓冲池也无法在现有内存内安全增加。此时,升级内存通常比继续挤压系统余量更合理。相反,如果可用内存稳定、没有持续换页,但CPU因复杂查询长期繁忙,应该先优化查询,而不是把“并发增长”直接等同于“内存不足”。

当业务从起步期进入增长期,数据量、同时执行的查询和网站进程都会变化。升级前后都应保持相同口径:在相近业务时段记录系统内存、MySQL状态、慢查询与应用延迟,并确认备份和回滚可用。若扩容后仍然变慢,就回到资源指标重新定位;内存只有在确实限制数据库缓存与并发承载时,才是优先升级项。

目录结构
全文