theme: default themeName: "默认主题" title: "Linux服务器内存优化:从「内存不够用」到「内存用得好」"
Linux服务器内存优化:从「内存不够用」到「内存用得好」
「内存不够用,加内存!」——这是很多人遇到内存问题的第一反应。但我见过太多案例,加了内存之后问题依然存在,甚至更严重。因为内存不够用,不一定是内存真的不够,更可能是内存用得不对。
今天从实战角度聊聊Linux服务器内存优化,帮你把内存「榨干」用好,而不是一味地加硬件。
先搞清楚:Linux内存是怎么用的?
很多人看到`free -h`输出,发现`used`很高就开始慌:
total used free shared buff/cache available
Mem: 31Gi 18Gi 1.2Gi 512Mi 12Gi 12Gi Swap: 8Gi 2.0Gi 6.0Gi
别慌! 这里有个关键字段:`available`。
Linux的内存管理哲学是「空闲内存是浪费的内存」。系统会把空闲内存用来做文件缓存(buff/cache),提升IO性能。这部分内存在应用需要时会立刻释放。
所以真正需要关注的是:
- available:实际可用内存(free + 可回收的buff/cache)
- Swap used:如果Swap使用量持续增长,才是真的内存不足
# 查看内存使用趋势
vmstat 1 10
查看Swap使用情况
swapon -s
查看哪些进程占用内存最多
ps aux --sort=-%mem head -20
如果`available`长期低于总内存的10%,且Swap持续增长,才需要考虑加内存或优化应用。
内存优化实战技巧
技巧一:调整Swappiness
`swappiness`控制系统使用Swap的倾向,值越高越倾向于使用Swap,值越低越倾向于保留内存。
默认值是60,对于服务器来说太高了——频繁Swap会导致IO飙升,性能急剧下降。
查看当前值:cat /proc/sys/vm/swappiness
对于数据库服务器,建议设为1-10:
# 临时修改
sysctl vm.swappiness=10
永久修改
echo "vm.swappiness=10" >> /etc/sysctl.conf sysctl -p
注意:不要设为0,那样系统在内存极度紧张时可能直接OOM Kill进程,而不是用Swap缓冲。
技巧二:合理配置OOM Killer
OOM(Out Of Memory)Killer是Linux在内存耗尽时的「最后手段」——它会选择一个进程杀掉,释放内存。
问题是,OOM Killer的选择算法不一定符合你的预期,可能把你最重要的进程杀掉。
保护关键进程不被OOM Kill:# 设置oom_score_adj为-1000,永远不被Kill
echo -1000 > /proc/$(pidof mysql)/oom_score_adj
或者在systemd服务里配置
[Service] OOMScoreAdjust=-1000
让不重要的进程优先被Kill:
# 设置oom_score_adj为1000,优先被Kill
echo 1000 > /proc/$(pidof some-process)/oom_score_adj
技巧三:大页内存(HugePages)
对于数据库(MySQL、PostgreSQL、Oracle)和大内存应用,启用HugePages可以显著减少TLB(Translation Lookaside Buffer)缺失,提升内存访问性能。
原理:默认内存页大小是4KB,HugePages是2MB。管理2MB的页比管理512个4KB的页效率高得多。 配置HugePages(以MySQL为例):# 计算需要多少HugePages
MySQL innodb_buffer_pool_size = 16GB
16GB / 2MB = 8192 pages
设置HugePages数量
echo 8192 > /proc/sys/vm/nr_hugepages
永久配置
echo "vm.nr_hugepages=8192" >> /etc/sysctl.conf
MySQL配置:
[mysqld]
large-pages
实测在大内存数据库服务器上,启用HugePages后TPS可以提升10-20%。
技巧四:NUMA架构优化
现代多路服务器(双路、四路)使用NUMA(Non-Uniform Memory Access)架构,每个CPU有自己的本地内存,访问本地内存比访问远端内存快很多。
查看NUMA拓扑:numactl --hardware
问题:如果进程跨NUMA节点访问内存,性能会下降30-50%。
解决方案:把进程绑定到特定NUMA节点:
# 把MySQL绑定到NUMA节点0
numactl --cpunodebind=0 --membind=0 mysqld
或者在systemd里配置
[Service] ExecStart=numactl --cpunodebind=0 --membind=0 /usr/sbin/mysqld
对于Java应用,JVM有专门的NUMA支持:
java -XX:+UseNUMA -XX:+UseParallelGC -jar app.jar
技巧五:内存碎片整理
长时间运行的服务器,内存碎片会越来越严重,导致大块内存分配失败,即使`free`显示有足够内存。
查看内存碎片情况:cat /proc/buddyinfo
手动触发内存碎片整理:
# 清理页缓存
echo 1 > /proc/sys/vm/drop_caches
清理dentries和inodes缓存
echo 2 > /proc/sys/vm/drop_caches
清理所有缓存
echo 3 > /proc/sys/vm/drop_caches
注意:`drop_caches`会清理缓存,短时间内IO会增加,不要在高峰期执行。
更温和的方式:开启内存碎片整理守护进程:
echo 1 > /proc/sys/vm/compact_memory
技巧六:应用层内存优化
Java应用:# 设置合理的堆大小,不要超过物理内存的70%
java -Xms4g -Xmx4g -jar app.jar
使用G1GC,减少Full GC停顿
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar app.jar
开启JVM内存监控
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/gc.log -jar app.jar
Python应用:
# 使用生成器代替列表,减少内存占用
不好
data = [process(x) for x in large_dataset]
好
data = (process(x) for x in large_dataset)
Node.js应用:
# 设置最大堆大小
node --max-old-space-size=4096 app.js
内存监控告警
推荐监控指标:- `available`内存低于总内存15%:警告
- `available`内存低于总内存5%:严重
- Swap使用率超过50%:警告
- OOM Kill事件:立即告警
# alertmanager规则
- alert: MemoryLow
expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.15 for: 5m labels: severity: warning annotations: summary: "内存不足 {{ $labels.instance }}"
description: "可用内存低于15%,当前: {{ $value humanizePercentage }}"
写在最后
内存优化不是一蹴而就的事,需要根据业务特点和服务器配置综合调整。
优化优先级:1. 先确认是否真的内存不足(看available,不看used) 2. 调整swappiness,减少Swap使用 3. 保护关键进程不被OOM Kill 4. 根据应用类型启用HugePages或NUMA绑定 5. 应用层优化内存使用
记住:加内存是最后手段,不是第一手段。 先把现有内存用好,再考虑扩容。
【放心,我们兜底】
不管你是自己尝试修复,还是需要专业人员上门,易云城IT服务都给你托底。修不好不收费,修好了质保期内随时找我。
📞 服务热线:13708730161 💬 微信:eyc1689 📧 邮箱:service@eycit.com 🌐 https://www.eycit.com
您身边的IT专家。