ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Linux核心转储配置指南:从core_pattern到systemd-coredump的完整实践

Linux核心转储配置指南:从core_pattern到systemd-coredump的完整实践 简介《转储配置.pdf》是一份面向SAP物料管理MM模块顾问、实施人员及系统维护者的SAP转储配置实操详解聚焦采购订单与库存运输订单的常见配置痛点。压缩包内为1个PDF文档大小3.36MB内容结构清晰适合本地查阅。该资源已有171人学习阅读价值获得初步验证。文档从事务代码OMH6设置的采购订单编号范围入手逐步展开采购订单类型配置事务代码OMEU、跳号问题解决通过SNRO关闭缓冲、报表查询按类型分类、定价方案差异化配置以及通过T160M/V_160M设置错误提示与价格差异限制等关键环节同时涉及采购订单审批机制、价格与物料法定价格差异的提示规则、后台配置点OMF4等并配有使用SE16直接修改视图的实际操作经验。对于需要在SAP系统中搭建或优化转储配置尤其是处理库存运输订单类型划分、编号跳号、采购价格管控等难题的读者可直接参考其中的配置路径与操作技巧。1. 转储配置系统崩溃时唯一能留住现场的手段看到《转储配置.pdf》这个名字你大概已经猜到它讲的是 Linux 核心转储coredump的配置方法。这份文档解决的场景很窄但很痛某天凌晨业务进程段错误退出日志里只有一句 signal 11你连崩溃时的调用栈都拿不到只能靠猜。转储配置就是为这种时刻准备的——它让内核在进程崩溃瞬间把内存快照写下来之后用 gdb 打开崩溃那一帧的代码、参数、调用链全都在里面。适合所有被线上诡异崩溃折磨过的 Linux 运维、SRE 和后端开发者。如果你系统里出现过“未配置任何 coredump 目标。无法保存主机核心转储”这类提示这篇文章正好能帮你把缺口补上。2. 先看懂转储链路内核信号、core_pattern 与 systemd-coredump 的三方协作2.1 崩溃信号与内存映像转储能存下什么进程不是平白无故消失的。以最常见的段错误为例x86_64 上访问非法地址触发 CPU 异常内核在异常处理路径里向进程发送 SIGSEGV默认动作是“终止并清理”。但在真正清理之前内核会先检查这个进程是否允许产生 core dump允许就执行 do_coredump 流程把内存映像写出去。这里有三道闸门。第一道是信号类型能触发转储的通常是有 core 动作的信号包括 SIGSEGV、SIGABRT、SIGBUS、SIGILL、SIGFPE、SIGTRAP 这些但 SIGKILL 和 SIGSTOP 不会产生 core因为这两个信号默认动作里根本没有“写转储”这个环节。第二道是资源限制进程的 RLIMIT_CORE 为 0 时无论信号多标准内核直接放弃转储。第三道是 dumpable 标志进程通过 setuid 降权、或者调用 prctl(PR_SET_DUMPABLE, 0) 之后内核会认为这个进程的内存不值得信任拒绝把它写入磁盘。三道闸门全过core 文件才会落地。那 core 文件里到底有什么进程地址空间中可读写的匿名内存、共享内存映射、寄存器上下文、程序头信息以及当时打开的文件描述符和命令行参数。简单说就是进程在崩溃瞬间的完整“内存快照”。栈上残留的局部变量、堆上还没被清零的对象、调用链每一层的返回地址全被原样保留。gdb 拿到它能还原出崩溃时刻的程序计数器位置和完整调用栈这就是转储配置的价值所在。有时候你会发现同一个程序有时候崩出 core有时候崩不出差别往往不在信号而在 coredump_filter。这个文件控制哪些内存段会被写进转储默认值已经覆盖匿名私有内存、匿名共享内存和 ELF 文件头映射。Java 这类动不动就映射大块内存的程序转储文件经常有几 GB就是因为它把整个堆都算进了匿名内存。理解这一点你才能解释为什么同一个配置C 服务转储只有几百 MBJava 服务却能写满磁盘。2.2 core_pattern 与内核参数转储目标由谁决定真正决定“内存快照往哪送”的是内核参数 kernel.core_pattern它写在 /proc/sys/kernel/core_pattern 里改一次立即全局生效。传统写法是给一个路径模板比如/var/crash/core.%t.%p.%e这里的 %t、%p、%e 叫模板符内核在落盘时按实际情况替换。常用模板符如下模板符含义示例值%p崩溃进程 PID3312%u崩溃进程 UID1000%g崩溃进程 GID1000%t崩溃时刻的 epoch 秒1720000000%e可执行文件名不含路径nginx%h主机名web-01%s触发崩溃的信号编号11%c当前 core 文件大小限制unlimited生产环境我习惯用 %t.%p.%e 三段组合。%t 保证不同时间崩溃的文件不重名%p 防止同一秒内多个进程崩溃时互相覆盖%e 让你一眼看出是哪个程序出了问题。只写 %e 的话两个同名进程先后崩溃会把前一个文件盖掉这种教训在真实环境里不少见。如果 core_pattern 以 | 字符开头内核就不再写文件而是把转储内容通过管道交给后面的程序由那个程序决定怎么存。现代发行版默认正是这么干的core_pattern 被指向 systemd-coredump内核职责止步于“把内存快照吐给管道”后续的存储、压缩、元数据记录全交给用户态的 systemd 组件。顺便说一句跟 core_pattern 配套的还有 core_uses_pid 和 core_pipe_limit。前者是旧时代的产物在没有模板符的年代把 PID 直接拼在文件名末尾现在用不用都行后者控制并发转储时的管道排队策略多进程同时崩溃时如果发现转储偶发丢失值得查一下这个值是不是被改成了很小的数。大多数情况下你只需要盯住 core_pattern 一个参数就够了。2.3 systemd-coredump默认托管者与两代方案对比RHEL 8/9、Ubuntu 18.04 之后的发行版默认把 core_pattern 指向 systemd-coredump形如|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %h %esystemd-coredump 做的事有三件把 core 写入 /var/lib/systemd/coredump/把崩溃进程的元数据信号、PID、命令行、环境变量摘要写进 journal然后对 core 文件做压缩。用户用 coredumpctl list 就能看到所有转储记录不用自己翻目录拼路径这是它比传统路径模板强的地方。两代方案的主要差别对比项传统路径模板systemd-coredump配置入口kernel.core_pattern/etc/systemd/coredump.conf文件命名自定模板符直观按 systemd 规则生成崩溃元数据完全没有写入 journalcoredumpctl 可查文件压缩不压缩默认压缩省空间gdb 前处理直接打开需要先解压或确认格式排查入口自己 ls 目录coredumpctl list 统一查选型没有绝对对错我自己的习惯是测试环境用传统路径模板崩溃后 ls 一眼就能看到文件调试路径短生产服务器走 systemd-coredump 托管因为它的元数据记录对事后追查太有用了——你不仅知道崩了还知道崩之前命令行是什么、环境变量是什么。但它也有个让人不舒服的地方文件是压缩的直接 gdb 会报格式不识别这个坑第四章会专门讲。3. 动手配置一套可落地的转储方案参数、命令与验证起点这一章给的是可以直接抄的作业。从检查现状到写配置每一步的命令和参数都摆在下面照做就能把转储配置跑通。完整验证放第五章但本章末尾会给你一个最小确认手段确保配置没白写。3.1 动手前先查三处现状别上来就改# 1) 当前转储目标模板确认是文件路径还是管道 cat /proc/sys/kernel/core_pattern # 2) 当前 shell 下 core 文件大小限制0 表示禁止转储 ulimit -c # 3) systemd-coredump 是否在运行 systemctl status systemd-coredump.socket --no-pager | head -10 # 4) 转储目录所在分区的剩余空间 df -h /var/crash /var/lib/systemd/coredump 2/dev/null这四个命令的输出决定后续动作。如果 core_pattern 已经被清空或者指向了一个不存在的管道程序系统诊断时就会弹出“未配置任何 coredump 目标。无法保存主机核心转储”。这行提示看着吓人但它只说明一件事内核不知道把转储交到谁手里。 如果 ulimit -c 显示 0别急着怀疑内核先把限制解开再试。注意 ulimit 是 shell 内建命令只对当前 shell 及其子进程生效通过 systemd 启动的服务根本不看它服务进程看的是 /proc/ /limits 里的 Max core file size。3.2 传统文件路径方案用 sysctl 写模板假设我们决定走传统方案目标目录定为 /var/crash# 临时修改立即生效重启后丢失先验证配置本身 sysctl -w kernel.core_pattern/var/crash/core.%t.%p.%e sysctl -w kernel.core_uses_pid1 # 持久化写入 /etc/sysctl.d/ 下独立文件 echo kernel.core_pattern/var/crash/core.%t.%p.%e /etc/sysctl.d/99-coredump.conf echo kernel.core_uses_pid1 /etc/sysctl.d/99-coredump.conf # 重载全部 sysctl 配置并确认结果 sysctl --system cat /proc/sys/kernel/core_pattern这段命令的逻辑是先用 -w 在运行态立即改验证配置本身有没有问题确认无误后再把同样内容写进 /etc/sysctl.d/ 下的独立文件。独立文件的优势是升级系统时不会跟发行版自带的 /etc/sysctl.conf 冲突后缀 99 保证它的优先级排在默认配置之后。core_uses_pid 设成 1 是双保险模板符里已经有 %p二者不冲突但有些老脚本只看这个参数设上能让它们少报一个错。提示修改 /etc/sysctl.d/ 下的文件不会自动生效必须执行sysctl --system重载否则重启前配置还是旧的。目录权限这一步经常被忽略。/var/crash 如果不存在内核创建文件会失败权限不对非 root 进程崩溃时也没法写。我一般这样处理mkdir -p /var/crash chmod 1777 /var/crash用 1777 而不是 755是为了让任何用户启动的进程都能把 core 写进来同时权限位里的 sticky bit 能防止普通用户互相删文件。如果你担心安全问题可以改成 1733 并把目录属主设成专用账号但绝大多数内部服务器用 1777 就够了。3.3 systemd-coredump 方案只动覆盖文件别改主配置如果发行版默认就走 systemd-coredump我的建议是不要去改写 core_pattern 指向自己的脚本而是在 /etc/systemd/coredump.conf.d/ 下加一个覆盖文件mkdir -p /etc/systemd/coredump.conf.d cat /etc/systemd/coredump.conf.d/99-local.conf EOF [Coredump] Storageexternal Compressyes ProcessSizeMax2G ExternalSizeMax2G EOF systemctl daemon-reload systemctl restart systemd-coredump.socket这里四个参数是核心。Storageexternal 表示 core 文件写入 /var/lib/systemd/coredump/journal 只留元数据如果设成 journal二进制 core 会被直接塞进日志一个 1G 的转储就能把默认大小的 journal 撑爆。Compressyes 是默认行为转储文件压缩后通常只有原来的三分之一到五分之一代价是 gdb 前要处理压缩格式。ProcessSizeMax 限制参与转储的进程最大内存映像超过则不转储ExternalSizeMax 限制压缩后输出文件的最大尺寸防止超大进程把磁盘写满。生产上这两个值参考你的业务内存设定Java 服务几百 GB 堆的话2G 显然不够要按实际情况调。改完配置后用下面的命令确认覆盖文件真的被读到了systemctl show systemd-coredump.socket --propertyListen systemd-analyze cat-config systemd/coredump.conf第一条确认 socket 正常监听第二条把生效配置完整打印出来如果 99-local.conf 的内容没出现在输出里说明文件放错位置或者语法有问题。3.4 服务进程的转储限制LimitCORE 与参数速查传统方案和 systemd 方案解决的都只是“内核把转储写到哪”但服务进程自己设的限制能直接掐断整条链路。通过 systemd 启动的 nginx、java、PostgreSQLshell 里敲 ulimit 根本影响不到它们必须在 unit 文件的 [Service] 段里写[Service] LimitCOREinfinity EnvironmentULIMIT_COREunlimitedLimitCOREinfinity 把进程的硬限制和软限制都放开服务崩溃时内核才允许转储。改完记得 systemctl daemon-reload 再重启服务否则不生效。这条是服务类进程转储“完全不生效”的头号原因比 core_pattern 写错还要常见因为很多人只查了内核参数没查进程自身的限制。常用转储配置参数速查参数所在位置作用常用值kernel.core_pattern/proc/sys/kernel/core_pattern转储目标路径或管道/var/crash/core.%t.%p.%ekernel.core_uses_pid/proc/sys/kernel/core_uses_pid文件名附加 PID1Storagecoredump.conf [Coredump]转储存储模式externalCompresscoredump.conf [Coredump]是否压缩转储yesProcessSizeMaxcoredump.conf [Coredump]参与转储的进程内存上限2GExternalSizeMaxcoredump.conf [Coredump]转储文件输出上限2GLimitCOREsystemd unit [Service]服务进程 core 限制infinity配完这一套跑一次最小验证新开一个 shell执行 ulimit -c unlimited然后运行 python3 -c import ctypes; ctypes.string_at(0)程序会立即段错误退出。接着看你的方案对应目录里有没有新增 core 文件有就说明链路通了没有就继续看下一章问题多半在那几个坑里。4. 转储配置避坑5 个反复出现的“不生效”现场这一章全部来自血泪经验。很多所谓转储配置的玄学问题拆开看都能归到下面五类按现象对号入座就行。4.1 系统提示“未配置任何 coredump 目标。无法保存主机核心转储”现场跑诊断脚本或系统巡检工具时输出里直接出现这句同时 /proc/sys/kernel/core_pattern 指向的管道程序根本不存在或者被某个初始化脚本写成了空。原因core_pattern 里的管道目标路径写死了但机器之间发行版不同systemd-coredump 的位置并不统一。有人在 RHEL 上把路径写死为 /usr/lib/systemd/systemd-coredump换到别的发行版就成了死路径更常见的是某个初始化脚本执行 sysctl -w kernel.core_pattern 想“关闭核心转储”结果留下一个无法判定的空目标诊断工具只能报这个提示。处理先用 command -v 确认 systemd-coredump 的真实路径再把它写回 core_patternCORE_PIPE$(command -v systemd-coredump) sysctl -w kernel.core_pattern|$CORE_PIPE %P %u %g %s %t %h %e echo kernel.core_pattern|$CORE_PIPE %P %u %g %s %t %h %e /etc/sysctl.d/99-coredump.conf sysctl --system如果 command 没有输出说明系统根本没装 systemd-coredump那就退回传统路径模板方案把 3.2 的配置写进去。反过来如果你确实想关闭核心转储正确做法是写成指向 /bin/true 的管道或者直接设置 Storagenone别把参数清空。4.2 core 文件完全没生成日志里连痕迹都没有现场用会段错误的小程序测试退出码是 13912811但 /var/crash 和目标目录空空如也journal 里也没有任何 coredump 记录。原因进程的 RLIMIT_CORE 是 0。shell 直接运行的进程ulimit -c 默认在很多发行版就是 0systemd 启动的服务则要看 /proc/ /limits 里的 Max core file size。最容易误判的点在于你已经在 ssh 会话里敲了 ulimit -c unlimited但那只是当前 shell 和它的子进程其他会话和系统服务根本不继承这个设置。处理先看真实运行进程的限制grep Max core file size /proc/实际pid/limits对服务进程在 unit 文件 [Service] 段补 LimitCOREinfinitydaemon-reload 后重启服务。对临时测试必须在同一个 shell 里先执行 ulimit -c unlimited再启动被测进程两个动作不能在两个会话里分开做这是新手最容易踩的坑。4.3 core 文件生成在进程工作目录预期目录里没有现场配置写的是 kernel.core_patterncore.%p崩溃后文件出现在进程的工作目录systemd 服务的工作目录通常跟着 ExecStart 路径走你翻遍了 /var/crash 也找不到。原因core_pattern 里写的是相对路径。内核遇到相对路径时以崩溃进程的 cwd 为基准创建文件而服务进程的 cwd 往往不是你以为的 /var/crash。3.2 里强调写绝对路径就是为了绕开这个坑——绝对路径下任何进程崩溃都往一个固定位置写不依赖 cwd。处理把 core_pattern 改成绝对路径同时检查目标目录的 SELinux 上下文。很多 CentOS/RHEL 机器只改了路径没管 SELinux结果是 core 文件创建失败journal 里出现 avc denied 记录。用下面两个命令排查cat /proc/sys/kernel/core_pattern grep avc.*denied /var/log/audit/audit.log | tail -20如果是 SELinux 拦截执行 restorecon -Rv /var/crash 恢复目录上下文或者用 semanage 给转储目录打上正确的类型标签。4.4 coredumpctl list 有记录但转储文件不在预期目录现场配好 systemd-coredump 后用 coredumpctl list 能看到崩溃记录但 /var/lib/systemd/coredump 下找不到任何文件journal 分区占用却涨得飞快。原因coredump.conf 的 Storage 被设成了 journal。这个模式下 systemd-coredump 把整个 core 当作 journal 字段写进日志不生成独立文件。journal 里的二进制数据没法直接交给 gdb而且 journal 空间有上限一个 2G 的转储就能把默认配置的 journal 挤爆顺带影响系统其他日志的正常写入。处理改成 external 或 bothcat /etc/systemd/coredump.conf.d/99-storage.conf EOF [Coredump] Storageexternal EOF systemctl daemon-reload systemctl restart systemd-coredump.socket改完后再触发一次崩溃用 coredumpctl info 查看新记录的存储模式确认已变成 external。旧记录不受影响但也不值得去抢救重新触发一次更干净。4.5 gdb 打不开 core文件存在但报 file format not recognized现场core 文件名称对、大小也合理但 gdb 打开时报“不是 core 文件”用 file 命令一看是一份 zstd 或 xz 压缩数据。原因systemd-coredump 默认对转储做压缩而传统路径模板方案不压缩。很多人拿到 core 文件习惯性直接 gdb没注意文件后缀和 magic number自然打不开。处理先用 file 判断真实格式再解压后分析file /var/lib/systemd/coredump/core.xxx zstd -d /var/lib/systemd/coredump/core.xxx.zst -o /tmp/core.xxx gdb /path/to/binary /tmp/core.xxx如果 team 里所有同事都习惯直接 gdb可以把 Compress 设为 no 省去每回解压代价是磁盘占用上升。我个人保留压缩把解压动作写进调试脚本因为磁盘被几个 5G 的未压缩 core 塞满时你会后悔当初的偷懒。5. 转储配置完成后怎么验证从模拟崩溃到自动化巡检配置写完了不验证等于没配。一套转储配置没经过真实崩溃检验永远不知道会在哪个环节断掉。这一章从手动触发到定时巡检给出能直接用的命令和脚本。5.1 用一段会崩溃的小代码模拟真实场景不推荐用 kill -s SIGSEGV $$因为 shell 对自身信号的处理可能绕过内核默认动作测试结果不可信。用 Python 一行就能触发标准段错误# 触发一次空指针解引用进程退出码应为 139128SIGSEGV python3 -c import ctypes; ctypes.string_at(0)验证按顺序执行四步在当前 shell 执行 ulimit -c unlimited运行上面的 Python 命令记住退出码必须是 139 才说明是 SIGSEGV 崩溃传统方案看 ls -l /var/crash/ 是否新增 core 文件systemd 方案执行 coredumpctl list 看是否有新记录用 file 命令确认生成文件的类型是 ELF core如果显示 compressed data回到 4.5 处理。如果第 3 步就断了回到第四章按现象排查如果第 4 步异常多半是压缩配置和调试工具链不匹配。这一步能排掉 90% 的“配置文件改了但等于没改”的情况。5.2 二次验证确认服务进程的转储链路是通的有些场景下系统级配置是通的但业务进程因为是 systemd 服务启动有自己的 rlimit 设置比如 Java 服务。针对这种情况验证的重点是 /proc/ /limits 里的实际值而不是 shell 里的 ulimitpid$(systemctl show -p MainPID --value 服务名) grep Max core file size /proc/$pid/limits输出应该是 unlimited。如果显示 0说明 unit 文件里的 LimitCORE 没生效或没重启回到 3.4 处理。这一步做完了还可以用 gdb attach 到进程发一个 SIGSEGV 来触发转储——但千万别在生产环境这么干测试环境和预发环境做一次就够了。验证结束后记得把临时加的 LimitCORE 和 ulimit 恢复原状别为了查一个问题把所有进程的 core 都开放了。5.3 自动化巡检一条脚本定时摸底转储配置最容易出现的问题不是配置错而是“没人动它自己坏了”——发行版升级、初始化脚本重置、磁盘挂载点变化都会悄悄改掉配置。我通常把巡检写成一个脚本丢给 cron 每日跑脚本内容如下#!/usr/bin/env bash # 转储配置巡检检查 core_pattern、进程限制、磁盘空间与 coredump 状态 # 用法./check_coredump.sh [服务名] SERVICE${1:-} echo core_pattern 当前值 cat /proc/sys/kernel/core_pattern echo 转储目录磁盘空间 df -h /var/crash /var/lib/systemd/coredump 2/dev/null | awk NR1 || /\// if [ -n $SERVICE ]; then pid$(systemctl show -p MainPID --value $SERVICE) if [ $pid ! 0 ]; then echo ${SERVICE} (pid${pid}) 的 core 限制 grep Max core file size /proc/$pid/limits else echo 服务 $SERVICE 未运行 fi fi echo 最近 10 条转储记录 coredumpctl list --no-pager 2/dev/null | head -10脚本三个点值得说明一是 coredumpctl 在没有安装 systemd-coredump 的机器上会报错所以加了 2/dev/null 和 head 限制输出条数二是 df 命令用 awk 只过滤转储目录相关的行避免无关挂载点干扰判断三是传服务名时用 systemd 的 MainPID 拿实际 pid比手动 ps grep 更可靠。cron 里可以这样写10 4 * * * /usr/local/bin/check_coredump.sh nginx /var/log/coredump-check.log 21每天凌晨跑一次输出重定向到日志文件只要 core_pattern 不再指向预期值看一眼日志就能发现。5.4 健康判据什么样的巡检结果算正常对巡检输出我按三个信号判断当前转储配置是否健康core_pattern 非空且指向绝对路径或真实存在的管道程序对主要服务/proc/ /limits 的 Max core file size 是 unlimited转储目录剩余空间大于计划保留的转储文件总大小的两倍。这三条全过才敢说这台机器的转储配置可信。如果只过了前两条但空间不足反而比不配更危险——core 写一半磁盘满了和滚雪球一样把其他服务拖垮。所以巡检脚本里我会把磁盘占用单独拎出来超过阈值直接告警而不是等转储失败再去翻日志。6. 进阶从转储文件里快速挖出崩溃函数配置和验证都通畅之后真正要面对的是最后一个问题core 拿到了怎么快速从里面挖出崩溃点。我的日常工作流分三步。第一步确认二进制与 core 匹配。同一个程序的不同构建版本core 不能混用动态库版本变了gdb 也会报加载错误。先看格式、再解压最后才打开file /var/lib/systemd/coredump/core.nginx.*.zst zstd -d /var/lib/systemd/coredump/core.nginx.*.zst -o /tmp/core.nginx第二步用 gdb 打开并取栈。对带符号的二进制这一下就能看到崩溃函数、参数值和寄存器状态gdb -q /usr/sbin/nginx /tmp/core.nginx -ex bt -ex info registers rip -ex quitbt 输出的是崩溃瞬间的调用栈从最新一帧往旧帧看最上面的函数就是事发地。如果栈被破坏info registers rip 能告诉你程序计数器最后停在哪条指令。多线程程序的情况更复杂最先崩溃的往往是某个工作线程不是主线程所以我会先执行 thread apply all bt 把全部线程栈导出到文件再逐个分析。第三步把分析流程封装成脚本。我习惯在 ~/.bashrc 里放一个函数输入程序和 core 文件路径一键打印崩溃栈core_analyze() { local bin$1 core$2 file $core | grep -q compressed zstd -d $core -o /tmp/core.tmp gdb -q $bin /tmp/core.tmp -ex thread apply all bt -ex quit }这套习惯帮我省下无数次“core 文件传回本地却打不开”的返工。最后给一句劝告core 文件是进程完整内存映像密码、密钥、用户数据全在里面转储目录一定要限制权限、定期清理别把后悔药变成泄密口。配好转储后按第五章做一次完整验证让这份《转储配置.pdf》真正成为团队遇到段错误时的第一顺位排查手段。希望帮到你。本文还有配套的精品资源点击获取
返回列表