在RHEL 7以及之后的版本中,系统默认不再把崩溃产生的core文件直接写到程序的工作目录,而是由systemd-coredump统一接管。很多习惯了直接找core文件用gdb调试的工程师,升级到RHEL 8或RHEL 9后突然发现core文件不见了,第一反应往往是怀疑ulimit设置有问题,实际上多半是systemd-coredump把转储内容收集到/var/lib/systemd/coredump目录去了。理解这套机制并熟练使用coredumpctl工具,是RHEL环境下排查崩溃问题的一项基本功。

systemd-coredump的工作原理与内核配置
systemd-coredump的核心是一个安装在/usr/lib/systemd/systemd-coredump的二进制程序,它通过内核的pipe模式(core_pattern以竖线开头)来接收崩溃信息。当进程崩溃时,内核不再把内存映像写到磁盘文件,而是把转储数据通过管道交给systemd-coredump处理,由它压缩存储并建立索引。查看当前配置可以执行:
cat /proc/sys/kernel/core_pattern # 典型输出如下: # |%s %c %d %I %P %u %g %r %t %h %e
如果输出的第一个字符是竖线,说明systemd-coredump正在接管转储。同时还要确认/proc/sys/fs/suid_dumpable和进程的RLIMIT_CORE限制,systemd-coredump要求进程的core限制不能为0,否则转储会被直接丢弃。RLIMIT_CORE可以通过systemd的LimitCORE指令来控制:
# 为某个服务开启无限core systemctl edit httpd.service # 在打开的配置片段中写入: # [Service] # LimitCORE=infinity
修改后执行systemctl daemon-reload并重启服务即可生效。另外systemd服务默认还会装载/usr/lib/sysctl.d/50-coredump.conf来设置core_pattern,如果你手工修改了/proc/sys/kernel/core_pattern,重启后可能被覆盖回来,需要从sysctl配置文件入手才能持久化。
coredumpctl常用操作:列出、查看与导出
coredumpctl是管理崩溃记录的主命令。程序崩溃后,先用list子命令查看有哪些转储记录:
coredumpctl list coredumpctl list mysqld # 只看某个程序的记录 coredumpctl list --since=today # 只看今天的记录
输出列表中包含时间、PID、UID、信号、程序路径等信息,通常段错误对应SIGSEGV信号。找到目标记录后,用info子命令可以查看崩溃时刻的详细信息,包括崩溃时的执行上下文、栈顶信息、进程的cgroup归属等,这些元数据对判断崩溃场景非常有帮助:
coredumpctl info 12345 # 或者按程序名匹配最近一条 coredumpctl info /usr/sbin/mysqld
最实用的操作是直接进入gdb调试。coredumpctl debug会自动解压转储文件并启动gdb加载,不需要手工指定core文件路径:
coredumpctl debug 12345 # 进入gdb后常用命令 # bt full 查看完整回溯 # info threads 查看所有线程 # thread 2 切换线程
如果需要在别的机器上分析,可以用dump子命令把原始core导出成文件,再配合可执行文件和符号表离线调试:
coredumpctl dump 12345 -o /tmp/mysqld.core.12345 gdb /usr/sbin/mysqld /tmp/mysqld.core.12345
需要注意的是,导出的文件是解压后的原始core,体积可能比存储在/var/lib/systemd/coredump下的压缩文件大很多,注意预留磁盘空间。
存储限制与屏蔽systemd-coredump
systemd-coredump的存储策略由/etc/systemd/coredump.conf控制。其中LimitBytes限制单个转储的最大字节数,超限的转储会截断或直接丢弃;ProcessSizeMax限制待处理转储的上限,默认值为2G;ExternalSizeMax限制外置工具处理时的上限;MaxUse和KeepFree则分别控制/var/lib/systemd/coredump目录的最大占用和至少保留的磁盘空间。对于内存占用很大的数据库程序,默认2G的ProcessSizeMax经常导致崩溃后拿不到转储,需要调大:
# /etc/systemd/coredump.conf [Coredump] Storage=external Compress=yes ProcessSizeMax=16G ExternalSizeMax=16G JournalSizeMax=767M MaxUse=20G KeepFree=2G
修改后执行systemctl restart systemd-coredump.socket生效。Storage支持none、external和journal三种模式,none表示完全不落盘只留日志,journal则把转储压缩后塞进journal里。另外还有一个常见的坑:/etc/systemd/system.conf里的DumpCore设置,如果被配置为no,systemd本身派生的服务进程崩溃时可能不生成转储,排查时别漏掉这一项。
有些场景下(比如某些老旧的分析工具链依赖固定路径的core文件),你可能希望恢复传统的core文件生成方式,这就需要屏蔽systemd-coredump:
systemctl mask systemd-coredump.socket # 然后修改core_pattern为传统模式 echo 'core.%e.%p' > /proc/sys/kernel/core_pattern # 持久化写入/etc/sysctl.d/99-core.conf # kernel.core_pattern = core.%e.%p
mask掉socket后,systemd-coredump将不再被触发,内核会按core_pattern的文件模式把core写到进程工作目录。此时要确认shell会话的ulimit -c足够大,以及目录有写权限。事后想恢复systemd-coredump,执行systemctl unmask systemd-coredump.socket并把core_pattern改回竖线开头的管道模式即可。
排查崩溃问题的实用建议
结合实际运维经验,建议在RHEL系统上做好几件事。第一,确认Debuginfod或本地debuginfo包是否可用,崩溃发生在系统库内部时,没有符号信息的回溯基本没法看,可以安装对应的*-debuginfo包或者设置DEBUGINFOD_URLS环境变量在线拉取符号。第二,定期清理转储,/var/lib/systemd/coredump目录被塞满后新转储会失败,可以结合MaxUse限制或者用coredumpctl配合journalctl的vacuum机制清理:
journalctl --vacuum-time=7d # 也可以直接删除旧转储文件后重启systemd-journald
第三,对于容器内进程的崩溃,确认容器的core_pattern是否也指向宿主机的systemd-coredump,跨容器定位PID时要借助coredumpctl info中的PID和cgroup信息对齐宿主机与容器的进程视图。掌握这套流程后,从崩溃发生到拿到可用回溯,整个排查链条可以在几分钟内完成,比到处翻找core文件的效率高得多。
systemd-coredumpRHELcore dump修改时间:2026-09-09 13:42:56