AEM 日志中显示 SegmentNotFoundException 并且实例无法正常工作

当存储库存在完整性问题时,出现 SegmentNotFoundException。

问题

您在 AEM 日志文件中看到 SegmentNotFoundException,并且 AEM 未按预期工作

或者

当存储库存在完整性问题时,运行离线压缩可能会失败,并出现 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)
...

或者

当存储库存在完整性问题时,运行离线压缩可能会失败,并出现 IllegalArgumentException。可以在日志中找到类似以下内容的堆栈跟踪:

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)

环境

AEM 6.x

原因

当离线压缩尝试读取节点时,如果对应的区段不存在,则会返回 SegmentNotFoundException。导致该问题的根本原因可能有多种:

  1. 手动干预(例如 rm -rf /)导致相关区段移除。
  2. 修订垃圾收集造成相关区段移除。 
  3. 代码中的某些错误导致无法找到相关区段。

如果问题是由于修订垃圾收集(第 2 点)所导致,请确保禁用离线压缩,以避免更多节点遭受损坏。

解决方案

 

我们可以采取多种措施来解决这个问题,并成功完成离线压缩过程。

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

A. 恢复到上一次已知良好的区段存储修订版本。

可使用 oak-run 的 check 运行模式,确定上一次已知良好的区段存储修订版本。这个修订版本可用来把损坏的区段存储手动恢复到最新的良好修订状态。

注意:

此过程会将系统中的数据回滚到以前的时间点。如果您希望避免丢失系统中的更改,可尝试下面的方案 B

要进行检查和恢复,请执行以下操作:

  1. 从这个网页 http://repo1.maven.org/maven2/org/apache/jackrabbit/oak-run/ 下载 oak-run jar 文件

  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 文件。

  6. 如果使用的是 AEM 6.0,请下载与 AEM 中安装的版本相匹配的 oak-run 版本来执行其余的步骤。从这个网页 http://repo1.maven.org/maven2/org/apache/jackrabbit/oak-run/ 下载相应的 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 中,如果安装 TarMK 时没有配置 FileDatastore,当发生二进制文件损坏的情况时,可执行以下操作。

注意:

以下过程适用于超级用户。删除损坏的节点时,您需要确保这些节点不是系统节点(例如,/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/node
    ERROR java.lang.UnsupportedOperationException:
    Cannot write to read-only store
            at 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-all>>nohup.out &

  6. 运行离线压缩。如果您不知道如何运行离线压缩,请访问此处

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

Adobe 徽标

登录到您的帐户