SUSE系统SAP HANA内存不足排查与调优实战指南 接到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机制默认允许内存过量分配overcommitHANA会利用这一点申请比当前实际使用量更大的虚拟地址空间用来预留未来负载增长的空间。这套机制正常时没问题但一旦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到hdbcons2.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 memoryfree输出里最关键的三个指标是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 --allhdbcons的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物理内存256GBHANA没有配置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.swappiness10让内核尽量优先回收文件页缓存和匿名页不到万不得已不去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 MemoryLimit32G systemctl set-property SAPLateService SwapMax8G这样应用进程最多只能吃到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和sapconfSUSE针对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 sidadm soft memlock unlimited sidadm 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 21 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应用因为内存不足而不可用的问题大概率能在半小时内给出明确的方向。