做Oracle运维这么多年,我最常被问的问题之一就是:“我这套11g单库,到底要不要打PSU?打补丁会不会出幺蛾子?”说实话,11g虽然“上了年纪”,但在现在的生产环境里存量依然很大,很多企业的核心业务库还跑在11.2.0.4上面。但官方对11g的普通支持早已结束,真正还在持续发布的安全补丁,主要就是PSU。这也让“Oracle 11g单库环境PSU补丁安装”成了每个DBA绕不开的日常操作。
这篇文章我按自己实际打补丁的流程来写,覆盖从补丁选型、环境准备、opatch apply、catbundle.sql数据字典更新,到验证和回滚的完整过程。不管你是有几年经验的老DBA,还是刚开始接触Oracle的运维新人,按这个流程走一遍,至少能少踩一半的坑。
1. PSU补丁的核心思路与整体拆解
1.1 为什么Oracle 11g必须打PSU补丁
先说清楚PSU到底是什么。PSU的全称是Patch Set Update,可以理解成Oracle在版本发布之后,把一段时间内累积的修复统一打包成的一个补丁集合。它和单补丁(One-off Patch)最大的区别是:PSU是累积式的,也就是说新PSU包含了旧的PSU里所有的修复项。这意味着补丁不是越打越多,而是越来越完整。你可以把PSU想象成一个不断更新的手机系统版本,每次发布新版都会包含之前所有修复内容。
Oracle 11.2.0.4是11g最后一个基础版本,之后的补丁维护基本都靠PSU。以11.2.0.4为例,PSU的编号规则一般是“11.2.0.4.年份日期”,比如11.2.0.4.180717代表2018年7月发布。越新的PSU,修复的安全漏洞和bug就越多。到了今天,很多安全扫描工具检查出来的数据库漏洞,官方给的建议基本都是“升级到最新的PSU”。所以打PSU不只是常规维护,很多时候是安全整改的硬性要求。
打PSU还有一个现实层面的原因:如果你不维护补丁,后面想恢复数据、排查疑难bug,Oracle支持很可能直接要求你先打个最新PSU再说。与其到时候仓促补,不如平时就把补丁策略固定下来,选一个维护窗口定期安装。
1.2 单库环境打补丁的整体思路
单库环境,说到底就是一台服务器上跑一个数据库实例,常见的部署形态是“单机+本地文件系统”或“单机+ASM存储”。相比RAC集群环境,单库打PSU有个非常明显的优势:不需要考虑滚动更新,不需要跨节点协调,只要规划好停机窗口,一台一台处理就行。
但单库环境也有自己的麻烦。因为只有一套环境,一旦补丁打挂了,整个业务都会直接停摆。所以单库打补丁的核心思路不是“快”,而是“稳”。整个流程我一般拆成四个阶段:准备、备份、执行、验证。准备阶段搞清楚当前版本和补丁包是否匹配;备份阶段把数据库和关键配置文件都留好后路;执行阶段按顺序来,不跳步;验证阶段不只是看补丁装没装上,还要确认数据库运行状态、监听、日常业务是否正常。
另外,打补丁的窗口选择也很重要。哪怕是单库,我也不会在业务高峰期动它。一般建议选择维护窗口,提前通知业务方,这个时间点足够你执行补丁、跑SQL脚本、做基础验证。时间不够的话,宁可下次再打,也不要赶工。
1.3 先分清几个容易混淆的概念
在动手之前,有几个概念必须先搞清楚,不然很容易在查阅资料时迷迷糊糊:
- PSU(Patch Set Update):累积型补丁集合,包含常规bug修复和安全修复,每季度发布一次。
- CPU(Critical Patch Update):Oracle早期对安全补丁的叫法,现在已经统一到PSU里。
- SPU(Security Patch Update):有些平台或版本里,Oracle会把只包含安全修复的补丁包单独命名为SPU,作用类似但不完全等同。
- One-off Patch:单个问题补丁,只针对某个bug,安装前最好经过Oracle支持确认。
- Bundle Patch:主要用于Windows平台的累积补丁包,Linux上不太提这个。
实际工作中,生产环境最常用的就是PSU。选补丁包的时候一定要注意匹配操作系统平台。同一个PSU编号,Linux、Solaris、AIX、Windows的补丁包是完全不同的,下载错了到了安装阶段才发现,白白浪费时间和窗口。
2. 补丁安装前的准备工作与检查项
2.1 环境信息收集:先搞清楚自己站在哪里
打补丁之前第一件事不是下载补丁,而是把当前环境信息摸清楚。我一般会整理一个信息清单,至少包含以下几项:
- 操作系统版本和架构(比如Red Hat Enterprise Linux 7.9 x86_64)
- 数据库版本和补丁基线(比如Oracle 11.2.0.4.0,还是已经打过某个PSU)
- 数据库实例的ORACLE_HOME路径、ORACLE_SID
- 当前OPatch工具版本
- 数据库是否启用了Data Guard、GoldenGate等同步机制
- 数据库的大小、备份策略是否完好
- listener.ora、tnsnames.ora等关键配置文件的路径
其中,数据库版本这一步尤其关键。很多人以为自己装的是11.2.0.4,实际上可能只是11.2.0.1,或者已经打过了某个月的PSU,再直接打最新PSU时就会遇到冲突。要确认当前版本,最直接的方式就是用SQL查看:
select * from v$version;或者看补丁信息:
opatch lsinventoryopatch lsinventory这命令建议每次操作前都跑一遍,它会把ORACLE_HOME下已经装过的补丁全部列出来,你能清楚地看到当前基线是干净的裸版本,还是已经带了很多历史补丁。这在后面做冲突检测时特别重要。
2.2 OPatch工具的版本升级
很多人忽略OPatch本身的版本,等opatch apply报错才回头查,其实这条写在最前面就能避免大部分问题。Oracle补丁包一般会要求OPatch的最低版本,尤其是新出的PSU,对OPatch版本要求会越来越高。11.2.0.4时代,OPatch版本如果太低,大概率会报“OPatch version is too low to support this patch”之类的错误。
OPatch工具本身也是一个补丁包,专门的补丁号通常是p6880880,同样按平台区分。升级OPatch很简单,先备份原来的OPatch目录,然后把新版本解压覆盖到ORACLE_HOME/OPatch下。注意操作的执行用户必须是ORACLE_HOME的属主,生产环境一般是oracle用户,不能用root直接解压覆盖,否则后续可能遇到权限错乱的问题。
做完之后用以下命令验证版本:
opatch version我习惯把这一步放在所有准备工作最开始,确认OPatch版本没问题,后面的流程才会顺畅。版本号以Oracle官方文档里对应补丁的README要求为准,不要自己拍脑袋判断。
2.3 备份是底线:补丁安装前必须做好的功课
单库环境打补丁,最大的恐惧不是补丁本身,而是万一出问题之后没有后路。我见过不少案例,数据库补丁打到一半,opatch报错,结果发现连备份都是旧的,最后只能硬着头皮恢复,过程极其痛苦。所以在打补丁之前,备份这道工序绝对不能省。
最低限度的备份要求是:
- 数据库逻辑备份或物理备份,确认备份文件完整可恢复。
- 备份ORACLE_HOME下的关键配置文件:
listener.ora、tnsnames.ora、sqlnet.ora、init.ora或spfile。 - 记录当前的补丁列表和数据库版本信息,方便回滚时对比。
如果是生产库,我还会额外做一次归档日志的检查,确认归档目录没有异常堆积,数据文件没有offline状态。这些检查看着琐碎,但能提前发现一些潜在风险。比如之前遇到过一次,数据库文件状态有问题,打补丁本身没失败,但后续启动实例时迟迟起不来,查了半天才发现历史遗留问题。
备份ORACLE_HOME配置,我的做法是单独建一个备份目录,用tar打包压缩,再复制到另一台机器或异地目录。不要把备份文件放在ORACLE_HOME内部,因为后续万一需要恢复整个目录,放在里面可能会被覆盖。
2.4 补丁包准备与冲突预检
下载补丁包之后,解压到临时目录,目录路径尽量不要包含中文字符和空格,也不建议放在ORACLE_HOME目录下。解压后先读一下补丁包自带的README,尤其是补丁的安装要求和注意事项。README里通常会明确写出OPatch最低版本、是否需要额外操作、是否有已知问题等,这些信息在Oracle官方文档里也有,但直接看README最直观。
解压完成后,进入补丁目录,做冲突检测和空间检查,命令如下:
cd /tmp/patch/31537677 opatch prereq CheckConflictAgainstOHWithDetail -phBaseDir ./ opatch prereq CheckSystemSpace -phBaseDir ./第一条是检查新补丁和当前ORACLE_HOME已有的补丁是否冲突;第二条是检查临时目录和ORACLE_HOME所在文件系统的剩余空间是否足够。这两个预检查是必做的,尤其要注意第一个。如果检测出来有冲突,必须先把冲突解决掉,比如先回滚旧补丁,或者向Oracle支持确认是否需要合并,不能强行apply。
实际操作中,补丁包很大,解压过程也可能遇到权限问题。建议解压完成后先看文件权限,确认补丁目录下文件的属主是oracle,而不是root。如果权限不对,后续opatch apply依然会报错。
3. 实操总结:PSU补丁安装全流程
3.1 关闭实例与监听,保持环境干净
安装PSU过程中,最关键的一个操作是关闭数据库实例和监听。这一步在官方文档里写得很清楚,但实际执行时经常有人偷懒,只停实例不停监听,或者干脆什么停不停直接跑opatch。结果就是二进制文件被进程占用,opatch apply时报文件占用错误,或者更隐蔽的是,补丁装了一部分但进程还在用旧代码,导致后续行为不可控。
关闭实例之前,我习惯先检查一下当前是否有活动的会话或长事务:
select count(*) from v$session;然后执行优雅关闭,建议用normal或者transactional方式,这样可以等事务完成后再关闭。如果时间紧,可以先检查完会话再shutdown immediate,一般业务库在维护窗口这样做问题不大。关闭监听用:
lsnrctl stop如果有EM Database Control或Oracle Agent在运行,也一并停掉。11g单库环境常见的是dbconsole,命令是:
emctl stop dbconsole如果数据库文件放在ASM里,而ASM实例和数据库共用同一个ORACLE_HOME,我也建议把ASM实例一并停掉,避免$ORACLE_HOME/bin/oracle这个二进制文件被ASM进程占用。这一步不是所有环境都必须,但在单库+ASM组合下这样做更稳妥。
关闭完毕之后确认一次:
ps -ef | grep ora_ | grep -v grep lsnrctl status看到没有监听进程、没有实例进程残留,再进入下一步。
3.2 opatch apply:核心安装过程
环境停干净之后,正式进入安装。执行安装的用户必须是oracle用户,命令顺序是:
cd $ORACLE_HOME export PATH=$ORACLE_HOME/OPatch:$PATH cd /tmp/patch/31537677 opatch applyopatch apply的过程中会做一系列自检,包括再次检查冲突、空间、补丁兼容性等。如果之前预检都通过,这里一般能顺利走完。看到屏幕输出OPatch succeeded就表示二进制补丁已经打上了。
这里有一个细节值得注意:opatch apply执行过程中,如果输出信息太长,建议保留一份日志,或者至少把输出重定向到文件里方便回查。有些老版本的opatch如果不指定日志,会直接在屏幕上输出大量信息,一屏滚过去,后面想确认结果反而麻烦。
打完补丁之后,不要急着启动数据库。先检查一下二进制文件的属主和权限,确认$ORACLE_HOME/bin/oracle还属于oracle用户,并且权限正常。曾经遇过一次,因为是root跑了一部分操作,导致oracle二进制属主变成了root,启动实例时报权限错误,花了不少时间才排查清楚。
3.3 执行catbundle.sql更新数据字典
这是PSU安装流程中最容易被忽略的一步。二进制补丁更新的是Oracle程序文件,但数据库里的数据字典内容还需要单独执行SQL脚本来更新。这一步不执行,补丁相当于只装了一半,后续很多功能可能表现异常。
启动数据库到open状态后,用SYS用户执行:
sqlplus / as sysdba SQL> startup; SQL> alter session set container=CDB$ROOT; SQL> spool /tmp/catbundle_psu.log SQL> @?/rdbms/admin/catbundle.sql PSU apply SQL> spool off;注意,11g还没有CDB概念,所以不需要alter session set container,直接执行catbundle.sql即可。正确格式是:
SQL> @$ORACLE_HOME/rdbms/admin/catbundle.sql PSU applyspool要把日志留下来,方便最后检查是否报错。整个脚本跑的时间不固定,短的十几分钟,长的可能半小时以上,具体取决于数据字典的大小和服务器性能。运行期间,不要开其他会话去动数据库,尤其不要执行DDL操作,否则可能导致锁冲突。
脚本跑完之后查看日志,确认没有出现ORA-错误。catbundle.sql正常执行的结尾一般会提示类似Catbundle completed的信息。如果日志里有错误,先不要慌,把错误信息记录下来,确认是致命错误还是可以忽略的告警。拿不准的情况下,最好找Oracle支持确认,不要贸然重跑。
3.4 安装后的验证清单
补丁打完了,数据字典更新也完成了,但整个安装流程还没结束,至少要做一轮基础验证。我习惯按下面这个清单过一遍:
查询当前补丁列表:
opatch lsinventory或者只看补丁ID:
opatch lspatches确认要安装的PSU编号在列,同时查看数据字典里的SQL patch记录:
select * from dba_registry_sqlpatch;在这条记录里,能看到ACTION列是APPLY,STATUS列是SUCCESS,这表示SQL patch已经正确应用。
接下来,验证数据库运行状态。执行:
select open_mode from v$database; select status from v$instance;然后启动监听:
lsnrctl start lsnrctl status主要确认监听进程起来了,数据库实例能正常注册到监听。这一步非常关键,因为单库环境如果监听起不来,对业务的影响和数据库宕机没什么区别。
最后做一次最小化的业务验证,比如通过JDBC连接串连接一次会话,执行一条简单的查询语句,确认网络连接正常,最基本的功能没坏。这一步看似多余,但在实战中能快速发现一些隐藏问题,比如JDBC驱动和补丁后的数据库不兼容之类的,早发现早解决。
4. 常见问题排查与避坑指南
4.1 opatch apply时报错:空间不足、权限错乱怎么办
opatch apply最常见的报错之一是文件系统空间不足。虽然前面预检时做了CheckSystemSpace,但有些环境在补丁执行期间日志文件、回滚文件会持续写入,临时目录可能突然被占满。遇到这种情况,先看哪个目录满了,用df -h确认,然后清理临时文件和旧日志,再重新执行opatch apply。
opatch apply本身具备续跑能力吗?严格来说,Oracle的opatch在失败后不会从断点继续,而是需要清理现场后再重试。重试前要检查ORACLE_HOME/bin目录下有没有残留的备份文件,比如.copy或.orig结尾的文件。如果有,说明上一次安装的中间状态还没清理干净,需要修复或还原后重新再来。
权限方面,最常见的错误是“Permission denied”。原因基本就是前面提到的,用了root用户执行了某些步骤,导致ORACLE_HOME下文件的属主变了。遇到这种情况不要直接在root下改权限然后继续,而是要用oracle用户对变更的文件做属主修复,或者从备份里恢复受影响文件。如果是root跑opatch导致的损坏,更保险的方案是找一台同版本的测试机重新校验一遍。
4.2 如果补丁安装失败,如何回滚
打完补丁后发现异常,需要回滚时,分两种情况:二进制补丁已经apply但SQL脚本还没执行,或者SQL脚本也执行了。
如果SQL脚本还没执行,回滚就相对简单。进入补丁目录,用OPatch自带的方式回滚:
cd /tmp/patch/31537677 opatch rollback -id 31537677 -phBaseDir ./rollback之后,再重新启动数据库到open状态,确认一切正常即可。如果opatch报错说不支持rollback,那就只能从备份恢复ORACLE_HOME,这种场景比较少,但也不是没有。
如果SQL脚本已经执行,情况就复杂了。此时数据字典已经变化,单纯回滚二进制补丁会导致二进制和字典版本不匹配,数据库反而更容易出问题。稳妥的路线是从备份完整恢复数据库,回到打补丁之前的某个时间点。这也是为什么我在前面反复强调备份的重要性。没有备份硬着头皮处理,往往耗时更长、风险也更高。
还有一种少见情况:PSU应用失败,但日志里没有明显报错,数据库也能起来,只是某些功能不正常。这种情况我建议先用dba_registry_sqlpatch确认SQL patch的实际状态,再根据具体症状对log进行排查,必要的时候再咨询Oracle支持。
4.3 打补丁后监听服务无法启动的排查思路
热词里经常有人搜“oracle监听服务无法启动”,打完补丁后遇到这个问题的概率确实不低。监听启动失败的原因很多,但在补丁场景下,最常见的就是这几种:
- listener.ora被修改或损坏。
- ORACLE_HOME环境变量没有切换到补丁更新后的路径。
- 端口被占用。
- 文件权限不对,监听进程没有权限读取配置。
排查顺序我一般从简单到复杂:先看监听配置文件内容,确认监听端口、协议、主机名有没有异常;再用命令启动并观察报错具体信息:
lsnrctl start lsnrctl status如果是端口被占用,用netstat -anp | grep 1521确认,杀掉占用进程或者修改监听端口。如果监听配置没问题,那就检查环境变量,确认当前shell里的ORACLE_HOME和PATH指向的是补丁更新后的正确路径。有时候打完补丁,用户登录时的环境变量文件(比如.bash_profile)里还残留了旧路径,导致监听进程加载了旧配置。
实际运维中,我遇到最多的其实是懒省事的做法——用root直接启动监听,导致监听进程以root身份运行,后续oracle用户登录之后反而看不到监听状态。正确的操作方式应该是su - oracle之后再执行lsnrctl,保证权限归属清晰。
4.4 打PSU期间容易忽略的几个细节
最后分享几条实战中的个人习惯,虽然算不上什么高深技术,但踩过坑之后就知道这些细节多值钱。
第一,补丁目录最好保留到下一次补丁打完再删。不仅是方便回滚,也是方便对照检查。
第二,打补丁当天不要执行任何其他变更操作。比如不要同时去改数据库参数、调整表空间、删归档日志。补丁过程本来就够复杂,变量越少越好,这算是我做变更管理的一条铁律。
第三,安装完成后跟业务方确认一下关键交易或存储过程是否正常。热词里经常有人搜“oracle存储过程”相关问题,有些存储过程在补丁后因为SQL执行计划变化突然变慢,或者出现奇怪的报错。这种问题不一定是补丁本身写坏了,更多时候是优化器行为变化造成的。遇到这类情况,先从执行计划入手排查,不要急着回滚。
补丁维护这件事,说白了就一句话:理性重视,按流程走。每一步都做到位,数据库和业务都会很平稳;跳过任何一个小步骤,都可能在某一天变成生产事故。希望这份实操记录能帮你顺顺利利完成一次Oracle 11g单库PSU补丁安装。