“SegmentNotFoundException 和 IllegalArgumentException”

描述

环境
Adobe Experience Manager

问题

场景1
运行离线压缩可能会失败,因为 SegmentNotFoundException 存储库存在完整性问题时。

您观察到 SegmentNotFoundException 在AEM日志文件中,AEM无法按预期工作。

场景2

运行离线压缩可能会失败,因为 SegmentNotFoundException 存储库存在完整性问题时。

日志中显示与下面类似的堆栈跟踪:

13:51:21.523 main ERROR o.a.j.o.p.segment.SegmentTracker - Segment not found: 4d139bc4-150c-4f0a-b82a-40a4e519fe8a. Creation date delta is 4 ms.
org.apache.jackrabbit.oak.plugins.segment.SegmentNotFoundException: Segment 4d139bc4-150c-4f0a-b82a-40a4e519fe8a not found
at org.apache.jackrabbit.oak.plugins.segment.file.FileStore.readSegment(FileStore.java:855) oak-run-1.0.22.jar:1.0.22
at org.apache.jackrabbit.oak.plugins.segment.SegmentTracker.getSegment(SegmentTracker.java:134)  oak-run-1.0.22.jar:1.0.22
at org.apache.jackrabbit.oak.plugins.segment.SegmentId.getSegment(SegmentId.java:101) oak-run-1.0.22.jar:1.0.22
...
Exception in thread "main" org.apache.jackrabbit.oak.plugins.segment.SegmentNotFoundException: Segment 4d139bc4-150c-4f0a-b82a-40a4e519fe8a not found
at org.apache.jackrabbit.oak.plugins.segment.file.FileStore.readSegment(FileStore.java:855)
at org.apache.jackrabbit.oak.plugins.segment.SegmentTracker.getSegment(SegmentTracker.java:134)
at org.apache.jackrabbit.oak.plugins.segment.SegmentId.getSegment(SegmentId.java:101)
...

场景3

运行离线压缩可能会失败,因为 IllegalArgument 存储库存在完整性问题时出现异常。

日志中显示与下面类似的堆栈跟踪:

java.lang.IllegalArgumentException

at com.google.common.base.Preconditions.checkArgument(Preconditions.java:77)

at org.apache.jackrabbit.oak.plugins.segment.ListRecord.(ListRecord.java:41)

at org.apache.jackrabbit.oak.plugins.segment.ListRecord.getEntry(ListRecord.java:64)

at org.apache.jackrabbit.oak.plugins.segment.ListRecord.getEntries(ListRecord.java:81)

at org.apache.jackrabbit.oak.plugins.segment.SegmentStream. read (SegmentStream.java:153)

at org.apache.jackrabbit.oak.commons.IOUtils.readFully(IOUtils.java:53)

at org.apache.jackrabbit.oak.plugins.segment.Compactor.getBlobKey(Compactor.java:412)

at org.apache.jackrabbit.oak.plugins.segment.Compactor.compact(Compactor.java:362)

at org.apache.jackrabbit.oak.plugins.segment.Compactor.compact(Compactor.java:321)

at org.apache.jackrabbit.oak.plugins.segment.Compactor.access$500(Compactor.java:54)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.propertyAdded(Compactor.java:227)

at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.propertyAdded(CancelableDiff.java:47)

at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:156)

at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff. diff (Compactor.java:214)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)

at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)

at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:161)

at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff. diff (Compactor.java:214)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)

at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)

at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:161)

at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff. diff (Compactor.java:214)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)

at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)

at org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.compareAgainstEmptyState(EmptyNodeState.java:161)

at org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState.compareAgainstBaseState(SegmentNodeState.java:434)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff. diff (Compactor.java:214)

at org.apache.jackrabbit.oak.plugins.segment.Compactor$CompactDiff.childNodeAdded(Compactor.java:263)

at org.apache.jackrabbit.oak.plugins.segment.CancelableDiff.childNodeAdded(CancelableDiff.java:74)

原因

A SegmentNotFoundException 当压缩尝试读取节点时区段不存在时,会返回。
这可能是由不同的根本原因造成的:

  1. 该区段已通过手动干预删除(例如: rm -rf /)。
  2. 高渠段已通过修订垃圾收藏集移除。
  3. 由于代码中的一些错误,无法找到该区段。

如果问题是由修订垃圾收集引起(原因#2), 确保禁用在线压缩 以避免更多节点损坏。

分辨率

解决方案

我们可以遵循多种程序来解决这种情况并成功完成离线压缩。

重要的:​在执行以下步骤之前,请对存储库执行完整备份。

A. 恢复到区段存储的最后一个已知良好修订。

Oak-run 的检查运行模式可用于确定区段存储的最后一个已知良好修订。这可用于手动将损坏的区段存储恢复为其最新的良好修订。

警告:此过程会将系统中的数据回滚到之前的时间点。如果您希望避免丢失系统中的更改,则可以尝试 选项B 下。

要执行检查和恢复,请执行以下步骤:

  1. 下载 oak-run 此处的jar文件 https://repo1.maven.org/maven2/org/apache/jackrabbit/oak-run/

  2. 停止 AEM。

  3. 运行此命令:

    java -jar oak-run-*.jar check --bin=-1 crx-quickstart/repository/segmentstore/

    此命令向后搜索修订,直到找到一致的修订:

    14:00:30.783 main INFO  o.a.j.o.p.s.f.t.ConsistencyChecker - Found latest good revision afdb922d-ba53-4a1b-aa1b-1cb044b535cf:234880

    (如果 ConsistencyChecker 失败,请转到下一分区)

  4. 通过编辑将存储库还原到此修订版本:

    /crx-quickstart/repository/segmentstore/journal.log

    删除包含最新良好修订的行之后的所有行。

    如果要了解要将存储库还原到的日期和时间,请在 segmentstore 文件夹(替换) afdb922d-ba53-4a1b-aa1b-1cb044b535cf 在 journal.log):

    find . -type f -name "data*.tar" -exec sh -c "tar -tvf {} |grep afdb922d-ba53-4a1b-aa1b-1cb044b535cf" \; -print

    输出将显示该修订的大致日期和时间。

  5. 移除全部 ./crx-quickstart/repository/segmentstore/*.bak files.

  6. 如果使用 AEM6.0,则下载与 AEM 中安装的内容相匹配的 oak-run 版本以完成剩余步骤。

    从此处下载 https://repo1.maven.org/maven2/org/apache/jackrabbit/oak-run/.

  7. 运行 检查点清理 要删除孤立检查点,请执行以下操作:

    java -jar oak-run-*.jar checkpoints ./crx-quickstart/repository/segmentstore rm-unreferenced

  8. 最后,压缩存储库:

    java -jar oak-run-*.jar compact ./crx-quickstart/repository/segmentstore/

B. 手动移除损坏的节点。

在 AEM 中,对于没有配置 FileDatastore 的 TarMK 设置以及二进制文件中存在损坏的情况,您可以执行以下操作。

*注意:*以下程序适用于高级用户。删除损坏的节点时,您需要确保它们不是系统节点(例如 /home, /jcr:system等)。
或者,如果它们是系统节点,则需要确保可以恢复它们。
如果您不确定,请咨询AEM客户关怀团队,以获取有关此处所述步骤的帮助。

  1. 停止 AEM。

  2. 使用Oak运行控制台并加载 childCount groovy脚本来识别区段存储中损坏的节点:

    加载 oak-run 控制台外壳:

    java -jar oak-run-*.jar console crx-quickstart/repository/segmentstore

    在外壳中运行以下两个命令来加载脚本并运行它:

    :load

    https://gist.githubusercontent.com/stillalex/e7067bcb86c89bef66c8/raw/d7a5a9b839c3bb0ae5840252022f871fd38374d3/childCount.groovy

    countNodes(session.workingNode)

    这将导致以下输出指示损坏节点的路径:

    21:21:42.029 main ERROR o.a.j.o.p.segment.SegmentTracker - Segment not found: 63ae05a4-b506-445c-baa2-cfa1b13b6e2f. Creation date delta is 3 ms.

    warning unable to read node /content/dam/test.txt/jcr:content/renditions/original/jcr:content

    在某些情况下,问题会链接到二进制属性,并且 childCount groovy脚本无法找到任何损坏的节点。

    在这些情况下,您可以改用以下命令,该命令将读取遍历期间遇到的每个二进制文件的前1024个字节(请注意,此命令将变慢,仅当上述命令未返回预期结果时才使用):

    countNodes(session.workingNode,true)

  3. 使用删除最后一个命令输出中列出的所有已识别的损坏节点 rmNodes.groovy.

    加载 oak-run 控制台外壳:

    java -jar oak-run-*.jar console crx-quickstart/repository/segmentstore

    加载 groovy 脚本:

    :load

    https://gist.githubusercontent.com/stillalex/43c49af065e3dd1fd5bf/raw/9e726a59f75b46e7b474f7ac763b0888d5a3f0c3/rmNode.groovy

    运行 rmNode 命令移除损坏的节点,通过带有您需要移除的损坏节点的路径替换 /path/to/corrupt/node

    rmNode(session, "/path/to/corrupt/node")

    其中损坏的节点路径是在步骤2中获取的路径,例如: /content/dam/test.txt/jcr:content/renditions/original/jcr:content/.注意:使用 oak-run.jar 版本1.6.13及更高版本,设置 --read-write JVM参数(如果遇到以下错误):

    / rmNode(session,"/path/to/corrupt/node")Removing node /path/to/corrupt/nodeERROR java.lang.UnsupportedOperationException:Cannot write to read-only storeat org.apache.jackrabbit.oak.segment.SegmentWriterBuilder$1.execute (SegmentWriterBuilder.java:171)at org.apache.jackrabbit.oak.segment.SegmentWriter.writeNode (SegmentWriter.java:318)at org.apache.jackrabbit.oak.segment.SegmentNodeBuilder.getNodeState (SegmentNodeBuilder.java:111)at org.apache.jackrabbit.oak.segment.SegmentNodeStore$Commit.init (SegmentNodeStore.java:581)at org.apache.jackrabbit.oak.segment.SegmentNodeStore.merge (SegmentNodeStore.java:333)at org.apache.jackrabbit.oak.spi.state.NodeStore$merge.call (Unknown Source)at groovysh_evaluate.rmNode (groovysh_evaluate:11)
    
  4. 针对步骤 2 中找到的所有节点,请重复步骤 3。

    以上 rmNode 命令应该为损坏路径返回 true,这意味着该命令删除了此损坏路径。

    通过重新运行 rmNode 命令。

    在下次运行时,应返回 false.

    如果您仍然看到存储库中存在相同的路径,则使用oak-run jar的修补版本(即 oak-run-1.2.18-NPR-17596)。

    修补版本的oak-run jar有何用途?

    此版本的jar会跳过压缩中不可读的二进制文件,将其替换为0字节二进制文件,并记录异常和系统路径。

    这样压缩的存储库随后应该传递oak-run检查、节点计数脚本,并且您还应该能够使用未修补的oak-run再次压缩它。

  5. 通过使用以下列出检查点来执行检查点清理。

    如果有多个检查点,则清理它们:

    nohup java -Xmx4096m -jar oak-run-1.2.18.jar checkpoints /app/AEM6/author/crx-quickstart/repository/segmentstore rm-allnohup.out &

  6. 运行离线压缩。

    如果您不知道如何运行离线压缩,请参阅 Oak离线压缩说明 在GitHub Gist上。

  7. 启动服务器并等待索引完成。

在此页面上