下面我将从 核心思路、常用工具、实践代码示例 三个方面,为你详细解析如何使用 Java 进行 Linux 服务器监控。

核心思路
Java 本身是一个运行在 JVM 上的应用,它不直接与操作系统内核交互,要监控 Linux 服务器,Java 程序必须通过某种方式来获取操作系统的信息,主要有以下几种方式:
-
执行 Shell 命令 (最直接、最灵活)
- 原理: Java 的
Runtime.getRuntime().exec()或ProcessBuilder类可以启动一个外部进程,执行 Linux 命令(如top,free,df,iostat等),然后读取命令的输出结果。 - 优点: 几乎可以获取任何 Linux 命令能提供的信息,非常灵活。
- 缺点: 性能开销相对较大,需要解析文本输出,当命令格式变化时,解析逻辑也需要更新。不推荐在生产环境中频繁执行高开销命令。
- 原理: Java 的
-
使用 JNI (Java Native Interface)
- 原理: 通过 JNI 调用 C/C++ 编写的本地库,这些本地库可以直接调用 Linux 内核的 API(如
/proc文件系统、sysfs)来获取系统信息。 - 优点: 性能极高,功能强大,可以获取到最底层的系统状态。
- 缺点: 开发复杂,需要处理 C/C++ 和 Java 之间的数据类型转换和内存管理,并且会失去 Java 的跨平台优势。
- 原理: 通过 JNI 调用 C/C++ 编写的本地库,这些本地库可以直接调用 Linux 内核的 API(如
-
使用成熟的 Java 监控库 (推荐)
(图片来源网络,侵删)- 原理: 很多优秀的开源库已经封装了上述两种方式,提供了简单易用的 Java API 来获取系统信息。
- 优点: 开发效率高,API 友好,性能经过优化,跨平台性好(这些库通常也支持 Windows/macOS)。
- 缺点: 功能可能不如直接调用命令或 JNI 那么无所不能,但对于 95% 的监控场景已经足够。
对于绝大多数 Java 使用成熟的 Java 监控库是最佳实践,只有在有极其特殊的高性能或底层需求时,才考虑 JNI。
常用工具和库
这里重点推荐几个在 Java 社区中广受好评的监控库。
OSHI (推荐首选)
- GitHub: https://github.com/oshi/oshi
- 简介: OSHI 是一个纯 Java 的、跨平台的、轻量级的系统信息库,它不依赖任何本地库,通过解析
/proc,/sys,netstat,lsof,wmic(Windows) 等系统文件和命令输出来获取信息。 - 优点:
- 纯 Java: 无需 JNI,部署简单。
- 跨平台: 一套代码,Linux/Windows/macOS/Unix 均可用。
- 功能全面: 涵盖了 CPU、内存、磁盘、网络、进程等几乎所有核心指标。
- 轻量级: 启动快,内存占用小。
- Maven 依赖:
<dependency> <groupId>com.github.oshi</groupId> <artifactId>oshi-core</artifactId> <version>6.4.0</version> <!-- 请使用最新版本 --> </dependency>
Sigar (功能强大,但较老)
- GitHub: https://github.com/hyperic/sigar
- 简介: Sigar 是一个非常经典的系统信息库,通过 JNI 调用其 C 语言库来获取系统信息,因此性能和功能都非常强大。
- 优点:
- 性能极高: 直接与内核交互。
- 功能极其丰富: 信息非常详尽。
- 缺点:
- 依赖本地库: 需要在服务器上部署对应平台的
.so(Linux) 或.dll(Windows) 文件,增加了部署复杂度。 - 项目更新缓慢: 最后一次更新已是多年前。
- 依赖本地库: 需要在服务器上部署对应平台的
- Maven 依赖:
<dependency> <groupId>org.fusesource</groupId> <artifactId>sigar</artifactId> <version>1.6.4</version> </dependency>
使用 JMX (Java Management Extensions)
- 简介: JMX 是 Java 标准的管理和监控规范,如果你的监控目标是一个 Java 应用(如 Tomcat, Spring Boot),JMX 是最标准、最强大的方式。
- 工作方式: Java 应用可以通过 MBean (Managed Bean) 暴露其内部状态(如内存池、线程数、自定义业务指标),监控程序(如 JConsole, VisualVM, Prometheus + JMX Exporter)可以连接到应用的 JMX 端口,读取这些 MBean 的数据。
- 优点:
- 标准规范: 无需额外库,JDK 自带。
- 功能强大: 可以监控应用内部细节,甚至可以动态修改配置。
- 远程监控: 支持通过网络进行远程监控。
- 缺点:
- 仅限 Java 应用: 无法直接监控操作系统或非 Java 进程。
- 需要应用支持: 目标应用必须开启并正确配置 JMX。
实践代码示例 (使用 OSHI)
下面我们使用 OSHI 库来编写一个 Java 程序,监控 Linux 服务器的核心指标。
项目准备
创建一个 Maven 项目,并在 pom.xml 中添加 OSHI 依赖。

<dependencies>
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.4.0</version>
</dependency>
<!-- 为了更好的格式化输出,可以加一个 Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
</dependencies>
编写监控代码
创建一个 ServerMonitor.java 文件。
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* 使用 OSHI 库进行 Linux 服务器监控
*/
public class ServerMonitor {
private static final SystemInfo si = new SystemInfo();
private static final HardwareAbstractionLayer hal = si.getHardware();
private static final OperatingSystem os = si.getOperatingSystem();
private static final DecimalFormat df = new DecimalFormat("0.00");
public static void main(String[] args) throws InterruptedException {
// 初始化 CPU 上下文,用于计算 CPU 使用率
CentralProcessor processor = hal.getProcessor();
long[] prevTicks = processor.getSystemCpuLoadTicks();
System.out.println("===== Linux 服务器监控开始 =====");
System.out.println("服务器时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("操作系统: " + os.getFamily() + " " + os.getVersionInfo());
System.out.println("=====================================\n");
while (true) {
printSystemInfo();
printCpuInfo(processor, prevTicks);
printMemoryInfo();
printDiskInfo();
printNetworkInfo();
System.out.println("\n-------------------------------------\n");
// 每 5 秒刷新一次
Thread.sleep(5000);
}
}
private static void printSystemInfo() {
System.out.println("--- 系统概览 ---");
System.out.println("主机名: " + os.getNetworkParams().getHostName());
System.out.println("制造商: " + hal.getComputerSystem().getManufacturer());
System.out.println("型号: " + hal.getComputerSystem().getModel());
System.out.println("CPU 逻辑核心数: " + hal.getProcessor().getLogicalProcessorCount());
System.out.println("CPU 物理核心数: " + hal.getProcessor().getPhysicalProcessorCount());
}
private static void printCpuInfo(CentralProcessor processor, long[] prevTicks) {
System.out.println("\n--- CPU 信息 ---");
double cpuLoad = processor.getSystemCpuLoadBetweenTicks(prevTicks) * 100;
System.out.println("CPU 使用率: " + df.format(cpuLoad) + "%");
System.out.println("CPU 上下文切换/秒: " + processor.getSystemCpuLoadTicks()[2]); // ctx switches
System.out.println("CPU 中断/秒: " + processor.getSystemCpuLoadTicks()[3]); // interrupts
// 更新 ticks 用于下一次计算
prevTicks = processor.getSystemCpuLoadTicks();
}
private static void printMemoryInfo() {
System.out.println("\n--- 内存信息 ---");
GlobalMemory memory = hal.getMemory();
long total = memory.getTotal();
long available = memory.getAvailable();
long used = total - available;
double usage = (double) used / total * 100;
System.out.println("总内存: " + formatBytes(total));
System.out.println("已用内存: " + formatBytes(used) + " (" + df.format(usage) + "%)");
System.out.println("可用内存: " + formatBytes(available) + " (" + df.format(100 - usage) + "%)");
}
private static void printDiskInfo() {
System.out.println("\n--- 磁盘信息 ---");
hal.getDiskStores().forEach(diskStore -> {
System.out.println("磁盘名称: " + diskStore.getName());
System.out.println("磁盘读取: " + formatBytes(diskStore.getReadBytes()) + " / " + diskStore.getReadCount() + " 次");
System.out.println("磁盘写入: " + formatBytes(diskStore.getWriteBytes()) + " / " + diskStore.getWriteCount() + " 次");
});
}
private static void printNetworkInfo() {
System.out.println("\n--- 网络信息 ---");
hal.getNetworkIFs().forEach(networkIF -> {
System.out.println("网络接口: " + networkIF.getName());
System.out.println("网络发送: " + formatBytes(networkIF.getBytesSent()) + " / " + networkIF.getPacketsSent() + " 个包");
System.out.println("网络接收: " + formatBytes(networkIF.getBytesRecv()) + " / " + networkIF.getPacketsRecv() + " 个包");
});
}
// 格式化字节大小
private static String formatBytes(long bytes) {
if (bytes < 1024) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(1024));
char pre = "KMGTPE".charAt(exp - 1);
return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre);
}
}
运行和解读
- 将代码编译打包成 JAR 文件。
- 将 JAR 文件上传到你的 Linux 服务器。
- 运行
java -jar your-jar-file.jar。
你将看到类似下面格式的输出,并且每 5 秒刷新一次:
===== Linux 服务器监控开始 =====
服务器时间: 2025-10-27 10:30:00
操作系统: Linux 5.4.0-150-generic
=====================================
--- 系统概览 ---
主机名: server-01
制造商: innotek GmbH
型号: VirtualBox
CPU 逻辑核心数: 4
CPU 物理核心数: 2
--- CPU 信息 ---
CPU 使用率: 5.20%
CPU 上下文切换/秒: 1200
CPU 中断/秒: 350
--- 内存信息 ---
总内存: 7.63 GB
已用内存: 2.10 GB (27.55%)
可用内存: 5.53 GB (72.45%)
--- 磁盘信息 ---
磁盘名称: sda
磁盘读取: 1.2 GB / 5000 次
磁盘写入: 500 MB / 3000 次
--- 网络信息 ---
网络接口: eth0
网络发送: 100 MB / 1000 个包
网络接收: 500 MB / 5000 个包
-------------------------------------
进阶:构建一个完整的监控系统
上面的代码只是一个简单的命令行工具,一个生产级的监控系统通常包含以下部分:
-
数据采集端 (Agent):
- 在每台需要监控的服务器上部署一个轻量级的 Agent 程序。
- 这个 Agent 可以使用 OSHI 或其他库,定期(如每 15 秒)采集服务器指标。
- 将采集到的数据格式化(如 JSON),并推送到一个中央存储。
-
数据存储:
- 时序数据库: 这是监控数据存储的最佳选择。InfluxDB, Prometheus, VictoriaMetrics,它们专门为时间序列数据优化,具有高效的写入和查询性能。
- 数据库: 也可以使用 MySQL, PostgreSQL, 但需要自行设计表结构和索引,性能通常不如时序数据库。
-
数据展示与告警:
- 可视化工具:
- Grafana: 业界标准,可以连接各种数据源(包括 InfluxDB, Prometheus),通过图表、仪表盘直观展示数据。
- Prometheus UI: 如果使用 Prometheus,其自带的 UI 也可以进行查询和展示。
- 告警系统:
- Alertmanager: Prometheus 生态系统的一部分,负责处理告警规则,并通过邮件、Slack、Webhook 等方式发送通知。
- Grafana Alerting: Grafana 内置的告警功能,可以基于图表数据设置阈值触发告警。
- 可视化工具:
架构图示例
+----------+ +-----------------+ +-------------+ +-------------+
| | | | | | | |
| Server |----->| Java Agent |----->| InfluxDB |----->| Grafana |
| (Node1) | | (使用 OSHI 采集) | | (存储时序数据) | | (可视化展示) |
| | | | | | | |
+----------+ +-----------------+ +-------------+ +-------------+
^ | |
| | | (告警规则)
| v |
| +-------------+ |
| | Alertmanager|<--------------+
| | (发送通知) |
+------------------------------------>+-------------+
- 入门和快速实现: 使用 OSHI 库,它能满足大部分服务器监控需求,且开发简单,部署方便。
- 深度监控 Java 应用: 使用 JMX,这是监控和管理 Java 应用的标准方式。
- 构建企业级监控: 采用 Agent + 时序数据库 + 可视化工具 的架构,Java 可以用来编写 Agent,将数据发送到 InfluxDB 或 Prometheus,然后用 Grafana 做出漂亮的监控大盘和告警。
希望这份详细的指南能帮助你开始 Java Linux 服务器监控的实践!
