Zabbix/J监控框架和Spring框架的整合方法

Zabbix/J是一个Java版本的系统监控框架,它可以完美地兼容于Zabbix监控系统,使得开发、运维等技术人员能够对整个业务系统的基础设施、应用软件/中间件和业务逻辑进行全方位的分层监控。

Spring是一种分层的Full-Stack(全栈)的轻量级开源框架,适用于JavaSE和JavaEE。Spring使用基本的JavaBean代替笨重的EJB,这样便降低了企业应用开发的复杂性。

本文将搭建一个最小化的SpringMVC工程,然后会将Zabbix/J整合入这个工程之中,最后在Zabbix的前端页面上监控这个最小化Web系统的三层监控数据。

在阅读本文之前,你最好对Zabbix和Spring有一定的使用经验,有兴趣的话还可以阅读以下扩展文章,有利于加深理解整个流程:

一、环境描述

1. Zabbix Server

2. Zabbix Agent

3. Zabbix/J

  • 操作系统:同Zabbix Agent
  • IP地址:同Zabbix Agent
  • 版本:1.0.1
  • 安装方式:Maven

4. Java环境

  • 操作系统:同Zabbix Agent
  • IP地址:同Zabbix Agent
  • JDK版本:1.7.0_60
  • IDE版本:Spring Tool Suite 3.6.3.RELEASE
  • Spring版本:4.2.4.RELEASE
  • Tomcat版本:apache-tomcat-8.0.24

5. Redis缓存

二、搭建最小化的SpringMVC工程

本文会将Zabbix/J整合入一个名为SpringTest的最小化工程,这个工程请参考《如何搭建SpringMVC的最小化工程》进行搭建。注意,由于操作系统和使用JDK版本不同,请读者自行裁剪和修改参考文章中的详细步骤(例如,将POM文件中的编译器版本修改为1.7,等等)。

三、整合Zabbix/J和Spring

整合Zabbix/J和Spring包含多个步骤,需要对前述的SpringMVC最小化工程进行改造,包括引入依赖包、注入探针实例、修改代码,等等。

1. 引入依赖包

/SpringTest/pom.xml文件中引入Jedis和Zabbix/J的JAR包:

  • jedis-2.1.0.jar:本文将会使用Redis缓存来存储页面访问次数,因此需要通过这个JAR包访问Redis缓存。

  • zabbixj-1.0.1.jar:本文将会在WEB容器的启动监听器中通过注入的方式实例化Zabbix/J探针,因此需要通过这个JAR包提供探针配置和数据收集的功能。

这个POM文件的最终内容如下所示:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>SpringTest</groupId>
  5. <artifactId>SpringTest</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <packaging>war</packaging>
  8. <dependencies>
  9. <!-- springframework begins -->
  10. <dependency>
  11. <groupId>org.springframework</groupId>
  12. <artifactId>spring-webmvc</artifactId>
  13. <version>4.2.4.RELEASE</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-context</artifactId>
  18. <version>4.2.4.RELEASE</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>redis.clients</groupId>
  22. <artifactId>jedis</artifactId>
  23. <version>2.1.0</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>commons-pool</groupId>
  27. <artifactId>commons-pool</artifactId>
  28. <version>1.5.6</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>com.quigley</groupId>
  32. <artifactId>zabbixj</artifactId>
  33. <version>1.0.1</version>
  34. </dependency>
  35. </dependencies>
  36. <build>
  37. <sourceDirectory>src</sourceDirectory>
  38. <plugins>
  39. <plugin>
  40. <artifactId>maven-compiler-plugin</artifactId>
  41. <version>3.5.1</version>
  42. <configuration>
  43. <source>1.7</source>
  44. <target>1.7</target>
  45. </configuration>
  46. </plugin>
  47. <plugin>
  48. <artifactId>maven-war-plugin</artifactId>
  49. <version>2.6</version>
  50. <configuration>
  51. <warSourceDirectory>WebContent</warSourceDirectory>
  52. <failOnMissingWebXml>false</failOnMissingWebXml>
  53. </configuration>
  54. </plugin>
  55. </plugins>
  56. </build>
  57. </project>

2. 新建Redis客户端类

新建RedisClient类,文件路径为:/SpringTest/src/hello/RedisClient.java。这个类提供了手动获取和释放Redis连接的功能,以及设置、获取和删除存储在Redis中的Key-Value对的功能。这个类的代码如下所示:

  1. package hello;
  2. import redis.clients.jedis.Jedis;
  3. import redis.clients.jedis.JedisPool;
  4. import redis.clients.jedis.JedisPoolConfig;
  5. public class RedisClient {
  6. // Redis客户端连接
  7. private Jedis jedis;
  8. // Redis连接池
  9. private JedisPool jedisPool;
  10. // Redis客户端构造器
  11. public RedisClient(String host, int port) {
  12. initialPool(host, port);
  13. jedis = jedisPool.getResource();
  14. }
  15. // 初始化Redis连接池
  16. private void initialPool(String host, int port) {
  17. JedisPoolConfig config = new JedisPoolConfig();
  18. config.setMaxActive(20);
  19. config.setMaxIdle(5);
  20. config.setMaxWait(1000l);
  21. config.setTestOnBorrow(false);
  22. jedisPool = new JedisPool(config, host, port);
  23. }
  24. // 设置String类型的键值对
  25. public String set(String key, String value) {
  26. return jedis.set(key, value);
  27. }
  28. // 获取String类型的键值对
  29. public String get(String key) {
  30. return jedis.get(key);
  31. }
  32. // 删除String类型的键值对
  33. public long del(String key) {
  34. return jedis.del(key);
  35. }
  36. // 检查String类型的键值对是否存在
  37. public boolean exists(String key) {
  38. return jedis.exists(key);
  39. }
  40. // 清空Redis数据库
  41. public String flushDB() {
  42. return jedis.flushDB();
  43. }
  44. // 释放Redis连接
  45. public void free() {
  46. jedisPool.returnResource(jedis);
  47. }
  48. }

3. 新建监控数据提供者类

新建TestMetricsProvider类,文件路径为:/SpringTest/src/hello/TestMetricsProvider.java。这个类的实例是一个监控数据提供者,Zabbix/J探针会通过这个实例获取测试页面的访问次数。这个类的代码如下所示:

  1. package hello;
  2. import com.quigley.zabbixj.metrics.MetricsException;
  3. import com.quigley.zabbixj.metrics.MetricsKey;
  4. import com.quigley.zabbixj.metrics.MetricsProvider;
  5. public class TestMetricsProvider implements MetricsProvider {
  6. public Object getValue(MetricsKey mKey) throws MetricsException {
  7. if (mKey.getKey().equals("page.count")) {
  8. RedisClient rc = new RedisClient("10.24.16.87", 6379);
  9. long counter = new Long(rc.get("counter"));
  10. rc.free();
  11. return counter;
  12. }
  13. throw new MetricsException("Unknown Key: " + mKey.getKey());
  14. }
  15. }

TestMetricsProvider类继承了Zabbix/J的MetricsProvider接口,当Zabbix服务端定时向探针发送查询请求时,这个类的实例便会查询和返回相应的监控数据。

4. 新建WEB容器启动监听器类

新建StartupListener类,文件路径为:/SpringTest/src/hello/StartupListener.java。这个类的实例会在Web容器启动时初始化应用的上下文配置,此处主要负责配置Zabbix/J探针的端口号和监控数据提供者,然后启动探针线程。这个类的代码如下所示:

  1. package hello;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.ApplicationContextAware;
  6. import com.quigley.zabbixj.agent.ZabbixAgent;
  7. import com.quigley.zabbixj.providers.JVMMetricsProvider;
  8. public class StartupListener implements ApplicationContextAware {
  9. @Autowired
  10. private ZabbixAgent zabbixAgent;
  11. @Override
  12. public void setApplicationContext(ApplicationContext ctx) throws BeansException {
  13. try {
  14. zabbixAgent.setListenPort(20050);
  15. zabbixAgent.addProvider("java", new JVMMetricsProvider());
  16. zabbixAgent.addProvider("test", new TestMetricsProvider());
  17. zabbixAgent.start();
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

注意,必须在Spring容器中注册这个监听器的实例,否则当Web容器启动时便不能对应用上下文进行初始化配置。

5. 改造测试类

现在,还需要对已有的HelloController测试类进行改造,现在这个类的代码如下所示:

  1. package hello;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.ResponseBody;
  5. @Controller
  6. public class HelloController {
  7. @RequestMapping("hello")
  8. public @ResponseBody String test() {
  9. RedisClient rc = new RedisClient("10.24.16.87", 6379);
  10. if (!rc.exists("counter")) {
  11. rc.set("counter", "0");
  12. }
  13. int counter = Integer.valueOf(rc.get("counter")) + 1;
  14. rc.set("counter", String.valueOf(counter));
  15. rc.free();
  16. return String.format("hello, world! This comes from spring, visited %d times!", counter);
  17. }
  18. }

实际上只是将测试类中的页面访问计数器由全局变量改为存放在Redis中,便于Zabbix/J探针定时获取数据。

6. 注册Bean

修改已有的applicationContext.xml配置文件,添加启动监听器和Zabbix/J探针的配置信息。修改后的配置文件如下所示:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4. xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  7. http://www.springframework.org/schema/tx
  8. http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
  9. http://www.springframework.org/schema/aop
  10. http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context-4.0.xsd">
  13. <context:annotation-config />
  14. <bean class="hello.StartupListener" />
  15. <bean id="zabbixAgent" class="com.quigley.zabbixj.agent.ZabbixAgent" />
  16. </beans>

其中,第13行表示使用Spring注解实现注入,第14行是启动监听器的bean注册信息,第15行是Zabbix/J探针的bean注册信息。

7. 测试工程的最终结构

整合后的测试工程的最终结构如下图所示:

测试工程的结构

四、配置Zabbix监控

1. 启动测试工程

在Eclipse的Servers视图中,右键点击测试工程对应的Tomcat服务器,在右键菜单中选择执行选项,如下图所示:

启动测试工程

在浏览器中访问http://localhost:8080/SpringTest/hello页面,若页面如下图所示,则表示测试工程启动成功:

打开测试页面

2. 注册Zabbix/J主机

在浏览器中登录Zabbix服务器,然后打开Configuration → Hosts配置页面,如下图所示:

打开Zabbix主机配置页面

点击上图中的Create host按钮,打开主机注册配置页面,然后填写主机名、IP地址和端口号等信息,详细配置如下图所示:

Zabbix主机配置详情

Zabbix/J主机注册完成之后,稍等几分钟,便能看到主机列表中的Availability栏中的Z图标变为绿色,表示这台主机注册成功,如下图所示:

Zabbix主机状态

3. 注册监控项

在主机列表页面中,点击ZabbixJ-Agent主机的Items超链接,打开监控项列表页面,如下图所示:

监控项列表页面

点击上图中的Create item按钮,新建JVM空闲内存监控项和页面访问计数监控项,这两个监控项的详细配置如下所示:

  • JVM空闲内存监控项
    JVM空闲内存监控项

  • 页面访问计数监控项
    测试页面计数监控项

此时,便能在监控项列表中看到这两个监控项了,如下图所示:

测试监控项列表

五、功能验证

现在,打开Monitoring → Latest data页面,然后在Hosts栏中填写ZabbixJ-Agent,这样便能在这个页面中进行过滤,只监控上述两个监控项的监控数据,如下图所示:

两个监控项的监控数据

至此,Zabbix/J和Spring的整合工作已经全部完成了。