使用自定义 Java 版本修复 Zabbix Java Gateway(错误“由较新版本的 Java Runtime 编译”)

使用自定义 Java 版本修复 Zabbix Java Gateway(错误“由较新版本的 Java Runtime 编译”)

在生产环境中,我们有一个简单的 Zabbix 监控系统,可以很好地收集来自各种 Tomcat 实例和其他 Java 应用程序的指标。

简而言之,这是我们当前的配置(某种程度上是经典的):

[ Zabbix Server ] → [ Zabbix Agent (passive) ] → [ Zabbix Java Gateway ] → [ Tomcat ]

它的工作原理如下:

[ Zabbix Server ] ← [ Zabbix Proxy ] →  [ Zabbix Agent (passive) ] → [ Zabbix Java Gateway ] → [ Tomcat ]

对于我们来说,上述配置至少可以在以下发行版中的任何本机包中使用:

这是我们建议安装代理的示例:

sudo apt install zabbix-agent zabbix-java-gateway

问题

出于应用原因,我们现在需要自定义 Java JDK。但是,它与 Zabbix Java Gateway 不兼容。

例如,如果我们在非标准的地方配置一个 Java JDK,以避免与现有包发生任何可能的冲突,然后我们将其设置为默认值,如下所示:

update-alternatives --install /usr/bin/java java /opt/jdk-production/bin/java 2222
update-alternatives --config java

从那时起,systemd 守护进程zabbix-java-gateway停止工作。

这是以下堆栈跟踪:

$ journalctl -fu zabbix-java-gateway
Apr 27 16:09:22 example-hostname systemd[1]: Starting Zabbix Java Gateway...
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]: Error: A JNI error has occurred, please check your installation and try again
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]: Exception in thread "main" java.lang.UnsupportedClassVersionError: com/zabbix/gateway/JavaGateway has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.lang.ClassLoader.defineClass1(Native Method)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.security.AccessController.doPrivileged(Native Method)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[956]:         at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:601)
Apr 27 16:09:22 example-hostname zabbix_java_gateway[947]: Zabbix Java Gateway did not start
Apr 27 16:09:22 example-hostname systemd[1]: zabbix-java-gateway.service: Control process exited, code=exited, status=1/FAILURE
Apr 27 16:09:22 example-hostname systemd[1]: zabbix-java-gateway.service: Failed with result 'exit-code'.
Apr 27 16:09:22 example-hostname systemd[1]: Failed to start Zabbix Java Gateway.

因此,该包显然与我们基于 Java 8 的 JDK 不兼容。

简而言之,我们希望:

  • 只需修复 Zabbix Java Gateway
  • 尽可能避免安装非本地包(避免安装另一个 Zabbix Java Gateway)
  • 可能的话,保留我们自定义的 Java 版本作为默认版本

问题

Debian 方式或 Ubuntu 方式如何修复与 Zabbix Java Gateway 类似的问题?

答案1

怎么了

这个错误显然是正常的,因为本机zabbix-java-gateway是使用较新版本的 Java 进行编译的,而您采用的是默认的旧版 Java。

如何修复(进行小幅修改,保留自定义 JDK)

您可以将自定义 Java JDK 保留为默认值,并修复此问题。

幸运的是,该软件包zabbix-java-gateway支持一种简单的方法来采用任何 Java 版本。此外,您甚至不需要安装额外的 Java 版本,因为您已经已安装所需的 OpenJDK 作为 Zabbix Java Gateway 的依赖项。

您只需要强制 Zabbix Java Gateway 再次采用 OpenJDK,仅针对该可执行文件。

创建此文件:

/etc/default/zabbix-java-gateway

并贴出类似的内容:

JAVA=/opt/path-to-your-jdk/java

例如,对于 Ubuntu 22.04 LTS,这是该文件的有效内容:

JAVA=/usr/lib/jvm/java-11-openjdk-amd64/bin/java

如果你是不是确保您的 OpenJDK 的 Java 路径正确,请使用以下命令仔细检查:

update-alternatives --list java | grep openjdk

此时只需重新启动您的服务:

sudo systemctl restart zabbix-java-gateway

一切都会好起来。

这样,您可以保留自定义 JDK,但 Zabbix Java Gateway 使用本机 JDK。


现在只需说明一下为什么 ↑ 有效。

这是可行的,因为 Zabbix Java Gateway 的 systemd 守护程序以这种方式工作(这里来自 Ubuntu 22.04 当前 LTS):

$ systemctl cat zabbix-java-gateway
# /etc/systemd/system/zabbix-java-gateway.service
[Unit]
Description=Zabbix Java Gateway
After=syslog.target
After=network.target

[Service]
Type=forking
KillMode=process
PIDFile=/run/zabbix/zabbix_java_gateway.pid
ExecStart=/usr/sbin/zabbix_java_gateway
SuccessExitStatus=143
User=zabbix
Group=zabbix

[Install]
WantedBy=multi-user.target

如果你检查中提到的可执行文件ExecStart,它有这样的内部逻辑:

...
if [ -r "/etc/default/zabbix-java-gateway" ]; then
        . /etc/default/zabbix-java-gateway
fi
...

JAVA=${JAVA:-java}

...

COMMAND_LINE="$JAVA 

...

exec $COMMAND_LINE

所以这实际上意味着 Zabbix Java Gateway 在启动时会执行以下操作:

  1. /etc/default/zabbix-java-gateway如果可用则执行文件
  2. 假设变量$JAVA"java"默认值-因为该 bash 行的含义是:NEWVAR=${VARNAME:-defaultvalue}
  3. 默认执行$JAVA( )"java"

简而言之,

这就是为什么您只需编辑文件即可/etc/default/zabbix-java-gateway。我感谢软件包维护者为 Debian 和 Ubuntu 做了如此出色的本机软件包,并允许这个最小解决方案。

相关内容