一、问题现象
环境情况:Red Hat Enterprise Linux 6.9 、 Oracle 11g
数据库宕机需要手工启动服务器和监听,发现无法通过su - oracle、su oracle切换到oracle用户 ,执行后直接卡死,无报错、也不退出。
通过su - oracle -c 'bash --noprofile --norc'绕开环境变量登录也卡住。
最后发现sudo -u oracle /bin/sh 仅延迟20多秒,可以正常进入,常规检查:
- 非登录式切换、跳过环境配置的切换命令依旧卡死,排除用户环境脚本问题
- 服务器无资源爆满、无磁盘IO阻塞、主机名解析正常,常规排查无异常
新增共性故障:测试切换系统其他普通用户(如 test、ora11203等),全部出现相同卡死现象,并非 oracle 用户单独故障,证明是root全局环境异常导致的系统性问题,非单一用户配置故障。
二、排除常规故障点
为精准定位问题,我们逐层排除全网最常见的 su 卡顿原因,缩小故障范围。
1. 排除 /etc/hosts 主机名解析问题
su 登录式切换会反向解析主机名,DNS/hosts 配置错误是卡顿高发原因。检查本机配置:
|-------------------------|
| hostname cat /etc/hosts |
本机 hosts 已正确配置本机 IP+主机名,localhost 解析正常,彻底排除 DNS 解析阻塞问题。
2. 排除用户登录脚本阻塞
常规认知中,su - 加载登录环境(bash_profile/bashrc)、sudo 不加载,若脚本中有网络探测、挂载、休眠命令会导致卡顿。
本次测试:无参数普通切换 su oracle(不加载登录脚本)依然卡死,新增用户也卡死,排除用户环境脚本阻塞问题。
3. 排除 PAM 认证模块异常
依次检查 /etc/pam.d/su、/etc/pam.d/system-auth 配置:
bash
[root@yikuer ~]# cat /etc/pam.d/su
#%PAM-1.0
auth sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
# Uncomment the following line to require a user to be in the "wheel" group.
#auth required pam_wheel.so use_uid
auth include system-auth
account sufficient pam_succeed_if.so uid = 0 use_uid quiet
account include system-auth
password include system-auth
session include system-auth
session optional pam_xauth.so
[root@yikuer ~]# cat /etc/pam.d/system-auth
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth sufficient pam_fprintd.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth required pam_deny.so
account required pam_unix.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=3 type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
#session required pam_limits.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so
- 无 sssd、ldap、winbind 远程认证模块,纯本地认证配置
- 无 pam_systemd、异常会话模块
- 临时注释 pam_limits.so 资源限制模块,故障依旧
同时排查 lastlog、faillock 日志文件,文件大小正常、无损坏、无登录锁定,排除 PAM 认证与日志文件故障。
4. 排除系统服务与资源限制
依次重启 dbus、systemd-logind、nscd 等会话与解析服务,清空登录缓存,调整用户资源限制,故障均未恢复。
三、strace 抓包锁定根因
常规排查全部无效后,使用 strace 追踪系统调用,精准定位卡死环节:
|------------------------------------------------------------------------------|
| strace -tt -o su_trace su oracle # 卡住20秒后 Ctrl+C 终止,查看日志末尾 tail -30 su_trace |
bash
[root@yikuer ~]# tail -30 su_trace
02:24:49.865114 mprotect(0x7f80a5169000, 2093056, PROT_NONE) = 0
02:24:49.865217 mmap(0x7f80a5368000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x9000) = 0x7f80a5368000
02:24:49.865325 mmap(0x7f80a536a000, 61648, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f80a536a000
02:24:49.865438 close(5) = 0
02:24:49.865547 open("/oracle/glibc-2.14/lib/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)
02:24:49.865654 open("tls/x86_64/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)
02:24:49.865755 open("tls/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)
02:24:49.865857 open("x86_64/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)
02:24:49.865958 open("libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)
02:24:49.866061 open("/lib64/libglib-2.0.so.0", O_RDONLY) = 5
02:24:49.866165 read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300l\201\3174\0\0\0"..., 832) = 832
02:24:49.866266 fstat(5, {st_mode=S_IFREG|0755, st_size=1142944, ...}) = 0
02:24:49.866371 mmap(NULL, 3237912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7f80a4e48000
02:24:49.866475 mprotect(0x7f80a4f5d000, 2097152, PROT_NONE) = 0
02:24:49.866583 mmap(0x7f80a515d000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x115000) = 0x7f80a515d000
02:24:49.866692 mmap(0x7f80a515e000, 2072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f80a515e000
02:24:49.866794 close(5) = 0
02:24:49.867101 mprotect(0x7f80a5368000, 4096, PROT_READ) = 0
02:24:49.867374 mprotect(0x7f80a59e1000, 4096, PROT_READ) = 0
02:24:49.867584 mprotect(0x7f80a5c26000, 4096, PROT_READ) = 0
02:24:49.867903 set_tid_address(0x7f80a78899d0) = 15179
02:24:49.868000 set_robust_list(0x7f80a78899e0, 24) = 0
02:24:49.868096 futex(0x7fff1564a5bc, FUTEX_WAKE_PRIVATE, 1) = 0
02:24:49.868259 futex(0x7fff1564a5bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, 7f80a7889700) = -1 EAGAIN (Resource temporarily unavailable)
02:24:49.868377 rt_sigaction(SIGRTMIN, {0x7f80a57cfb40, [], SA_RESTORER|SA_SIGINFO, 0x7f80a57d95e0}, NULL, 8) = 0
02:24:49.868496 rt_sigaction(SIGRT_1, {0x7f80a57cfbc0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7f80a57d95e0}, NULL, 8) = 0
02:24:49.868579 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
02:24:49.868680 getrlimit(RLIMIT_STACK, {rlim_cur=10240*1024, rlim_max=RLIM64_INFINITY}) = 0
02:25:10.347868 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL, si_value={int=0, ptr=0x100000000}} ---
02:25:10.348168 +++ killed by SIGINT +++
关键异常日志:
|---------------------------------------------------------------------------------------------------|
| open("/oracle/glibc-2.14/lib/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) |
日志明确显示:su 切换用户时,系统动态链接器持续遍历 /oracle/glibc-2.14/lib 目录
root@yikuer \~# ls -ld /oracle/glibc-2.14/lib/
drwxr-xr-x 4 root root 4096 Mar 9 2022 /oracle/glibc-2.14/lib/
root@yikuer \~# ls -l /oracle/glibc-2.14/lib/libglib-2.0.so.0
ls: cannot access /oracle/glibc-2.14/lib/libglib-2.0.so.0: No such file or directory
该目录真实存在,但目录内缺失关键的 libglib-2.0.so.0 库文件。动态链接器会反复重试检索、遍历子目录匹配库文件,持续耗时20秒以上,最终表现为 su 命令卡死无响应。
四、su 卡、sudo 正常 原因
这是本次故障的核心关键点,也是最容易被忽略的运维盲区:
1. su 命令特性
su 会完整继承当前 root 终端的所有环境变量,包括畸形的 LD_LIBRARY_PATH。系统动态链接器 ld.so 会强制遍历环境变量中定义的所有库目录,目录不存在时会反复重试、遍历子目录,造成长时间阻塞卡死。
2. sudo 命令特性
sudo 具备安全净化机制,默认自动清空、过滤高危环境变量,主动丢弃错误的 LD_LIBRARY_PATH,不会遍历无效目录,因此仅轻微延迟、可以正常进入用户环境。
五、临时 及 永久 解决
1. 临时应急修复(立即生效)
清空当前 root 终端的异常库路径环境变量,即刻恢复 su 切换:
|----------------------------------------------|
| unset LD_LIBRARY_PATH LD_PRELOAD su - oracle |
执行后切换用户秒进,无任何卡顿,验证根因完全匹配。
2. 永久根治(彻底解决复发)
异常变量来源于 root 用户的开机自启配置,需彻底删除错误配置:
步骤1:定位异常变量配置文件
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| root@yikuer \~# grep -r "/oracle/glibc-2.14" /etc/profile /etc/profile.d/ /root/.bash* /root/.bash_history:../configure --prefix=/oracle/glibc-2.14 /root/.bash_history:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:LD_LIBRARY_PATH /root/.bash_history:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:LD_LIBRARY_PATH /root/.bash_profile:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH |
检索结果:异常路径写入了 /root/.bash_profile,每次 root 登录都会自动加载错误 LD_LIBRARY_PATH。
步骤2:删除错误配置
|---------------------------------------------------------------------------------------------------------------|
| # 一键删除异常行 sed -i '/\/oracle\/glibc-2.14\/lib/d' /root/.bash_profile # 重载配置,生效永久 source /root/.bash_profile |
步骤3:验证彻底修复
|-----------------------------------------|
| # 新开终端或直接执行,秒进无卡顿 su - oracle su oracle |
六、 环境变量 配置 glibc-2.14 的 原因
结合本次服务器历史操作命令:
bash
[root@yikuer ~]# history
493 tar -xf glibc-2.14.tar
495 cd glibc-2.14
498 ./configure --prefix=/oracle/glibc-2.14
499 make -j4
500 make install
503 cd /orcale
506 cd glibc-2.14/
509 export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH
510 strings /lib64/libc.so.6 |grep GLIBC_
539 strings /lib64/libc.so.6 |grep GLIBC_
540 mpstat
541 export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH
542 mpstat
543 vi ~/.bash_profile
544 source ~/.bash_profile
可以精准锁定本次手动编译 glibc-2.14、配置全局 LD_LIBRARY_PATH 的直接诱因:RHEL 6.9 系统自带 glibc2.12 版本过低,无法运行新版 mpstat压测工具
bash
[root@yikuer ~]# mpstat
mpstat: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by mpstat)
[root@yikuer ~]# export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH
[root@yikuer ~]# mpstat
Linux 2.6.32-696.el6.x86_64 (yikuer) 06/30/26 _x86_64_ (8 CPU)
05:43:45 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
05:43:45 all 0.50 0.01 0.11 0.09 0.00 0.00 0.02 0.00 0.00 99.26
1. 服务器原生系统限制
服务器系统为 Red Hat Enterprise Linux 6.9 ,系统原生自带 glibc 版本仅为 2.12 ,版本老旧、兼容性极差。大量新版压测工具、系统监控组件、第三方二进制程序、Oracle 附属工具,编译依赖 GLIBC_2.14 及以上版本符号,系统原生库完全无法满足。
2. 从历史日志 及客户沟通了解
当时完整操作流程如下:
- 首先通过 yum、源码包反复安装stress、sysstat 压力测试工具
- 运行 mpstat / pidstat / stress 等系统性能工具时,触发了 GLIBC_2.14 版本缺失报错
- RHEL6.9 官方 yum 源无高版本 glibc,无法通过 yum 升级补齐 GLIBC_2.14 依赖
- 因此手动下载 glibc-2.14.tar.gz 源码包
- 手动创建 build 编译目录,自定义安装路径:--prefix=/oracle/glibc-2.14
- 编译安装完成后,临时写入环境变量:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH
- 为了永久生效,写入 /root/.bash_profile
- 重新 source 加载,用于正常运行 stress、sysstat、监控工具
4. 故障的真相
- 业务测试结束后,客户清理操作:rm -rf glibc-2.14*
- 只删除了源码包、编译缓存
- 没有删除 /oracle/glibc-2.14/ 安装目录
- 没有删除 .bash_profile 中的 LD_LIBRARY_PATH 变量
- 久而久之目录残留、变量残留,但内部关键 .so 库文件缺失
- 最终导致:所有 su 切换用户触发 ld.so 遍历卡死
七 、故障复盘与运维总结
1. 故障根源
服务器为适配mpstat、 stress压测工具(依赖 GLIBC_2.14),在 RHEL6.9 原生 glibc2.12 不兼容的情况下,手动编译安装 glibc-2.14,并将库路径写入 root 全局环境变量实现临时兼容。压测实验结束后,仅删除了编译源码与临时文件,未清理全局 LD_LIBRARY_PATH 变量、未删除残留安装目录,导致系统动态链接器每次执行 su 切换用户时,遍历无效库路径反复重试,最终造成命令卡死。
2. 核心区别总结
- su:继承全部环境变量,无净化机制,易受异常变量影响卡死
- sudo:自动净化环境变量,规避大部分变量导致的卡顿问题
3. 运维避坑建议
- 临时测试的环境变量,切勿写入 root 全局开机配置,避免长期残留故障
- 遇到 su 卡顿、sudo 正常的差异化故障,优先排查 LD_LIBRARY_PATH 路径存在但库文件缺失的场景,这是极易被忽略的隐性故障点
- 常规排查无效时,优先使用 strace 追踪系统调用,精准定位阻塞环节,避免盲目排查
- 自定义编译系统依赖库后,需及时清理无用环境变量与残留配置