返回

解决Scriptella报错: Cannot invoke ... because "anyController" is null

java

解决 Scriptella 中 "Cannot invoke "jdk.internal.platform.CgroupInfo.getMountPoint()" because "anyController" is null" 错误

在使用 Scriptella 将 CSV 文件数据导入 MySQL 数据库时,你碰到了这个错误:java.lang.NullPointerException: Cannot invoke "jdk.internal.platform.CgroupInfo.getMountPoint()" because "anyController" is null。别慌,我们来一步步解决。

一、问题根源

这个错误信息看着吓人,实际上跟你的 CSV 连接或者 temps.etl.xml 配置关系不大。它通常与 Java 运行时环境(JRE)或 Java 开发工具包(JDK)尝试访问容器(如 Docker)相关的 cgroup 信息有关,而这些信息可能不存在或无法访问。 更直接地说,很可能是你当前使用的Java版本和 Scriptella 的某些底层操作有兼容问题,或者当前系统环境不满足某些系统资源检测的要求。

二、解决方案

针对这个问题,咱们有几个方法可以试试:

1. 调整 Scriptella 的 JMX 监控 (最推荐)

Scriptella 默认会尝试注册 JMX MBean 来进行性能监控, 问题的根源就在这里. 我们可以通过关闭这个功能来避免这个问题。

  • 原理: Scriptella 利用 Java Management Extensions (JMX) 来暴露运行时指标。 这个错误表明 JMX 尝试获取 cgroup 信息时失败。禁用 JMX 可以绕过这个有问题的步骤。

  • 操作步骤:

    1. 在你的 temps.etl.xml 文件里, 找到 <etl> 标签。
    2. <etl> 标签里, 添加 disable-jmx="true" 属性。
  • 修改后的 temps.etl.xml:

    <!DOCTYPE etl SYSTEM "http://scriptella.org/dtd/etl.dtd">
    <etl disable-jmx="true">
    
        <properties>
            <include href="connexion.properties"/>
        </properties>
        <connection id="db_out" driver="auto" url="$url" user="$user" password="$password" classpath="~/Scriptella/lib/mysql-connector-java-5.1.39-bin.jar" />
        <connection id="temps_csv_in" driver="csv" url="../data/temps.csv" />
    
        <query connection-id="temps_csv_in">
            <script connection-id="db_out">
                INSERT INTO temps(annee,mois,jour) VALUES (?annee,?mois,?jour);
            </script>
        </query>
    </etl>
    
  • 安全建议: 禁用 JMX 会导致无法通过 JConsole 或其他 JMX 客户端监控 Scriptella 的运行状态。如果你不依赖这个功能,禁用是安全的.

2. 换个 Java 版本试试

有些时候, 特定 Java 版本可能会跟 Scriptella 或底层库有冲突。换个 JDK 版本有时能直接解决问题。

  • 原理: 不同版本的 JDK 在实现上可能存在细微差异。有些 JDK 版本可能更稳定, 或者更好地处理了与 cgroup 相关的操作。

  • 操作步骤:

    1. 先确定你当前用的 Java 版本:在命令行输入 java -version
    2. 下载并安装另一个 JDK 版本,例如,如果你目前用的是 JDK 17,可以试试 JDK 11 或 JDK 8 (推荐使用 LTS 版本,长期支持版)。可以从 AdoptOpenJDK, Oracle, 或其他 JDK 提供商那里下载。
    3. 配置你的系统或 Scriptella 启动脚本,让它使用新安装的 JDK. 保证PATH环境变量指向正确的Java版本.
    4. 再次运行 Scriptella 脚本。
  • 命令行示例(Linux/macOS, 假设你安装了 JDK 11):

    # 临时设置 JAVA_HOME 和 PATH
    export JAVA_HOME=/path/to/your/jdk11
    export PATH=$JAVA_HOME/bin:$PATH
    java -jar scriptella.jar -f temps.etl.xml # 或者你启动 Scriptella 的命令
    
  • 安全建议: 使用旧版本的Java可能会有一些安全性问题,一定要下载可信赖来源的Java,安装后尽快进行安全更新。

3. (进阶)检查并配置 cgroup 环境 (如果适用)

如果你的程序确实需要用到 cgroup 功能 (通常在容器化环境中),而且你确定 必须 启用 JMX,那就要保证 cgroup 环境配置正确。

  • 原理: 如果你的应用在容器内运行,或者明确需要访问 cgroup 信息,那么确保 cgroup 正确挂载和配置是必要的。

  • 操作步骤 (以 Docker 为例):

    1. 确认容器是否启用了 cgroup v2: 有些老版本的 Docker 或容器运行时默认使用 cgroup v1。 你可以通过 docker info 命令查看。如果 Cgroup Version: 2 存在则代表是Cgroup V2, 反之则是 V1.
    2. 如果不是CGroupV2 ,并且你使用了较新版本的Java,你可以考虑使用cgroup v2. 这需要你宿主机系统支持. 你可以通过添加启动参数强制Java使用旧的Cgroup API,启动参数: -Djdk.internal.platform.cgroupv1=true ,这个不是特别推荐,仅仅是提供了这个选择。
    3. 确保必要的 cgroup 控制器已挂载: 在 cgroup v2 中,你需要确保所需的控制器(如 memory, cpu)在容器内部是可用的。这通常在启动容器时通过挂载 /sys/fs/cgroup 来完成。
    4. 权限问题: 确保 Scriptella 运行的用户具有访问 cgroup 文件系统的权限。
  • 命令行示例 (仅作参考,具体取决于你的容器配置):

    # 查看 cgroup 挂载情况 (在容器内部或宿主机上)
    cat /proc/self/cgroup
    
    # 如果需要, 确保 /sys/fs/cgroup 已正确挂载 (可能需要在 Dockerfile 或容器编排配置中设置)
    
    • 这是一个非常进阶的方案,在确定需要此项时再操作。

4. 更新 Scriptella (不太可能,但值得尝试)

虽然可能性比较小, 但也可以看看有没有 Scriptella 的新版本。新版本或许修复了这个问题。

  • 原理: 新版本可能包含针对特定 JDK 版本或环境的兼容性修复。
  • 操作步骤:
    1. 访问 Scriptella 的官方网站或代码仓库,查看是否有新版本发布。
    2. 下载最新版本的 Scriptella。
    3. 替换你当前使用的 Scriptella JAR 文件。
    4. 重新尝试.
      通常,按照前面几个方法进行调整,问题基本都能解决。记住在调整系统环境或Java版本之前最好先备份你的配置。如果还有任何其他问题,记得及时寻求帮助。