在生产环境中,我们有一个简单的 Zabbix 监控系统,可以很好地收集来自各种 Tomcat 实例和其他 Java 应用程序的指标。
简而言之,这是我们当前的配置(某种程度上是经典的):
[ Zabbix Server ] → [ Zabbix Agent (passive) ] → [ Zabbix Java Gateway ] → [ Tomcat ]
它的工作原理如下:
[ Zabbix Server ] ← [ Zabbix Proxy ] → [ Zabbix Agent (passive) ] → [ Zabbix Java Gateway ] → [ Tomcat ]
对于我们来说,上述配置至少可以在以下发行版中的任何本机包中使用:
- Debian GNU/Linux 11(当前稳定版)(https://packages.debian.org/bullseye/zabbix-java-gateway)
- Ubuntu 20.04(当前 LTS)(https://packages.ubuntu.com/focal/zabbix-java-gateway)
- Ubuntu 22.04(当前 LTS)(https://packages.ubuntu.com/jammy/zabbix-java-gateway)
这是我们建议安装代理的示例:
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 在启动时会执行以下操作:
/etc/default/zabbix-java-gateway
如果可用则执行文件- 假设变量
$JAVA
为"java"
默认值-因为该 bash 行的含义是:NEWVAR=${VARNAME:-defaultvalue}
- 默认执行
$JAVA
( )"java"
简而言之,
这就是为什么您只需编辑文件即可/etc/default/zabbix-java-gateway
。我感谢软件包维护者为 Debian 和 Ubuntu 做了如此出色的本机软件包,并允许这个最小解决方案。