ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Oracle EBS R12.1生产部署排错:ORA-12547与adpatch

Oracle EBS R12.1生产部署排错:ORA-12547与adpatch

简介:围绕Oracle EBS R12.1.1至R12.1.3生产环境部署整理的一册技术文档,面向具备Linux与Oracle数据库基础、负责EBS安装配置与维护的IT技术人员,重点解决从操作系统准备到应用服务器上线的全流程落地问题。压缩包仅含1个PDF文件,体积约844KB,便于随身查阅和按目录检索,内容以图文步骤、配置说明和常见问题处理为主线。已有953人学习,说明其在EBS部署场景中具备一定参考价值。文档按Linux系统安装与配置、EBS安装升级、数据库升级、应用服务器部署等模块展开,并穿插远程登录、文件传输、网络地址、主机域名、硬盘挂载、防火墙等环境配置细节,同时给出安装升级过程中的排错思路。读者可据此梳理生产环境部署顺序、核对关键配置项,并在遇到版本升级或环境准备问题时快速定位处理方向。

1. 装完就跑不起来:Oracle EBS R12.1 生产环境部署最费时间的不是安装

Oracle EBS R12.1 的生产环境部署,真正耗时间的从来不是 Rapid Install 那根进度条,而是装完之后一个接一个冒出来的报错。R12.1.1 装完只是起点,后面还要把应用升到 R12.1.3、数据库升到 11.2.0.4、应用服务器升到 10.1.3.5,中间任何一步顺序错、环境变量串了、权限位丢了,最后都会变成一个看起来毫不相干的错误码——ORA-12547、FRM-92050、ORA-20011,随便一个都能让人对着屏幕坐一下午。折腾过几轮的人都有共识:EBS 的安装是一次性的,排错是长期的,而且这些报错之间是有因果链的,前面一步没做干净,后面三步全在还债。这篇排错笔记面向正在做 R12.1 生产部署、已经被某个错误卡住的同学,从操作系统准备一路讲到补丁收尾,把每个坑的触发条件、根因和能直接抄的命令摊开。

2. ORA-12547: TNS:lost contact:连不上数据库时的四层排查顺序

这个报错出现的时机非常固定:装完数据库跑完 root.sh、第一次用sqlplus / as sysdba登录,或者刚打完补丁重启完数据库。字面意思是"连接丢失",于是绝大多数人的第一反应是去查监听器、查防火墙、查网络,查了两个小时发现监听器状态明明好好的。

它最有迷惑性的地方就在名字里那个 TNS——十次里有七八次,这玩意儿跟 TNS 配置一点关系都没有。搞清楚它到底断在哪一层,比背十条解决方案管用。

2.1 先分清是"连不上"还是"连上了又死掉"

客户端连数据库分两步走:第一步连监听器,第二步由监听器 fork 一个服务器进程接管会话。第一步失败报的是 ORA-12541(没有监听器)或 ORA-12514(监听器不认识这个服务名),这两类才是真正的网络和配置问题。ORA-12547 出现在第二步之后——监听器已经接单了,请求也转下去了,但服务器进程没能把会话建立起来就退了。

所以看到 12547,可以直接把网络排查这条路砍掉,转头看服务端进程的启动条件。判断方法很简单,走一次不走监听的本地连接做对比:

# 本地连接,不经过监听器,直接走 IPC sqlplus / as sysdba # 走监听器连接,用同一个实例做对照 sqlplus system/<密码>@PROD

如果本地直连也报 12547,问题百分之百在服务器进程的启动环境上,监听器是无辜的;如果本地直连能进、只有走监听报错,那才轮到listener.ora和tnsnames.ora出场。

注意:本地直连测试前先确认$ORACLE_SID是目标实例,不然你测的是另一个库,结论会完全跑偏。

在 EBS 这种一套系统里同时存在 DB 层和应用层两套环境变量的场景下,ORACLE_HOME被别的 shell 脚本改掉是常事。应用层用户applmgr的.bash_profile里如果 source 了 DB 的环境文件,就会出现在应用层执行 sqlplus 却连到另一个 HOME 的情况,报错还是 12547,但根因完全变了。排查时建议养成习惯:先echo $ORACLE_HOME $ORACLE_SID,再动手。

2.2 二进制权限位:ORA-12547 最常见的真凶

$ORACLE_HOME/bin/oracle这个文件不是普通可执行文件,它的权限位里必须带 setuid 和 setgid。正常长这样:

ls -l $ORACLE_HOME/bin/oracle # 正常输出:-rwsr-s--x 1 oracle oinstall ... # ^ ^ # | └── setgid # └────── setuid

如果那个s变成了x,或者属主变成了root,服务器进程就没办法以正确身份去读某些资源,fork 出来立刻退,客户端看到的就是 12547。这个坑的成因很隐蔽:用 tar 覆盖解压、从另一个 HOME 拷贝二进制做"救急"、用 root 跑过一次 relink、甚至某些备份还原工具的权限保留选项没开,都会把 s 位弄丢。

恢复动作本身不复杂,但顺序别反:

# 1. 先看当前状态,确认属主和权限位 ls -l $ORACLE_HOME/bin/oracle # 2. 属主不对先改属主,再改权限 chown oracle:oinstall $ORACLE_HOME/bin/oracle chmod 6751 $ORACLE_HOME/bin/oracle # 3. 再确认一次,必须是 -rwsr-s--x ls -l $ORACLE_HOME/bin/oracle # 4. 如果二进制本身已经被别的版本覆盖,改权限也没用,直接 relink cd $ORACLE_HOME/rdbms/lib make -f ins_rdbms.mk ioracle

6751这四位拆开看:6是属主读写,7是属组读+写+执行并且带 setuid/setgid,5是其他用户读+执行,最后的1是其他用户可执行。EBS 官方文档里给的就是这个值,不要自作聪明改成 755 或 775,改完照样报错,而且更难查——因为看上去"权限是对的"。

我一般会在装完数据库、打完每一个补丁之后都跑一次ls -l $ORACLE_HOME/bin/oracle,十秒钟的事,能省掉后面半小时的怀疑人生。这条经验是被坑出来的:有一次打完补丁 relink 完,应用层突然连不上库,翻遍了监听器和网络,最后发现就是 relink 之后 s 位没回来。

2.3 监听器与 tnsnames.ora:主机名解析比端口更常出错

确认权限位没问题、本地直连能进之后,剩下的嫌疑就集中在监听器这一侧。查看监听器状态时不要只看"是否在运行",要看它认了哪些服务:

# 看监听器状态,重点看 Service Summary 里有没有目标实例 lsnrctl status LISTENER_PROD # 从应用层机器测服务名解析,测的是 TNS 解析,不是网络通不通 tnsping PROD 3

tnsping返回的Used parameter files和Attempting to contact两行信息量很大:前者告诉你它读的是哪个tnsnames.ora,后者告诉你它把服务名解析成了哪个主机和端口。EBS 环境里经常出现应用层读的是$TNS_ADMIN下的文件,而 DBA 改的是$ORACLE_HOME/network/admin下的那份,两边不一致,改了半天没生效。

listener.ora里最容易被忽略的是主机名写法:

LISTENER_PROD = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = dbhost.example.com)(PORT = 1521)) ) )

HOST这一项必须能被解析到本机网卡地址。写成localhost会导致只有本机能连、应用层连不上;写成短主机名而/etc/hosts里只有带域名的那一行,解析就会落到 DNS 上,解析结果跟实际网卡对不上。EBS 对主机名和域名的要求比普通单机库严格得多,装之前就要把hostname、/etc/hosts、/etc/sysconfig/network三处对齐,写全 FQDN,后面 AutoConfig 生成的各种配置文件全都依赖这个一致性。

# 三处必须一致,不一致就在这一步改掉,别等到 autoconfig 之后再返工 hostname hostname -f grep -i "$(hostname -s)" /etc/hosts cat /etc/sysconfig/network | grep HOSTNAME

提示:改完主机名之后不要直接往下走,先重启一次网络服务再tnsping,EBS 的很多监听注册是在服务启动时完成的,不重启看不到效果。

2.4 内核参数与资源限制:装完就忘的 sysctl.conf 和 limits.conf

前三点都排除干净还是 12547,剩下的可能就是进程起不来但没报错——被资源限制卡住了。EBS 安装文档里给了一长串sysctl.conf和limits.conf的配置项,很多人装的时候照着贴了一遍,装完就再也没看过。问题是这些参数在系统升级、内核更新、或者有人为了跑别的程序调过之后,是会变的。

# /etc/security/limits.conf 里 EBS 相关的几行,两个用户都要配 oracle soft nproc 2047 oracle hard nproc 16384 oracle soft nofile 4096 oracle hard nofile 65536 applmgr soft nproc 2047 applmgr hard nproc 16384 applmgr soft nofile 4096 applmgr hard nofile 65536
# /etc/sysctl.conf 里 EBS 必须落地的几项(节选,完整清单按文档给的来) kernel.sem = 256 32000 100 142 kernel.shmall = 2097152 kernel.shmmax = 4294967295 fs.file-max = 6815744 fs.aio-max-nr = 1048576 net.ipv4.ip_local_port_range = 9000 65500 # 改完必须让它生效,然后重新登录验证,不能只在当前 shell 里生效 sysctl -p ulimit -n ulimit -u

kernel.sem的四个值分别是信号量集合里最多几个信号量、系统级信号量总数、单次 semop 调用允许的操作数、信号量集合最大数。这几个值配小了,Oracle 后台进程在并发高的时候会起不来,表现之一就是连接被拒或直接 12547。net.ipv4.ip_local_port_range默认从 32768 起,EBS 的并发管理器、Forms 服务加起来会占掉大量临时端口,端口段不够就会随机性地连不上,这种"时而好时而坏"的故障最消耗人。

limits.conf有个经典的坑:它对通过 PAM 登录的会话生效,但对su - oracle之后再用su切换出来的子 shell 不一定生效。验证时不要只看ulimit -a的输出,要确认当前会话真的是通过登录方式进来的。我一般会在.bash_profile里直接加一段ulimit -n 65536兜底,虽然不太优雅,但能避免半夜被叫起来查"为什么白天好好的晚上连不上"。

3. adpatch 跑到一半失败:从 R12.1.1 升到 R12.1.3 的顺序与卡点

R12.1.1 装完之后,真正的大工程是把它升到 R12.1.3。这一步涉及的补丁多、顺序强、耗时以小时计,中间任何一环失败都得回滚到维护模式重启一遍。更麻烦的是很多人拿 R12.2 的文档来套 R12.1,上来就敲adop,然后发现命令根本不存在——R12.1 用的是adpatch,在线打补丁那套adop是 R12.2 才有的东西。这个版本错位是新手最容易翻的车之一。

3.1 顺序错了全盘皆输:维护模式、关应用、关数据库的先后

升级前必须先让系统进入维护模式,否则补丁一边跑、用户一边登录,表结构改到一半会话还在读,结果就是一堆不可预期的无效对象。进入维护模式的入口是adadmin,菜单里找 "Change Maintenance Mode",然后选 "Enable Maintenance Mode"。开启之后普通用户登录会被挡在门外,管理员账号仍然可以进,方便你验证。

接着是关服务。EBS 的启停脚本有三个,停的时候顺序不能乱:

# 停应用:脚本会依次停掉并发管理器、CM、Forms、Web 服务 $ADMIN_SCRIPTS_HOME/adstpall.sh apps/<apps密码> # 停完必须确认没有残留进程,否则后面的 adpatch 会卡在文件锁上 ps -ef | grep -E 'FNDLIBR|FNDFS|opmn|IAS_' | grep -v grep # 打补丁期间数据库保持打开,应用层关掉即可 # 打完补丁再按相反顺序启动 $ADMIN_SCRIPTS_HOME/adstrtal.sh apps/<apps密码>

adstpall.sh的参数是apps/<密码>,密码里如果有特殊字符(比如$、#)要用单引号包起来,不然 shell 会先做变量替换,脚本拿到的密码是错的,表现是脚本不报错但服务没停干净。这个坑极其隐蔽,因为屏幕上只有一行 "The Application Server is Stopped",你以为停成功了,其实什么都没做。

关掉应用之后不要立刻开始打补丁,先看一眼数据库的会话数和锁情况。残留的数据库会话会让补丁在改表结构时一直等待,最后超时失败:

-- EBS 应用层的会话应该都断干净了,剩下的大多是后台进程 SELECT COUNT(*), machine, program FROM v$session WHERE type = 'USER' GROUP BY machine, program ORDER BY 1 DESC;

补丁过程中的先后关系大致是:进维护模式 → 关应用 → 打多语言加速包 → 打 AD 补丁 → 编译 APPS schema → 扩表空间 → adrelink → 打中文语言补丁 → 打 R12.1.3 升级补丁 → 打后续的 9817770 和 9966055 → 跑 AutoConfig。这条链上任何一步跳过,后面都会以另一种形式报出来,而且报错位置和真实原因隔得很远。

3.2 打 9239090 与 9239089:adpatch 参数、日志位置和失败重跑

R12.1.3 的升级补丁是 9239090,它前面还要先打 AD 补丁 9239089。adpatch的启动方式对目录有要求,必须在$APPL_TOP/admin/<SID>这一层执行,否则它找不到应用上下文:

cd $APPL_TOP/admin/$TWO_TASK adpatch \ logfile=u9239090.log \ patchtop=/u01/patch/9239090 \ driver=u9239090.drv \ workers=4 \ interactive=no \ options=nocopyport

几个参数值得单独说。logfile是主日志,实际运行时它会拆成一堆u9239090.lst、adwork001.log之类的文件放在同目录下,排错时真正有用的是 worker 日志而不是主日志。patchtop指向解压后的补丁目录,这个目录的权限必须让applmgr可读可执行,放在/root下面是最常见的失败原因。workers是并行 worker 数量,一般给 4 到 8,给太多反而会因为表锁竞争互相等待,实际耗时更长。interactive=no让补丁在遇到可跳过的确认时自动继续,适合长时间无人值守;但第一次跑某个补丁时不建议这么干,先交互跑一遍看清楚它问了什么。options=nocopyport的作用是不覆盖已经由 AutoConfig 管理过的文件,跳过它会导致补丁把你手工调过的配置打回去。

补丁跑起来之后,监控靠adctrl:

# 看每个 worker 的当前状态,重点看有没有 Failed 或 Restart adctrl # 实时看主日志里的错误行 tail -f u9239090.log | grep -i -E 'error|fail|unable' # 补丁跑完之后统一扫一遍所有 worker 日志 grep -i -n 'error' adwork*.log | head -50

失败之后不要急着重头再来。adpatch会在$APPL_TOP/admin/<SID>/restart/下留状态文件,直接在原目录敲adpatch(不带任何参数)它就会读这个状态接着往下跑。如果是某个 worker 挂了,用adctrl选 "Restart worker" 单独重启那一个,比整体重跑省几个小时。

注意:补丁失败后不要先急着删 restart 目录,那是你唯一的后悔药。确认问题解决之后再从干净状态重跑。

3.3 表空间不够的真实表现:adpatch 不是报"空间不足",而是报"对象无效"

这是最容易走弯路的一类故障。表空间快满的时候,adpatch不一定直接给你一个ORA-01653: unable to extend table,很多时候它只是安静地失败几步,然后在编译阶段给你一堆无效对象,你在那里查权限查同义词,根本想不到是磁盘满了。

补丁前先做一次空间盘点:

-- 看每个表空间的实际使用和可扩展上限 SELECT tablespace_name, ROUND(SUM(bytes)/1024/1024/1024, 2) AS total_gb, ROUND(SUM(maxbytes)/1024/1024/1024, 2) AS max_gb, ROUND(SUM(bytes)/1024/1024/1024, 2) / NULLIF(ROUND(SUM(maxbytes)/1024/1024/1024, 2), 0) * 100 AS used_pct FROM dba_data_files GROUP BY tablespace_name ORDER BY used_pct DESC;

APPS_TS_TX_DATA是补丁期间长得最快的表空间,升级前给它留足余量是常规操作:

-- 加一个自动扩展的数据文件,避免补丁跑到一半卡住 ALTER TABLESPACE APPS_TS_TX_DATA ADD DATAFILE '/u02/oradata/PROD/apps_ts_tx_data04.dbf' SIZE 4G AUTOEXTEND ON NEXT 512M MAXSIZE 30G;

MAXSIZE 30G这个上限不是随便写的。8K 块大小的数据库单个数据文件上限是 32G,写UNLIMITED在超过 32G 时会直接报错,所以给一个略低于上限的值更安全。AUTOEXTEND NEXT 512M控制每次扩展的步长,给太小会导致频繁扩展、文件碎片化;给太大又可能在磁盘快满时一口气把盘吃光。

扩完表空间再回头编译 APPS schema,路径是adadmin→ "Compile/Reload Applications Database Entities menu" → "Compile APPS schema",选择重新编译全部无效对象。这一步耗时可能到几小时,跑完之后用下面这条确认结果:

-- 按 owner 统计无效对象,和补丁前的基线对比,不能明显增多 SELECT owner, object_type, COUNT(*) AS invalid_cnt FROM dba_objects WHERE status = 'INVALID' AND owner IN ('APPS', 'AP', 'AR', 'GL', 'INV', 'PO', 'HR') GROUP BY owner, object_type ORDER BY invalid_cnt DESC;

APPS schema 下有少量长期 INVALID 的对象是 EBS 的常态,不用追求清零。判断标准是"和补丁前相比有没有变多"——所以补丁前一定要先跑一遍这条 SQL 把结果存下来,没有基线就没法判断。

3.4 多语言加速包与中文语言补丁:跳过的代价是重跑

多语言加速包 8576725 是升级到 R12.1.3 之前的必备件,作用是把多语言相关的数据预先准备好。跳过它直接打中文语言补丁,症状是补丁跑得异常慢,最后在某个语言表上超时失败,回头还得从头来。

中文语言本身要在adadmin或者 OAM 里先做授权,再打语言补丁。授权这一步如果漏了,补丁能跑完但登录进去还是英文界面,查起来又是一轮。

打语言补丁时要注意adpatch的workers不能给太高,语言相关的表数据量大、索引多,并行度高反而容易锁冲突。我一般在这种补丁上把workers压到 2 到 4,牺牲一点速度换稳定。

打完所有补丁之后跑adrelink,把应用层的可执行文件重新链接一遍:

# adrelink 会重新链接 FNDLIBR 等核心执行文件 # force=y 强制重链,debug=n 不带调试符号(生产环境不需要) $AD_TOP/bin/adrelink.sh force=y debug=n "fnd FNDLIBR"

adrelink之后一定要回头检查$ORACLE_HOME/bin/oracle的权限位——有些版本的adrelink会把 DB 层的二进制一起处理,处理过程中 s 位会丢,然后你就看到了第 2 章那个 12547。这两章看着不相关,实际在现场经常是连着出现的。

4. DBUA 升级到 11.2.0.4 失败:升级前后最容易漏掉的动作

应用层升到 R12.1.3 之后,数据库要从 10g 升到 11.2.0.4。这一步用 DBUA 图形界面走完看着很顺,但升级前没做的检查、升级后没补的动作,会在几周之后以各种奇怪的方式冒出来。最常见的现象是:DBUA 显示成功,dba_registry里却有组件是 INVALID,然后应用层登录报错,你在应用层查了半天,问题其实在数据库。

4.1 升级前的三件事:utlu112i.sql、临时表空间、时区版本

DBUA 启动之前必须跑预检查脚本,这是硬性要求,不是可选项:

-- 用 11.2.0.4 的 HOME 来跑,不是原来的 10g HOME -- 输出里所有 WARNING 都要逐条处理,不能跳过 @?/rdbms/admin/utlu112i.sql

这个脚本会生成一份upgrade_info_<SID>.log,里面列出表空间是否够、有没有失效的组件、时区文件版本是否兼容、有没有用到的特性在新版本被废弃。EBS 环境里最常出的两条警告是临时表空间不足和组件版本不匹配。临时表空间不够的话,DBUA 在跑catupgrd.sql阶段会直接失败,回滚都得花半天。

-- 临时表空间先看一眼,EBS 升级期间用量会翻好几倍 SELECT tf.tablespace_name, ROUND(tf.bytes/1024/1024/1024, 2) AS total_gb, ROUND((tf.bytes - NVL(fs.free_bytes, 0))/1024/1024/1024, 2) AS used_gb FROM dba_temp_files tf LEFT JOIN (SELECT tablespace_name, SUM(bytes_free) free_bytes FROM v$temp_space_header GROUP BY tablespace_name) fs ON fs.tablespace_name = tf.tablespace_name;

时区版本这一项容易被忽略但后果最严重。EBS 的很多日期字段依赖数据库时区文件,升级前后版本不一致会导致日期显示错乱、并发请求的日期参数解析异常。升级前先记一笔:

-- 升级前后各跑一次,版本号必须对得上(或者按文档要求显式升级时区文件) SELECT version FROM v$timezone_file;

4.2 initPROD.ora 里加 disable_fast_validate,以及关闭应用层的时机

初始化参数文件里要加的disable_fast_validate,作用是关掉快速验证路径,避免升级过程中某些对象校验走捷径而出错。这里有个容易踩的细节:文档里写的是disable_fast_validate,但实际生效的写法通常要带下划线变成隐藏参数_disable_fast_validate=TRUE,直接按文档写不带下划线,加进去等于没加,日志里也不会提示你。

我的做法是加之前先确认它到底认不认:

-- 加完之后查一下,能查到说明生效了 SHOW PARAMETER disable_fast_validate;

如果查不到,就改成带下划线的形式再试一次。隐藏参数不是不能碰,但每次碰都要记清楚改了什么、为什么改,不然下次升级时看到一堆不认识的参数会更乱。

关闭应用层的时机也很关键。DBUA 需要一个没有应用连接的数据库,所以顺序是:先关应用、再关数据库监听、再启动 DBUA。反过来做的话,DBUA 在检查阶段会报"数据库正在被使用"。

# 1. 停应用 $ADMIN_SCRIPTS_HOME/adstpall.sh apps/<apps密码> # 2. 确认数据库里没有应用会话残留 # 3. 停监听器,避免升级过程中有连接打进来 lsnrctl stop LISTENER_PROD # 4. 关闭数据库 sqlplus / as sysdba <<'EOF' SHUTDOWN IMMEDIATE; EXIT; EOF

4.3 DBUA 卡在 70% 或者直接报错:日志在哪里看

DBUA 的进度条走到 70% 左右会停留很久,那一段是在跑catupgrd.sql和编译组件,属于正常现象。判断"卡住"还是"在跑"的方法是看日志有没有在增长,而不是看进度条。

需要盯的三个位置:$ORACLE_BASE/cfgtoollogs/dbua/<SID>/upgrade<时间戳>/下的 DBUA 自身日志、$ORACLE_HOME/rdbms/log/下的 SQL

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进