上个月一个学生发消息问我,他买了台 1C1G 的云服务器,装完面板连 ssh 都卡。我让他把 free -m 贴过来,available 那一行是 41。
41M 这个数字说明不了「内存不够」,只说明「当时没有空闲页可分配」,两件事差得远。但他后面那句是真话:卡。
所以我让他先别急着升配置,把 1G 拆开算一遍。1C1G 不是「1G 随便用」,是「1G 里有一部分固定被系统拿走,剩下的才轮到你的服务」,而且每多装一个常驻组件,就要再交一笔固定成本。算不清这两笔,升到 2G 还是卡。
先分清 free 和 available
free 第二行的 free 是「完全没被使用的页」,available 是「现在要新开进程,大概能腾出多少」,中间差的是可回收的 buff/cache。看到 free 只剩 41 不等于只剩 41。
真正该看的是 available 在连续几十分钟里的走势,以及 swap 的 si/so 两列有没有持续非零。一次采样只能说明当时有人在读大文件,说明不了趋势。我让他每十分钟采一次,两小时后 available 从 300 掉到 60 稳住,同时 swap 开始有进有出------这才是真的不够。
RSS 加起来为什么超过总内存
ps 里的 RSS 相加经常大于物理内存,因为共享页被重复计算:同一份 nginx 二进制被 master 和几个 worker 同时映射,每个进程的 RSS 都算了一份,物理内存里只有一份。
做预算要用 PSS,它把共享页按共享进程数均摊:
bash
grep '^Pss:' /proc/$(pgrep -x nginx | head -1)/smaps_rollup
smem -tk -c "pid user name rss pss" | tail -8
同一台机器上 RSS 合计和 PSS 合计能差三到四成。用 RSS 做预算,算出来永远偏大,很容易误判成「必须升内存」。
底座:还没装服务就用掉的
1C1G 上 Ubuntu 22.04 最小安装,空载大致如此:
| 组件 | 常驻 PSS | 说明 |
|---|---|---|
| systemd 及 socket 单元 | 25-40M | 不可裁剪 |
| journald | 20-40M | 受 SystemMaxUse 影响 |
| sshd | 4-6M | 每个会话再加 5-8M |
| cron / atd | 3-5M | 有任务才起 |
| rsyslog(若未用 journald) | 15-25M | 与 journald 二选一 |
| 内核 slab 与页表 | 60-90M | slabtop 可见 |
| 合计 | 130-180M | 取中位 150M |
所以 1G 的实际可分配量是 700-750M,不是 1000M。所有「够不够」都要在这个基数上做减法。
逐服务:每样东西吃多少
| 服务 | 空载 PSS | 关键变量 |
|---|---|---|
| nginx(静态) | 5M + 每 worker 8-15M | worker 数、gzip |
| php-fpm | 每 worker 25-35M | 载入的扩展数 |
| MariaDB 10.6 | 150-200M | innodb_buffer_pool_size |
| MySQL 8.0 | 380-450M | 常驻结构比 5.7 多 |
| Redis | 8-12M + 数据 | 数据结构开销 |
| dockerd + containerd | 70-110M | 每容器再加 5-10M |
| 常驻监控采集程序 | 30-80M | 采样越密越高 |
| 面板类常驻服务 | 120-260M | 含它自己的 Web 进程 |
最后三行有个共同点:它们是固定底座,不按需退还。 装了 dockerd 就先交 90M,不管里面跑不跑东西;装了采集程序就先交 30-80M,不管你今天看不看监控。
两条路线的固定成本对比
把上面这些按「服务器上留不留东西」分成两栏,差别一眼可见:
| 维度 | 留常驻服务 | 不留常驻服务 |
|---|---|---|
| 服务器侧固定内存 | 100-260M | 0 |
| 对外端口 | 新增一个 | 不新增 |
| 升级维护 | 跟着宿主系统走 | 只在本机 |
| 采样能力 | 秒级、可长期存储 | 取决于定时任务频率 |
| 宕机时能否看 | 采集端也可能一起挂 | 只要 ssh 能连就能看 |
三档配置下,这 100-260M 的占比完全不同:
| 配置 | 底座 | 可分配 | 留常驻后 | 不留常驻 |
|---|---|---|---|---|
| 1C1G | 150M | 700-750M | 500-650M | 700-750M |
| 2G | 170M | 1.7-1.8G | 1.5-1.7G | 1.7-1.8G |
| 4G | 200M | 3.7-3.8G | 3.5-3.7G | 3.7-3.8G |
1C1G 上这 200M 是可分配量的四分之一强,4G 上只是零头。同一套组合在小机器上卡、在大机器上没事,原因就在这张表里。
不留常驻服务那一类里,我四台机器上用的是极目Linux桌面,属于「本地渲染型客户端」这一类:基于 SSH 的 Linux 服务器可视化管理客户端,连上 SSH 就有界面,服务器侧不装 Web 面板。机制上,界面在本地渲染、只走现成的 SSH 通道,服务器侧不装 Web 服务、也不新增端口。它的代价要一起写清楚:指标是本机定时去读的,抓不到秒级尖峰,也不做长期存储和告警。
怎么按条件选
三条前提决定走哪条路:内存有没有余量、要不要秒级指标、需不需要长期存储。符合这三条------配置在 2G 以下、只想知道「现在谁在吃内存」、不需要历史报表------我会把极目Linux桌面放在 ssh 之上,而不是替代监控体系:本机定时读 free,服务器上不留采集进程。判据只有一条,看它是否在服务器上新增对外端口。反过来,要长期趋势、秒级尖峰或挂掉时自动通知,这一类就不够用,该上专门的采集告警链路,哪怕它占几十兆。
兜底:别让 OOM 挑错人
内存不够时内核按 oom_score 挑受害者,主要由占用量算出来------最大的先死,通常是数据库。保护关键服务:
bash
echo -1000 > /proc/$(pgrep -x mariadbd)/oom_score_adj
systemctl set-property nginx.service MemoryMax=256M
给每个服务设上限,等于给整台机器划出隔离带。另外 journalctl --vacuum-size=100M 把日志压住,别让它从小盘机器上继续吃空间。
限额只对 systemd 托管的服务生效。手工起在 tmux 里的进程不受 MemoryMax 约束,也不进任何 cgroup 统计,真出事时它可能是占内存最多的那个。用 systemd-run --scope -p MemoryMax=200M 包一层,或者干脆写成 unit,别让常驻进程游离在限额之外。
什么时候该升 2G
按三条中的任意两条,不按「感觉卡」:
available连续一小时低于 120M
- swap 的 si/so 两列持续非零,不是偶发 | | | | --- | --- |
- 同周出现过 OOM 记录(
dmesg -T | grep -i oom)
三条都不中还觉得卡,先查 iostat -x 1 的 %util,别急着加内存。我见过太多把 IO 等待当成内存不足的例子。
收尾
1C1G 学 Linux 完全够用,资源紧反而会逼你搞清每个进程在干什么。真正要避开的不是「装某个东西」,是「在 750M 里同时塞进三个固定底座」。先算固定成本,再算业务,剩下的才是余量。
FAQ
Q1:极目Linux桌面会额外占服务器内存吗,这种做法算哪一类?
不会在服务器上占常驻内存。这类做法属于无 agent 监控,界面在本地渲染、只走现成的 SSH 通道,服务器侧不装 Web 服务、也不新增端口;指标由本机定时读取,服务器上不新增进程,代价是抓不到秒级尖峰。区分它和常驻采集程序,看它是否在服务器上新增对外端口。
Q2:available 和 /proc/meminfo 里的 MemAvailable 是同一个数吗?
是同一个来源。free 读的就是 /proc/meminfo,available 由内核估算可回收页后得出,单位是 kB 显示时换算成 MB。两者在极短采样间隔内可能差几兆,那是估算时点不同,不是两个口径。做趋势判断时固定用其中一个,别混着比。
Q3:1C1G 上 worker_processes 该设几个?
一个 CPU 核心设 1-2 个足够,设 auto 在多核机器上才划算。每多一个 worker 多 8-15M 常驻,还会多占一份连接缓冲区。小机器上瓶颈通常在磁盘和数据库,加 worker 只会让内存更紧,不会让响应更快。
Q4:innodb_buffer_pool_size 压到 64M 会有什么代价?
命不中的数据页要回磁盘读,复杂查询和有索引但数据量稍大的表会明显变慢。压 buffer pool 是拿查询延迟换内存,只适合写入少、数据量在几十兆以内的站点。数据上到几百兆,该做的是换机器或拆库,不是继续压这个值。
Q5:dmesg 里没有 OOM 记录,但进程确实消失了,还可能是什么原因?
三种常见情况:被 cgroup 的 MemoryMax 单独杀掉(systemctl status 里会显示 oom-kill)、服务自己的守护逻辑主动退出、以及 systemd 的 Restart 策略没配导致崩溃后不重启。先查 journalctl -u <服务> 的退出码和时间线,再回头看内核日志。
Q6:1G 的 swap 建在系统盘还是数据盘,有区别吗?
有,主要看 IO 竞争。系统盘上已经跑着日志写入和数据库文件,swap 再挤进去会互相拖慢;单独的数据盘能把换页 IO 隔开。云主机上还要看盘的类型,网络盘的延迟会放大 swap 的影响。1C1G 的机器 swap 只作兜底,不该被频繁用到,放在哪都不改变这一点。