接到SUSE服务器上SAP业务不可用的告警,登录系统一看,free显示物理内存被吃干净了,swap也几乎占满,SAP HANA进程状态异常,应用侧报"系统内存不足"。这个场景在SAP HANA的Linux运维里太典型了——HANA是出了名的内存大户,但很多时候问题并不是HANA本身不够用,而是Linux内存管理、HANA内存参数、甚至是同机其他进程抢占资源共同作用的结果。
这篇文章把我处理SUSE系统上SAP HANA内存不足的完整排查链路和解决方案整理出来,覆盖从系统层到HANA层的诊断手段、内核参数调优、HANA内存参数配置,以及后续的监控预防。无论你是刚接手SAP HANA运维的Linux工程师,还是被"内存不足"故障反复折磨的DBA,这篇都能直接拿来当排查手册用。
1. HANA为什么总把机器内存吃光:先搞清楚内存去哪了
1.1 HANA的内存模型决定了它是"内存贪婪者"
SAP HANA本质上是内存数据库,它的核心数据全部驻留在物理内存里,这和传统的MySQL、Oracle那种以磁盘数据文件为主、内存作为缓存的工作方式有本质区别。HANA启动之后,会把列式存储的数据表、索引、数据版本管理、redo log缓冲区、SQL执行计划缓存等全部放进内存,一套完整的数据集加载完,几百GB内存见底是很正常的事。
更关键的是,HANA的内存分配策略非常"激进"。它不像普通应用那样等分配失败才报错,而是倾向于在启动和加载数据阶段就把内存圈占完整。Linux的malloc机制默认允许内存过量分配(overcommit),HANA会利用这一点申请比当前实际使用量更大的虚拟地址空间,用来预留未来负载增长的空间。这套机制正常时没问题,但一旦HANA运行时真的有大量数据加载或复杂查询并发进入,预留空间被迅速消耗,系统物理内存就见底了。
从实际操作来看,用free命令看内存使用,只能看到整体层面的内存分布,真正想搞清楚HANA的内存到底分给了谁,得去看HANA自己的内存视图。
1.2 最容易忽略的"隐形占用":同机非HANA进程和内核内存
我处理过很多这类故障,处理完之后发现一个规律:大部分"内存不足导致SAP不可用"的现场,机器上不只有HANA一个数据库,还跑着SAP应用服务器(比如S/4HANA的ABAP应用实例),以及一些配套的监控代理、文件同步进程、数据库客户端工具。这些进程平时看着不起眼,每个只占几个GB,加起来往往就把HANA和操作系统之间的缓冲区间吃光了。
另外还有一个隐形占用项经常被忽略——Linux内核本身和文件页缓存(page cache)。SUSE系统上HANA存储持久化文件时,内核会把这些文件读写入操作产生的页缓存留在内存中,这部分内存在内存压力增大时理论上可以被回收,但如果内核的回收优先级设置得不够激进,或者进程正在频繁进行文件I/O,页缓存的回收速度赶不上内存消耗速度,系统就会先触发swap,再触发OOM Killer。
还有hugepages。HANA在SUSE上默认开启大页内存支持,大页是启动时预先分配好的,不会像普通页那样可以回收。如果hugepages分配多了,普通内存池可用的部分就变少,反过来如果分少了,HANA内部的大页需求得不到满足,又会导致内存分配效率下降。这是一个需要精细平衡的点,后面实战部分我会给出具体配法。
1.3 环境因素:SUSE系统参数和虚拟化平台的双重影响
SUSE Linux Enterprise Server for SAP Applications相比通用SLES,多了sapconf和saptune这套自动调优工具,可以自动应用SAP HANA推荐的内核参数。但很多系统管理员在部署HANA时为了图省事,直接装完操作系统就手动改了内核参数,没用saptune,导致一些关键参数没有生效,比如vm.max_map_count不够大、kernel.shmall设置过小,这些参数在内存负载高时会成为压垮系统的最后一根稻草。
虚拟化平台的影响也值得一提。如果HANA跑在VMware或者云平台上,虚拟机内存超量分配(memory overcommit)是常态,宿主机物理内存一旦吃紧,就可能出现虚拟机内部的"内存气球"机制生效,把虚拟机内存强制回收一部分。这种场景下SAP HANA会表现为内存莫名其妙减少、数据库性能骤降,但你在虚拟机内部的free命令里看不到明确的内存泄漏——这是排查时最容易让人绕弯子的地方。
2. SAP应用报"内存不足"的完整排查链路:从free到hdbcons
2.1 第一板斧:看系统整体内存分布和swap情况
接到告警后,第一件事不是重启服务,而是尽可能多地收集现场信息。以下这组命令组合起来能快速给出系统内存的宏观画像:
# 当前内存总量、已用、可用、swap使用 free -g # 内存和swap的详细使用分布 cat /proc/meminfo # 按内存使用量排序,找出占用TOP 15的进程 ps aux --sort=-%mem | head -n 15 # 查看系统OOM事件记录 dmesg -T | grep -i "out of memory"free输出里最关键的三个指标是available、buff/cache和Swap used。available代表系统实际可用内存(已经考虑回收潜力),它如果掉到10%以内就要高度警惕;swap used持续升高说明内存压力已经真实存在,并且系统开始用磁盘来兜底,HANA在这种状态下性能会大幅下降。
有时候SAP报错信息写的是"Not enough physical memory available",但free看下来available明明还有几十GB。这种情况往往是SAP应用服务器自己配置的Java堆内存或ABAP内存参数超标,和操作系统层面不是同一个概念,不要把这两类问题混在一起查。
2.2 第二板斧:检查HANA进程状态和内部内存视图
HANA进程如果被OOM Killer杀了,SAP应用连接数据库必然报错。但更多时候HANA进程还活着,只是内部内存分配失败,这种情况靠系统命令看不出来,必须进入HANA内部看。
# 查看HANA各进程状态 sapcontrol -nr 00 -function GetProcessList # 进入HANA诊断shell su - hdbadm hdbcons "mm l --all" hdbcons "mm g --all"hdbcons的"mm l --all"输出HANA整体内存分配情况,重点看几个区域:Column Store是列式存储主数据区,Row Store承载行式表,Total Used表示HANA已使用的总内存。如果Total Used持续逼近HANA配置的memory_limit(默认可能是机器物理内存的90%),说明HANA内部确实到了瓶颈。
再执行下面的命令可以看到更细粒度的分配:
hdbcons "mm g memory --all" hdbcons "mm l -allocdump"另外,HANA Studio的Administration界面里有一个"Memory"页签,能直观看到Allocated Memory、Used Memory、Peak Used Memory三条曲线的走势。我在排障时依赖这个视图比依赖free更多,因为它直接反映的是HANA数据库实际吃的内存,而不是操作系统层的统计。
2.3 第三板斧:翻aler日志和trace文件,定位OOM触发的根因
HANA运行过程中出现内存不足,会在/diagnostics/hdb/log/目录下的trace文件里留下大量异常分配记录。用下面命令可以快速定位:
cd /hana/shared/HDB/hdb00/trace/ ls -lt *.trc | head -5 grep -i "memory" *.trc | grep -i "error" | tail -30同时关注HANA的aler日志:
tail -n 200 /hana/shared/HDB/hdb00/trace/alert_*.logOOM相关的内容会以"Out of memory"、"Memory allocation failed for multi-size class"这类字样出现。一旦出现多size class分配失败,几乎可以断定HANA进程在申请内存时系统层面没有可用物理内存了,属于综合因素导致的资源耗尽,不是HANA单方面的问题。
2.4 一个典型恶性循环案例:HANA占满内存,swap兜底后又被拖垮
我遇过最典型的一次故障是这样的:一套S/4HANA 1909,物理内存256GB,HANA没有配置memory_limit,默认按90%左右去占。白天业务高峰时大量查询并发,HANA内存飙到230GB,系统free剩不到10GB。此时同一台机器上的SAP应用服务也在增长内存,触发swap开始写入。swap一用起来,HANA性能下降,SQL变慢,连接堆积,应用进程内存继续涨,swap持续增高,最终整个系统变得几乎不可用,SAP前台完全无法操作。
这轮故障里的"SAP应用不能使用"其实是连锁反应,源头是内存资源配置策略没有隔离好。单纯给HANA调参救不了,必须给每类进程划定清晰的资源边界。
3. 解决内存不足的六类有效手段:参数、隔离、回收
3.1 给HANA配置合理的内存上限:memory_limit和statement memory limit
数据库层面,最直接的做法是在global.ini里为HANA配置内存上限,避免它无限占用物理内存:
[memorymanager] memory_limit = 180G statement_memory_limit = 20Gmemory_limit设置的是HANA实例可以使用的最大内存总量(包含所有主要区域),它必须留出足够余量给操作系统和其他应用,一般建议不超过物理内存的75%-85%。statement_memory_limit是限制单条SQL语句最大能使用的内存,这个参数特别重要,一条没写好join的报表SQL可以把整个HANA内存打穿,设了这个上限后最多只废掉那一条statement,不会影响全局。
需要注意的是,确定memory_limit之前先去查一下HANA快照表里的历史峰值:
SELECT * FROM M_MEMORY_RECORDINGS ORDER BY TIME DESC LIMIT 30;再结合业务增长趋势来定,不要凭感觉拍脑袋。设置太低会导致实际业务内存需求得不到满足,设置太高起不到保护作用。
3.2 开启swap做兜底,但控制好swapiness
很多SUSE管理员为了防止swap拖累HANA性能,把swap完全关掉。但实际生产经验告诉我,swap不是不能用,而是要控制使用策略。完全不配swap的风险在于:瞬时内存尖峰时连缓冲的机会都没有,OOM Killer直接触发,整个SAP应用瘫痪。配了适量的swap,遇到尖峰还能靠短期置换扛过去,给运维留出干预窗口。
推荐的做法:
- 配置swap为物理内存的1/4到1/2,放在独立存储上(不要和HANA数据文件同盘)。
- 设置vm.swappiness=10,让内核尽量优先回收文件页缓存和匿名页,不到万不得已不去swap。
# 创建swap文件(以256GB物理内存为例,划64GB) fallocate -l 64G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo "/swapfile none swap sw 0 0" >> /etc/fstab3.3 控制同机其他进程的内存占用,划定明确的资源边界
HANA机器上如果不是HANA独占(只有HANA一个工作负载),就必须给其他进程划定资源边界。做法是使用systemd的MemoryLimit控制单元,或者用cgroup直接对进程组做约束。举个例子,如果机器上运行着SAP NetWeaver应用服务,可以对它的服务单元做如下限制:
systemctl set-property SAPLateService MemoryLimit=32G systemctl set-property SAPLateService SwapMax=8G这样应用进程最多只能吃到32GB,不会继续蚕食给HANA预留的内存池。同理,监控代理、备份工具、sshd这类基础进程,如果确认内存占用异常,也可以逐个排查并合理约束。
3.4 手工内存回收与连接数压降:应急三板斧
故障发生时,如果确认HANA本身还活着,但系统内存被page cache和僵尸进程占掉大片,可以尝试手收集内存:
# 清页缓存和inode缓存(HANA场景下谨慎使用) echo 3 > /proc/sys/vm/drop_caches # 终止内存异常的僵尸或失控进程 ps aux --sort=-%mem | head -n 10drop_caches可以把文件页缓存释放出来,但需要注意,HANA的column store如果正高频访问数据,page cache释放后短时间内性能会下降,这个操作尽量放在业务低峰或者SAP连接已经大量报错、业务客观上不可用的阶段做。如果确认是某条应用进程内存失控导致整体雪崩,该kill的进程不要心软,先恢复系统可用度,再排查原因。
3.5 调整内核参数:overcommit和hugepages的正确用法
Linux内核的vm.overcommit_memory参数决定了malloc大内存请求的批准策略。HANA官方SAP Note 2382423明确推荐的是:
vm.overcommit_memory = 0也就是"启发式overcommit",内核根据内存当前状态决定是否批准malloc请求。有些管理员为了"保险"把它调成2(禁止overcommit),结果HANA启动时申请预留内存被拒绝,直接起不来或者运行中报内存分配失败。这个参数在HANA场景下不要乱调,默认0就对了。
hugepages的典型配置如下(以物理内存256GB为例,如果确认HANA列存数据主力内存在160GB量级,可以按130GB-150GB来分配大页):
# 计算大页数量(每页2MB) python3 -c "print(int(150*1024/2))" # 期望结果76800 # 永久配置 cat /etc/sysctl.d/99-hana-hugepages.conf vm.nr_hugepages = 76800配置完大页后需要确保HANA用户有锁内存的权限,否则大页还是起不了作用:
# /etc/security/limits.d/99-hana.conf @hanauser soft memlock unlimited @hanauser hard memlock unlimited设置完重启HANA实例使memlock生效。大页分配过多的情况下,普通内存池剩余不足,也可能间接引发OOM,所以这个值要对着HANA实际内存记录来定,不要拍脑袋。
3.6 saptune和sapconf:SUSE针对SAP负载的官方调优实践
处理SUSE系统问题,saptune是绕不开的工具。这个工具的价值在于集中应用和维护SAP HANA推荐的内核参数,避免一个人一个改法、越改越乱的局面。
# 查看当前支持的调优方案 saptune solution list # 为HANA数据库应用方案 saptune solution apply HANA # 查看实际生效的参数 saptune solution verify HANA # 自启动及服务状态 systemctl enable --now saptune.servicesaptune应用之后会自动管理一组与内存相关的重要参数,包括但不限于vm.max_map_count、kernel.shmall、kernel.shmmax、vm.vfs_cache_pressure。在它管理范围内的参数,不要手动去改sysctl,否则saptune下一次verify时会报"参数与方案不一致",回头还得用saptune reconcile把它拉回来。有saptune兜底,内存相关的内核参数才能保持在一个经过SAP官方验证的稳定状态。
4. 实战配置清单:一套SUSE系统上HANA内存优化的完整方案
4.1 假设环境参数与目标
假设物理机内存192GB,单实例HANA 2.0,同机跑一个SAP应用服务实例(限制48GB),页面缓存及系统余量约15GB,目标给HANA划定约120GB可用内存空间。接下来给出整套配置文件。
4.2 内核参数配置文件
# /etc/sysctl.d/99-saphana.conf vm.max_map_count = 2147483647 vm.swappiness = 10 vm.overcommit_memory = 0 vm.vfs_cache_pressure = 50 kernel.shmall = 4194304 kernel.shmmax = 17179869184 vm.nr_hugepages = 64000 net.core.rmem_max = 134217728 net.core.wmem_max = 134217728应用与确认:
sysctl --system sysctl vm.nr_hugepages注意sysctl --system执行后hugepages会立即尝试分配,如果内存已经被HANA占用,可能会导致分配失败,报"No space left on device"之类。生产环境建议在HANA维护窗口期做hugepages变更,先停HANA、再调参数、再启动HANA。
4.3 HANA用户内存锁限制
# /etc/security/limits.d/99-hanauser.conf sapadm soft memlock unlimited sapadm hard memlock unlimited <sid>adm soft memlock unlimited <sid>adm hard memlock unlimited其中sapadm是SAP Host Agent运行用户, adm是实际HANA实例管理用户,比如s4hadm。改完后需要验证ulimit生效:
su - s4hadm ulimit -l unlimited4.4 global.ini中的内存区域划分
[memorymanager] memory_limit = 120G statement_memory_limit = 12G allocation_limit = 120G use_huge_pages = on huge_alloc_limit = 96G [internal_communication] enabled = onmemory_limit和allocation_limit同时配置时,后者用于限制分配器直接malloc的最大量,一般和memory_limit保持一致或略高一点。use_huge_pages开启后,确定huge_alloc_limit的值不要超过系统配置的nr_hugepages对应的容量(上面64GB大页对应约131GB容量,配置96G比较安全)。不然HANA内部使用大页时发现系统预留不够,反而转向普通内存,失去大页的地址翻译优势。
4.5 同机应用进程的cgroup限制
# 创建独立控制组 mkdir -p /sys/fs/cgroup/sap_apps echo 48318382080 > /sys/fs/cgroup/sap_apps/memory.max echo "PID" > /sys/fs/cgroup/sap_apps/cgroup.procs如果使用systemd托管服务,可以直接用systemctl set-property做持久化限制,这样重启后还能保留。
4.6 验证整体方案生效
free -g cat /proc/meminfo | grep -i "huge" su - s4hadm hdbcons "mm g --all"上面这套配置在多个项目中落地过,稳定运行后HANA能长期保持在"内存占用受控但不会可用内存被吃干"的状态。只要内存limit设置合理,业务负载变化时SAP应用不会因为HANA把内存占完而无法连接。
5. 内存故障后的复盘与日常防御:从"救火"到"防火"
5.1 必看的几类关键日志和监控指标
每处理完一次SAP HANA内存不足故障,不要在业务恢复之后就当没事发生。复盘阶段必看以下几个信息:
- HANA trace日志里内存分配失败的记录,分析是瞬时尖峰还是趋势性增长。
- 系统层面OOM Killer的触发记录,确认哪个进程被杀、当时内存top进程是谁、触发前后swap的增长曲线。
- 业务侧SQL执行日志,确认是否有大查询、大报表在故障时间点并发执行。
- saptune verify的结果,确认内核参数在故障前后是否有漂移。
日常监控建议至少盯住三个指标:HANA的Used Memory与memory_limit的比值(超过85%预警)、系统available内存(低于15%预警)、swap使用增长速率(持续上升预警)。这三个指标组合在一起,基本能提前预判到故障风险。
5.2 一键脚本采集异常现场的技巧
为了下次故障时不再手忙脚乱找信息,可以先准备一个快速dump脚本,在告警时一条命令收集完所有关键信息:
#!/bin/bash TS=$(date +%Y%m%d_%H%M%S) DIR=/tmp/mem_${TS} mkdir -p $DIR free -g > $DIR/free.txt cat /proc/meminfo > $DIR/meminfo.txt ps aux --sort=-%mem | head -n 20 > $DIR/process.txt dmesg -T | grep -iE "oom|out of memory" > $DIR/oom.txt 2>&1 cat /sys/fs/cgroup/memory.max 2>/dev/null > $DIR/cgroup.txt echo "done: $DIR"脚本可以在系统crontab里挂一条每分钟执行的检测:
* * * * * /root/scripts/mem_check.sh当可用内存低于阈值时自动调用采集脚本并告警。这样遇到问题时,已经有完整现场素材供排查,不用一边看告警一边去现找数据。
5.3 与业务侧约定内存基线:明确谁的负载变化会引发风险
HANA内存不足往往不是运维单方面能根治的,业务侧的数据量增长、新报表上线、月末批量任务并发都会直接影响内存水位。运维侧可以建立一个简单规则:每月对比HANA内存历史峰值(M_MEMORY_RECORDINGS里都有),如果连续两个月峰值增长超过10%,就要提前评估是否需要扩容或者调优。
这类"月度内存水位对比"可以在HANA Studio或SQL客户端里执行:
SELECT * FROM M_MEMORY_RECORDINGS WHERE TIME > ADD_DAYS(CURRENT_TIMESTAMP, -30) ORDER BY TIME DESC;把结果导出来做趋势分析,比单纯看free直观得多。HANA的内存使用不是线性增长的,定期记录峰值能帮你更早发现异常突增。
5.4 最后分享几个实际运维中踩过的特殊坑
内存领域有几个容易误导人的"假象",我专门列出来提醒各位:
- 不要只看free的"used"列,available才是真实可分配内存。
- HANA的Peak Used Memory不等于当前游离内存,某些大查询执行完后内存可能不会立即归还给OS,这是HANA内存池化的特性,不代表泄漏。
- 不要贸然使用drop_caches清内存,如果HANA正承载业务,清page cache带来的短期性能抖动可能比内存不足本身影响还大。
- 修改hugepages之前务必确认HANA当前的大页使用量,分配过多会浪费内存,分配过少则HANA退回到普通页分配模式,地址翻译开销上升,性能结算下来未必划算。
- 云平台虚拟化环境里,即使虚拟机内部free显示还有上百GB可用,宿主机内存超卖导致气球挤占时,HANA一样可能出现分配失败,这类问题要从虚拟化集群的资源调度策略上去解。
处理Linux系统上SAP HANA内存不足,说到底是一套组合拳——HANA侧的内存限制、系统侧的swap和hugepages策略、以及其他进程的资源隔离,三者缺一不可。先按这套链路排查,再根据实际场景微调参数,SAP应用因为内存不足而不可用的问题,大概率能在半小时内给出明确的方向。