Oracle 11g 容器"挂掉"两天查不出原因:最终定位是 processes=800 撞上 SGA 512M

奥黛丽·逐爱者
2026-11-05 / 0 评论 / 1 阅读 / 正在检测是否收录...

Oracle 11g 容器故障排查与处置记录

环境标识:某客户服务器 —— web-svr-01(内网)容器:oracle11g(镜像 lhrbest/oracle_11g_ee_lhr_11.2.0.4:1.0)数据库:Oracle 11.2.0.4 EE,SID ORCL,库容量 3.18 GB系统:Kylin Linux Advanced Server V10 (Tercel),内核 4.19.90,Hygon C86 7280 32 核,内存 30 GB处置日期:2026-11-05处置结果:✅ 已恢复并完成容器与参数改造


一、故障现象

连续两天(11-04、11-05)业务系统无法访问,表现为"数据库挂了",人工重启容器后恢复,但找不到原因。

故障时状态:

现象说明
容器 docker ps显示 Up,看不出异常
应用连接报 TNS-12505: TNS:listener does not currently know of SID
监听器lsnrctl status 正常,但实例未注册
数据库实例已经停止,但容器还活着(这是最容易误判的地方)

二、故障时间线(从 alert 日志与 audit 日志还原)

11-04 上午          业务侧报告第一次"挂掉"11-04 12:08:51      docker stop oracle11g(SIGTERM → 10 秒未退出 → 强制 SIGKILL,退出码 137)11-04 12:18:08      实例启动,出现 "parallel recovery started with 7 processes"(崩溃恢复)11-04 14:42:35      开始大量 ORA-00600 [spstp: ORACLE_HOME uid does not match euid]11-04 15:00~23:00   每小时 57~72 次,非常稳定11-05 00:00~06:00   每小时 53~55 次,06:00 突增到 107 次11-05 07:19:46      最后一次 ORA-00600(累计 1192 次)11-05 07:21:13      再次 docker stop → 强制 SIGKILL → 07:21:22 实例重启11-05 07:36:06      ⚠️ 同事执行:ALTER SYSTEM SET processes=800 SCOPE=SPFILE;                              ALTER SYSTEM SET job_queue_processes=20 SCOPE=SPFILE;11-05 11:23         运维排查中执行 shutdown immediate11-05 11:28         强制删除旧容器,实例未关完 → 产生 2 条 ORA-00600 [ksb_shut_detached_process3]11-05 11:29         新容器创建,startup 失败:ORA-00821(SGA 太小)11-05 12:00         用 pfile 覆盖参数后启动成功 → Database opened11-05 12:05         参数写回 spfile(processes=300 / job_queue_processes=100)11-05 12:08         优雅关闭验收通过(>>> 数据库已关闭)11-05 12:15         SGA 扩至 2G、PGA 扩至 512M,重启生效11-05 12:30         磁盘治理:根分区 86% → 61%

三、根因分析

3.1 直接原因:参数改错导致实例无法启动

spfile 中:processes = 800           sga_target = 512M启动报错:ORA-00821: Specified value of sga_target 512M is too small,                     needs to be at least 620M

800 个进程所需的 SGA 固定结构(ksl/kss 等)至少需要 620M,而 SGA 只有 512M,实例直接拒绝启动。

后果链条:

实例起不来 → 监听器独立运行(lsnrctl 单独启动的)           → 客户端连进来时找不到 SID → TNS-12505           → 应用全部无法连接 → 业务中断           → 但容器主进程是 tail -F,容器仍显示 Up           → 运维误判"数据库在跑,只是应用有问题"

3.2 为什么"重启就好"

同事 07:36 的 ALTER SYSTEM 是 SCOPE=SPFILE,只写入了参数文件,要重启才生效。之前的每次重启用的都是当时 spfile 里"还没生效"的旧值(processes=300),所以看起来"重启即恢复"。

直到本次真正重启,800 才生效 → 直接起不来。

3.3 历史 ORA-00600(独立问题,已消失)

11-04 14:42 ~ 11-05 07:19 共 1192 次:

ORA-00600: internal error code, arguments:  [spstp: ORACLE_HOME uid does not match euid], [500], [0]影响进程:j000(作业从进程)、w000(空间管理)、cjq0(作业队列)、m000(MMON 从进程)

性质:实例派生子进程时,ORACLE_HOME 属主 uid(500)与子进程 euid(0)不一致,被 Oracle 拒绝。后果:所有定时作业、空间管理等后台任务全部瘫痪(不影响普通连接)。现状:容器重建后彻底消失,至今零新增(1192 是历史累计值)。

3.4 已排除的原因(避免误判,附证据)

怀疑项排除证据
内存 OOMOOMKilled=false、RestartCount=0、内核 OOM 记录为空、memory.failcnt=0、容器峰值仅 747 MB
内存不足SGA 512M + PGA 78M,30 GB 内存,MemAvailable 长期 15 GB+
磁盘满/data 19%,归档目录不存在堆积
setuid 位导致audit 显示 11-04 00:00~14:00 全是 euid=0,但当时数据库完全正常,非触发条件
外部作业(EXECUTABLE)dba_scheduler_jobs 全是 PLSQL_BLOCK/STORED_PROCEDURE,dba_scheduler_credentials 为空
数据库自行崩溃alert 日志无 Shutting down instance、无致命 ORA 错误;两次退出均为 signal 15(docker stop 发起)

3.5 暴露出的容器设计缺陷

原 command 结尾是:

tail -F listener.log alert_ORCL.log    # ← 容器主进程是 tail,不是数据库

导致:1. 数据库死了容器仍显示 Up → restart: always 完全失效2. docker stop 只杀 tail → 10 秒后 SIGKILL 整个容器 → 每次停库都要崩溃恢复3. hostname 随容器变化 → 重建容器后 tail 找不到日志路径 → 秒退重启循环


四、处置步骤

4.1 应急恢复:用 pfile 覆盖参数启动

# ① 宿主机写 pfile(注意:docker exec 不带 -i 时 heredoc 会丢失,必须在宿主机写)cat > /tmp/init_fix.ora <<'EOF'spfile=/u01/app/oracle/product/11.2.0.4/dbhome_1/dbs/spfileORCL.oraprocesses=300job_queue_processes=100EOF# ② 拷入容器docker cp /tmp/init_fix.ora oracle11g:/tmp/init_fix.oradocker exec oracle11g cat /tmp/init_fix.ora       # 必须确认有内容!# ③ 启动docker exec -u oracle oracle11g bash --norc -lc \  "echo 'startup pfile=/tmp/init_fix.ora' | sqlplus -S / as sysdba"

结果:

ORACLE instance started.Database mounted.Database opened.        ← 服务恢复

4.2 参数永久写回 spfile

docker exec -u oracle oracle11g bash --norc -lc "echo 'alter system set processes=300 scope=spfile;alter system set job_queue_processes=100 scope=spfile;exit' | sqlplus -S / as sysdba"

⚠️ 多条 SQL 必须换行写,写在一行用 ; 分隔会报 ORA-00911: invalid character。

4.3 容器改造(核心)

新建 /data/oracle11g/entrypoint.sh:

#!/bin/bashexport ORACLE_SID=ORCLterm_handler() {  echo ">>> 收到停止信号,正在优雅关闭数据库..."  su - oracle -c "export ORACLE_SID=ORCL; sqlplus -S / as sysdba <<SQLshutdown immediateexitSQL"  su - oracle -c "lsnrctl stop" 2>/dev/null  echo ">>> 数据库已关闭"  exit 0}trap term_handler TERM INTsu - oracle -c "export ORACLE_SID=ORCL  lsnrctl start  sqlplus -S / as sysdba <<SQLstartupexitSQL"tail -F \  /u01/app/oracle/diag/tnslsnr/$(hostname)/listener/trace/listener.log \  /u01/app/oracle/diag/rdbms/orcl/ORCL/trace/alert_ORCL.log &TAIL_PID=$!wait $TAIL_PID

docker-compose.yml:

version: '3.6'          # docker-compose 1.22 最高支持 3.6(写 3.8 会报 unsupported)services:  oracle11g:    image: registry.cn-hangzhou.aliyuncs.com/lhrbest/oracle_11g_ee_lhr_11.2.0.4:1.0    container_name: oracle11g    hostname: oracle11g              # 关键:固定主机名,否则重建后 tail 找不到日志    restart: unless-stopped    stop_grace_period: 120s          # 给数据库 2 分钟优雅关闭    environment:      - TZ=Asia/Shanghai      - ORACLE_SID=ORCL      - NLS_LANG=AMERICAN_AMERICA.AL32UTF8    ports:      - "1521:1521"    volumes:      - /usr/share/zoneinfo:/usr/share/zoneinfo:ro      - /etc/localtime:/etc/localtime:ro      - /data/oracle11g/app:/u01/app      - /data/oracle11g/entrypoint.sh:/entrypoint.sh:ro    entrypoint: ["/bin/bash", "/entrypoint.sh"]    healthcheck:      test: ["CMD-SHELL", "su - oracle -c \"echo 'select 1 from dual;' | sqlplus -S / as sysdba\" | grep -q 1"]      interval: 60s      timeout: 20s      retries: 3      start_period: 300s    logging:      driver: json-file      options: { max-size: "50m", max-file: "3" }    networks:      - ixjkj_networknetworks:  ixjkj_network:    external: true

切换时注意:旧容器是别的 compose 项目创建的,docker-compose down 会提示 Found orphan containers 且删不掉,必须 docker rm -f oracle11g 再 docker-compose up -d。

4.4 性能参数优化

经评估:库仅 3.18 GB,buffer cache 命中率已达 99.0%(逻辑读 1,221,524 / 物理读 13,081),命中率不是瓶颈,但原 SGA 512M 撑不起多进程且共享池偏小。

参数原值调整后说明
sga_max_size512M2G上限,需重启生效
sga_target512M2GDatabase Buffers 约 1.44G
pga_aggregate_target78M512M原值过小,排序会写临时表空间
processes800(起不来)300历史验证可用的值
docker exec -u oracle oracle11g bash --norc -lc "echo 'alter system set sga_max_size=2G scope=spfile;alter system set sga_target=2G scope=spfile;alter system set pga_aggregate_target=512M scope=spfile;exit' | sqlplus -S / as sysdba"

重启后验证:

Total System Global Area 2,137,886,720 bytes  (~2G)  Database Buffers      1,509,949,440 bytes  (~1.44G)  Variable Size           620,758,936 bytes  (~590M)

4.5 磁盘治理

操作释放说明
swap 从 /swapfile 迁到 /data/swapfile8 GB原 swap 建在根分区,误占系统盘
删除 3 天前的 cron-2026xxxx 归档~2 GB/var/log 中每天 180M
# swap 迁移swapoff /swapfilefallocate -l 8G /data/swapfile && chmod 600 /data/swapfilemkswap /data/swapfile && swapon /data/swapfilesed -i '\|^/swapfile |d' /etc/fstabecho '/data/swapfile none swap sw 0 0' >> /etc/fstabrm -f /swapfile# 日志清理find /var/log -maxdepth 1 -name "cron-2*" -mtime +3 -delete

结果:根分区 86% → 61%(剩 15 GB)。

4.6 参数基线备份

# spfile 二进制备份docker exec -u oracle oracle11g bash --norc -lc \  'cp /u01/app/oracle/product/11.2.0.4/dbhome_1/dbs/spfileORCL.ora \      /u01/app/oracle/product/11.2.0.4/dbhome_1/dbs/spfileORCL.ora.baseline.$(date +%F)'# 可读参数清单导出docker exec -u oracle oracle11g bash --norc -lc \  "echo \"create pfile='/tmp/baseline.ora' from spfile;\" | sqlplus -S / as sysdba"docker cp oracle11g:/tmp/baseline.ora /root/oracle_ORCL_baseline_$(date +%F).ora

注意:docker cp 在 Docker 18.09 下不支持中文文件名(tar USTAR 编码限制),一律用英文名。


五、改造前后对比

项目改造前改造后
docker stop 停库10 秒后 SIGKILL,每次崩溃恢复trap 捕获 → shutdown immediate → 干净关闭
数据库死了容器状态永远 Up(tail 撑着)healthcheck 标记 healthy/unhealthy
容器重建hostname 变化 → tail 找不到日志 → 秒退循环hostname: oracle11g 固定
容器日志无限制50m × 3 轮转
自动拉起restart: always 形同虚设unless-stopped + 可感知健康状态
SGA512M2G
PGA78M512M
swap0(后加 8G 在根分区)8G,位于 /data
根分区86%61%

六、监控与自动化

6.1 已部署的三个定时任务

*/5  * * * * /root/ora_watch.sh        # 数据库无响应时抓现场快照到 /root/ora_incident/*/10 * * * * /root/ora_guard.sh        # 数据库无响应时自动重启容器(带优雅关闭)30   * * * * /root/ora_perm_check.sh   # bin/oracle 权限被改则自动纠正为 751

6.2 日常巡检脚本 /root/ora_check.sh

一条命令输出:容器状态、实例状态、会话/进程数、表空间使用率、归档区、错误计数(累计/新增)、系统资源、自动处置记录。

/root/ora_check.sh

关注三点:容器 healthy、实例 OPEN、【6】错误计数新增 = 0。


七、运维红线(必须遵守)

禁止正确做法
❌ docker-compose down 停数据库✅ docker restart oracle11g(已有 stop_grace_period 保护)
❌ docker exec -u root ... sqlplus / as sysdba 后 startup✅ docker exec -u oracle oracle11g ... 或以 oracle 身份启动
❌ 多条 SQL 用 ; 连成一行✅ 每条独立一行,或用 SQL 文件 @/tmp/x.sql
❌ 手工 chmod/chown 动 $ORACLE_HOME✅ 有需求先报备,改完跑 ora_perm_check.sh 复核
❌ 直接替换 spfile 或用 root 复制 spfile✅ 先备份,改完确认属主是 oracle:oinstall、权限 640
❌ 单改 processes 不调 SGA✅ processes 每 +100 约需 +40M SGA,必须同步调整并重启验证
❌ 用 rm 删正在写入的日志✅ 用 : > file 清空(进程持有句柄)

八、遗留事项

事项状态建议
数据库未开归档NOARCHIVELOG,无 PITR 能力行业业务建议开启:alter system set db_recovery_file_dest_size=20G; shutdown immediate; startup mount; alter database archivelog; alter database open;(约 2 分钟停机)
cron 日志 180M/天会持续占用根分区检查 crond 是否带 -x 调试参数,或把每分钟任务的输出重定向掉
job 203 已删除原 PR_AUTO_DELDATA() 因 log_user=SYS 无法解析而报 ORA-12012若业务需要自动清理,重建时用带 schema 前缀的 APP_SCHEMA.PR_AUTO_DELDATA();
tomcat 每天 01:00 自动重启crontab 中有 0 1 * * * systemctl restart tomcat.service说明应用侧本身不稳,需单独排查 catalina/应用日志
容器无 privileged/shm-size当前 SGA 2G 可正常运行若后续继续调大 SGA,需加 shm_size 或 --ipc=host

九、经验总结

  1. docker ps 显示 Up 不等于数据库活着——容器主进程若是 tail/sleep 之类的守护命令,数据库死了容器照样 Up。必须配 healthcheck。
  2. SCOPE=SPFILE 的参数改动是"定时炸弹":改的当下看不出问题,下次重启才爆炸。改完必须评估影响并择机验证重启。
  3. Oracle 参数之间有强关联:processes 与 sga_target 必须匹配,单改一个很可能起不来(ORA-00821)。
  4. ORA-00821 的排查路径:先看 alert 日志尾部,直接告诉你需要多少 SGA,比猜快得多。
  5. docker exec 的两个坑:不带 -i 时 heredoc 内容丢失;不经 shell 时通配符不展开、$VAR 不解析。
  6. 停库前先优雅关闭,否则每次都要崩溃恢复;而优雅关闭的前提是容器入口脚本能捕获 SIGTERM。
  7. 日志、swap、镜像都要"放对分区":swap 8G 建在 40G 的系统盘上,直接把根分区推到 86%。

十、最终状态验收

检查项结果
容器Up (healthy)
实例OPEN,26 个会话,应用已自动重连
SGA / PGA2G / 512M
processes300(spfile 已固化,可正常重启)
优雅关闭✅ 验收通过(日志出现 >>> 数据库已关闭,无 SIGKILL)
ORA-00600零新增(1192 条为历史)
TNS-125050
根分区61%(剩 15 GB)
swap8G,位于 /data
自动恢复ora_watch(5m) + ora_guard(10m) + perm_check(1h) 已启用
参数备份spfile.baseline + pfile 导出均已保存

本文记录一次真实的 Oracle 11g 容器故障排查全过程,涉及 OOM 排除、SGA/processes 关联、容器健康检查改造等实战经验。

0

评论 (0)

取消