原文地址:Binary patching is slow because of the inventory
原文作者:Mike.Dietrich
这篇博文的标题可能听起来有点神秘:由于库存,二进制补丁很慢。但实际上,当您应用的每个补丁程序使您的二进制补丁程序变得越来越慢时,这似乎是主要原因之一。

你修补的越多,它变得越糟糕
你可能已经阅读了我关于我的季度补丁经验的博客文章。当我写道:
至少在我的环境中,对新 opatch 25的两次检查都需要很长时间。我想我每次检查都等了 3 分钟才能返回命令提示符。而且由于 opatch 在我在下一阶段调用 apply 时再次进行检查,因此当它告诉我“正在验证环境并执行先决条件检查…”时,等待时间再次发生。
正如您在2021 年 7 月的博客文章中看到的那样,我没有进一步调查。但我在2021 年 10 月和2022年 1 月的以下补丁周期中看到了相同的行为。当然,在2022 年 4 月,现在的等待时间是 5 分钟的三倍,甚至更多。
现在你会说:谁在乎五分钟多或少?但请记住,我只修补数据库主页,不涉及 GI 修补。此外,我只有一个玩具环境,我每季度打一次补丁。
从客户的反馈中,例如 Peter 确定:
- 错误 33425636 – OPATCHAUTO VER 27 二进制文件应用需要很长时间 19.12 Sev 1 SR
看起来好像您应用的补丁越多,最终花费的时间就越长。
这很糟糕,因为我们要求您每季度打补丁。这意味着您越频繁地修补数据库,您就会受到这种影响的影响越大。
更大的开发测试
由于我们现在已经从各种客户那里获得了足够的信息,我们可以根据大量开发中的数据来讨论这个问题。我的伙伴们开始使用多节点 RAC 环境和带有许多 PDB 的 CDB 进行大型测试。
截至目前,有几位客户报告了几种影响:
- 您拥有的补丁越多,二进制补丁所需的时间就越长
- 您拥有的集群节点越多,所需的时间就越长
- 您在每个集群节点上运行的数据库越多,所需的时间就越长
- 您拥有的 PDB 越多,所需的时间就越长
尽管上面的一些陈述似乎很明显,但在某些情况下效果是“有趣的”。
由于此处的这篇博文仅涉及二进制补丁,因此我将把其他问题(并希望得到答案)转移到本系列的其他博文中。
回到开发测试运行,很明显我们看不到二进制补丁的巨大影响。相反,数据补丁似乎有更大的影响。因此,尽管像 Peter 或 Sven 这样的客户有糟糕且更长的修补“经验”,但我们内部并没有看到这一点。至少不像对客户环境的影响那么大。
我并不是一个人
幸运的是,那里有非常聪明的人。有些人读了我的博客。
我之前已经在 LinkedIn 上引用了 Balaji Govindu 的博客文章(您需要拥有 LinkedIn 用户才能看到它)。但让我描述一下他做了什么,因为他在补丁日志中看到了同样无聊的消息:他在清单中编辑了一个文件,跟踪系统上应用的补丁:$ORACLE_HOME/inventory/ContentsXML/oui-patch.xml .通过这样做,他可以大大减少二进制修补时间。
当您在补丁运行期间tail -f日志时,这似乎很明显。Opatch 正在检查依赖项。不幸的是,对于每个其他补丁,检查依赖项所需的时间都比以前长。因此,它不仅仅是“一次检查更多”,而是一个乘数。你修补的越多,它变得越糟糕。
快速比较
因此,在向您展示解决方法之前,我将在我的玩具环境中进行测试,即我们的动手实验室。设置是安装了 OJVM 的 19.14.0 数据库主目录。目标将是 19.15.0。我将进行两次运行并比较时间和日志中的一些信息。
运行 1 – oui-patch.xml 没有更改
当我首先检查空间和冲突时,我已经认识到运行时间很长。
$ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./
和
$ORACLE_HOME/OPatch/opatch prereq CheckSystemSpace -ph ./
准确地说,在我的环境中的每一次检查都需要5 分 29 秒。
因此,您需要将等待时间乘以 2。因此,这两个简单的预检查一起运行11 分钟。在这个阶段请记住,我只修补我的数据库主页。不涉及网格基础设施,它具有完全相同的检查,可能补丁更少。
在我并行跟踪的日志文件中,我看到以下消息——然后持续了几分钟,但是什么也没有。
[May 9, 2022 6:23:41 PM] [INFO] [OPSR-TIME] Loading raw inventory
[May 9, 2022 6:23:42 PM] [INFO] [OPSR-MEMORY] Loaded all components from inventory. Heap memory in use: 25 (MB)
[May 9, 2022 6:23:42 PM] [INFO] [OPSR-MEMORY] Loaded all one offs from inventory. Heap memory in use: 34 (MB)
[May 9, 2022 6:23:42 PM] [INFO] [OPSR-TIME] Raw inventory loaded successfully
[May 9, 2022 6:23:49 PM] [INFO] [OPSR-TIME] Loading cooked inventory
[May 9, 2022 6:23:49 PM] [INFO] [OPSR-MEMORY] : Loading cooked one offs. Heap memory used 848 (MB)
[May 9, 2022 6:23:56 PM] [INFO] [OPSR-MEMORY] : Loaded cooked oneoffs. Heap memory used : 682 (MB)
[May 9, 2022 6:23:56 PM] [INFO] [OPSR-TIME] Cooked inventory loaded successfully
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 29517242 is a subset of other poh CUP: 33192793
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 29517242 is a subset of other poh CUP: 33515361
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 30557433 is a subset of other poh CUP: 30869156
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 30557433 is a subset of other poh CUP: 31281355
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32218454 is a subset of other poh CUP: 32545013
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32218454 is a subset of other poh CUP: 32904851
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32218454 is a subset of other poh CUP: 33192793
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32218454 is a subset of other poh CUP: 33515361
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32545013 is a subset of other poh CUP: 32904851
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32545013 is a subset of other poh CUP: 33192793
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32545013 is a subset of other poh CUP: 33515361
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32904851 is a subset of other poh CUP: 33192793
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 32904851 is a subset of other poh CUP: 33515361
[May 9, 2022 6:23:56 PM] [INFO] CUP_LOG: Found poh CUP 33192793 is a subset of other poh CUP: 33515361
您认出了我之前应用的补丁的补丁 ID。我默默地假设 opatch 现在试图理清依赖关系和潜在的冲突。
当然,我只能等待它完成。不幸的是,这些检查稍后在我调用 opatch 以应用补丁包时再次运行。现在您可以计算一下 4 节点集群上发生的情况。是的,opatch 会一遍又一遍地做这个练习,一个节点一个节点。
请不要问我为什么要花这么长时间。在一次内部讨论中,一位同事说:“嗯,你会认为如果数据在内存中,它应该在几秒钟内被处理。”。嗯……
再一次发生
现在,当我应用补丁时,哦,奇怪的是,opatch 会自己再次进行相同的检查。所以我想知道为什么我总是遵循自述文件并在 opatch 只是重复它们时运行检查。它是否期望我的磁盘在几分钟后已满?或者它是否期望我在两者之间偷偷地应用了其他几个补丁?
不管怎样,你已经知道了——我的日志文件从一开始就看起来是一样的,但发生这种情况时又需要 5.5 分钟的等待时间:
$ $ORACLE_HOME/OPatch/opatch apply
Oracle Interim Patch Installer version 12.2.0.1.30
Copyright (c) 2022, Oracle Corporation. All rights reserved.
Oracle Home : /u01/app/oracle/product/19
Central Inventory : /u01/app/oraInventory
from : /u01/app/oracle/product/19/oraInst.loc
OPatch version : 12.2.0.1.30
OUI version : 12.2.0.7.0
Log file location : /u01/app/oracle/product/19/cfgtoollogs/opatch/opatch2022-05-09_18-29-45PM_1.log
Verifying environment and performing prerequisite checks...
再次等待:
最后,opatch 将补丁包应用到我现有的家中。
所以让我快速总结一下:
- 手动预检查冲突:5 分 29 秒
- 手动预检查空间:5 分 26 秒
- opatch 在“应用”期间完成的预检查:5 分 29 秒
- 19.15.0 的原始补丁应用持续时间:
3 分 58 秒,包括复制文件以进行回滚
这看起来不太愉快。等待检查的时间超过16 分钟,而实际修补活动的时间不到4 分钟。
这里似乎有些不对劲。特别是因为我在我的 21c 或 12.2.0.1 家庭中看不到相同的行为,尽管我在所有三个家庭中都使用完全相同的 opatch 版本,并且我的 12.2.0.1 家庭看到的补丁包几乎与我的 19c 一样多家得到了。
然而,并没有结束
我也想从 2022 年 4 月开始应用 OJVM 捆绑包。因此,我需要根据 README 再次运行检查。
你可能会猜到又会发生什么?当然,opatch 会检查相同的库存并再次进行完全相同的检查。并且它们与以前的一样长,但有一个更正:由于我的源主页现在已经包含数据库 RU 19.15.0,因此比以前多了一个补丁包。
我为您节省时间并揭示结果。现在每次检查5 分 52 秒。自从我进行冲突检查、空间检查以来的三次——即使我将两者都保存并留给 opatch,它也会再次进行相同的检查。现在检查超过 18 分钟,或者在应用运行期间至少将近 6 分钟。
OJVM 包本身的实际修补只用了52 秒。
解决方法
好的,足够了解它需要多长时间以及可能出现的问题或不是最佳的。您来这里是为了了解解决方法。以及它的作用。因此,让我们从一些编辑工作开始。请记住一件重要的事情:这不是 Oracle 官方支持的解决方法。这只是提示您如何提高修补持续时间。始终保留原始oui-patches.xml文件。请注意,当您使用已编辑的副本进行修补时,它并没有得到更新。
为了强调这一点,该文件甚至包含一个标题行:
<!-- Copyright (c) 2022 Oracle Corporation. All Rights Reserved.
Do not modify the contents of this file by hand.
我想现在很明显,您不会说服 Oracle Support 批准手动编辑。
运行 2 - 手动编辑 oui-patch.xml
让我稍微清除一下 opatches 的记忆。为什么 opatch 需要检查我几个月前从硬盘中删除的补丁?
在我的小实验开始时,我的$ORACLE_HOME/inventory/ContentsXML/oui-patch.xml有1001 行。
你会看到结构很简单。补丁包包含在以下之间的 XML 标记中:
<ONEOFF REF_ID="30125133" UNIQ_ID="23151502" TYPE="upgrade" LANGS="en" ROLLBACK="F" XML_INV_LOC="oneoffs/30125133/" ACT_INST_VER="12.2.0.7.0" INSTALL_TIME="2019.Oct.16 19:27:15 CEST">
<DESC>Database Release Update : 19.5.0.0.191015 (30125133)</DESC>
<REF_LIST>
...
</BUG_LIST>
<FILE_LIST/>
<PROPERTY_LIST/>
</ONEOFF>
我现在会小心地删除除 19.14.0 补丁程序块之外的所有块。
自从我在博客上收到评论以来,一个非常重要的注释:
当您的 XML 文件中有一个关闭和/或合并此特定 RU 的补丁时,请留下它们并且不要将它们清除。仅删除较旧的条目。因此,我将例如“n-1”视为带有 OJVM 19.14.0 的 19.14.0,并在其上添加一次性补丁。
结果,我的文件仅包含136 行和两个补丁包,即 19.14.0 RU 和 19.14.0 OJVM:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2022 Oracle Corporation. All Rights Reserved.
Do not modify the contents of this file by hand.
-->
<ONEOFF_LIST>
<ONEOFF REF_ID="33197296" UNIQ_ID="24445578" TYPE="unknown" LANGS="en" ROLLBACK="F" XML_INV_LOC="oneoffs/33197296/" ACT_INST_VER="12.2.0.7.0" INSTALL_TIME="2021.Dec.16 09:42:01 CET">
<DESC>JDK BUNDLE PATCH 19.0.0.0.211019</DESC>
<REF_LIST>
<REF NAME="oracle.jdk" VER="1.8.0.191.0"/>
<REF NAME="oracle.jdk" VER="1.8.0.201.0"/>
</REF_LIST>
<BUG_LIST>
<BUG>33197296</BUG>
</BUG_LIST>
<FILE_LIST/>
<PROPERTY_LIST/>
</ONEOFF>
<ONEOFF REF_ID="33515361" UNIQ_ID="24589353" TYPE="upgrade" LANGS="en" ROLLBACK="F" XML_INV_LOC="oneoffs/33515361/" ACT_INST_VER="12.2.0.7.0" INSTALL_TIME="2022.Jan.19 21:37:55 CET">
<DESC>Database Release Update : 19.14.0.0.220118 (33515361)</DESC>
<REF_LIST>
<REF NAME="oracle.help.ohj" VER="11.1.1.7.0" PATCH_LEVEL="3"/>
<REF NAME="oracle.perlint" VER="5.28.1.0.0" PATCH_LEVEL="3"/>
<REF NAME="oracle.rdbms.locator" VER="19.0.0.0.0" PATCH_LEVEL="3"/>
<REF NAME="oracle.perlint.expat" VER="2.0.1.0.4" PATCH_LEVEL="3"/>
<REF NAME="oracle.rdbms.rsf" VER="19.0.0.0.0" PATCH_LEVEL="3"/>
... here I cut several lines to shorten it only for display - these lines were left in the file I used ...
<REF NAME="oracle.precomp.lang" VER="19.0.0.0.0" PATCH_LEVEL="3"/>
<REF NAME="oracle.jdk" VER="1.8.0.191.0" PATCH_LEVEL="3"/>
<REF NAME="oracle.jdk" VER="1.8.0.201.0" PATCH_LEVEL="3"/>
</REF_LIST>
<BUG_LIST>
<BUG>7391838</BUG><BUG>8460502</BUG><BUG>8476681</BUG><BUG>14570574</BUG><BUG>14735102</BUG><BUG>15931756</BUG><BUG>15959416</BUG><BUG>16662822</BUG><BUG>16664572</BUG><BUG>16750494</BUG><BUG>17275499</BUG><BUG>17395507</BUG><BUG>17428816</BUG><BUG>17468475</BUG><BUG>17777718</BUG><BUG>18534283</BUG><BUG>18697534</BUG><BUG>19080742</BUG><BUG>19138896</BUG><BUG>19697993</BUG><BUG>20007421</BUG><BUG>20083476</BUG><BUG>20313356</BUG><BUG>20319830</BUG><BUG>20479545</BUG><BUG>20867658</BUG><BUG>20922160</BUG><BUG>21119541</BUG><BUG>21232786</BUG><BUG>21245711</BUG><BUG>21374587</BUG><BUG>21528318</BUG><BUG>21629064</BUG>
... here I cut over 100 lines of bug numbers only for display - those were left in the file I used ...
<BUG>33482590</BUG><BUG>33489699</BUG><BUG>33490031</BUG><BUG>33500486</BUG><BUG>33507610</BUG><BUG>33507953</BUG><BUG>33514179</BUG><BUG>33515115</BUG><BUG>33540746</BUG><BUG>33558058</BUG><BUG>33558251</BUG><BUG>33558391</BUG><BUG>33559316</BUG><BUG>33563167</BUG><BUG>33599734</BUG><BUG>33613512</BUG><BUG>33632051</BUG><BUG>33635094</BUG><BUG>33651003</BUG><BUG>33656104</BUG><BUG>33656608</BUG><BUG>33674035</BUG><BUG>33661960</BUG><BUG>30166257</BUG><BUG>33384092</BUG><BUG>33618962</BUG>
</BUG_LIST>
<FILE_LIST/>
<PROPERTY_LIST/>
<SUPERSEDES>
<REF_ID REF_ID="33192793" UNIQ_ID="24462514" LANGS="en"/>
</SUPERSEDES>
</ONEOFF>
<ONEOFF REF_ID="33561310" UNIQ_ID="24538862" TYPE="unknown" LANGS="en" ROLLBACK="F" XML_INV_LOC="oneoffs/33561310/" ACT_INST_VER="12.2.0.7.0" INSTALL_TIME="2022.Jan.19 22:12:28 CET">
<DESC>OJVM RELEASE UPDATE: 19.14.0.0.220118 (33561310)</DESC>
<REF_LIST>
<REF NAME="oracle.javavm.server" VER="19.0.0.0.0"/>
<REF NAME="oracle.javavm.server.core" VER="19.0.0.0.0"/>
<REF NAME="oracle.rdbms.dbscripts" VER="19.0.0.0.0"/>
<REF NAME="oracle.rdbms" VER="19.0.0.0.0"/>
<REF NAME="oracle.javavm.client" VER="19.0.0.0.0"/>
</REF_LIST>
<BUG_LIST>
<BUG>29445548</BUG><BUG>29254623</BUG><BUG>29540327</BUG><BUG>29774362</BUG><BUG>30134746</BUG><BUG>30160625</BUG><BUG>30534662</BUG><BUG>29512125</BUG><BUG>29942275</BUG><BUG>30855101</BUG><BUG>31306261</BUG><BUG>31359215</BUG><BUG>30895577</BUG><BUG>29224710</BUG><BUG>26716835</BUG><BUG>31668872</BUG><BUG>32165759</BUG><BUG>32069696</BUG><BUG>32032733</BUG><BUG>30889443</BUG><BUG>30674373</BUG><BUG>32167592</BUG><BUG>32523206</BUG><BUG>29415774</BUG><BUG>28777073</BUG><BUG>32124570</BUG><BUG>31247838</BUG><BUG>29540831</BUG><BUG>32892883</BUG><BUG>31776121</BUG><BUG>33223248</BUG><BUG>33563137</BUG><BUG>33184467</BUG><BUG>31844357</BUG>
</BUG_LIST>
<FILE_LIST/>
<PROPERTY_LIST/>
</ONEOFF>
</ONEOFF_LIST>
清除 opatches 内存后的结果
我猜你会感到惊讶
将数据库 19.15.0 RU应用到我的环境中,并预先手动运行所有检查:
- 手动预检查冲突:9 秒
- 手动预检查空间: 8 秒
- opatch 在“应用”期间完成的预检查:12 秒
- 19.15.0 的原始补丁应用持续时间:
3 分 51 秒,包括复制文件以进行回滚
我想你不会有更多的问题了。
此外,对于OJVM RU,检查次数增加了 1-2 秒。两次检查每次都需要 10 秒。
最终的补丁应用需要端到端的1 分 11 秒,包括所有内容。
总而言之,用 19.15.0 RU 数据库和 19.15.0 OJVM 修补我的环境只用了不到 6 分钟。这大约是之前使用 1001 行长的补丁清单文件对我的系统进行一次检查所花费的时间。
重新审视n-1 讨论
正如您可能已经在本系列的初始博客文章中读到的那样,我总是被抛回 n-1 主题。由于 opatch 目前不提供仅清除 n-1 个补丁之前的所有内容的可能性,例如仅保留当前的补丁信息,例如 2022 年 4 月和之前的补丁包 2022 年 1 月,但删除所有早于 2022 年 1 月的补丁,我们在这里自助。
基本上,该变通方法确实完成了 n-1 清除机制所做的工作:清除 opatches 的内存并仅保留有关前一个补丁的信息。
现在我也和 opatch 团队讨论了这个问题。有人告诉我,实施这样的清除行为并非易事。但团队会讨论和考虑。
我仍然非常肯定它迟早会到来。
请记住,当您使用解决方法来保护您以前的oui-patches.xml文件时。
客户体验
我想分享 Sven 的结果,因为他重做并比较了运行,没有更改 XML 文件和我提出的更改。以前,修补时间是我见过的最糟糕的。Sven 在这里使用 SPARC Solaris,以下时间仅适用于数据库主目录的 19.15.0。
- 使用 opatch 12.2.0.1.29(1 月 22 日 opatch)测试运行 1
完成会话所需的时间 146 分 11 秒 - 使用 opatch 12.2.0.1.30(4 月 22 日 opatch)测试运行 2
完成会话所需的时间 111 分 51 秒 - 使用 opatch 12.2.0.1.30 和 oui-patch.xml 编辑测试运行 3 到 n-1
完成会话所需的时间 40 分 58 秒
所以你认识到两件事:
- 对 opatch 版本有依赖性(未来的博文)
- 使用 n-1 个库存文件有显着改进
总结
让我在这里总结一下这个小小的练习。
首先,很明显不支持手动编辑$ORACLE_HOME/inventory/ContentsXML/oui-patch.xml。但是这样做非常有效。但请记住,您将看到我上面描述的这个问题,只有通过就地修补。当您按照我们的建议进行异地修补时,您将从全新的$ORACLE_HOME/inventory/ContentsXML/oui-patch.xml 开始。因此,这个问题根本不会影响您。
但是,如果您遇到较长的二进制修补时间,请检查您的日志。即使您没有事先进行预检查。尤其是在不止一个节点获得补丁的 RAC 环境中,尤其是在您不仅要为数据库而且还要为 Grid Infrastructure 打补丁的环境中,您可能需要检查您的 opatch 日志文件。当您调用 opatch 时,opatch 始终会告诉您日志的位置。您将始终在$ORACLE_HOME/cfgtoollogs/opatch中找到它们。
上面我小小的测试环境的结果令人印象深刻。我将 16 分钟以上的修补持续时间与大型 xml 文件进行比较,与缩小文件的 5.5 分钟进行比较——即使我没有事先运行检查并将其留给 opatch。当我自己手动运行所有推荐的检查时,结果会变得更糟。
当然,开发也注意到了这一点。而且我们迟早会看到修复或清除机制。但由于这个工具不属于我们的团队,我不能保证任何事情。




