#RabbitMQ 监控(一)java
本RabbitMQ监控博文内容均来自于《RabbitMQ实战高效部署分布式消息队列》一书。书籍上的代码是使用Python实现的,我用Java尝试了一下,该系列代码都在个人github上。ios
监控RabbitMQ并不仅是确保端口5672是开启的并能接收TCP链接而已,对于这样复杂的系统,须要可以模拟AMQP客户端来确保链接以后获取信道、使用REST API来找出全部构成Rabbit的Erlang部件都正常运行,而且它们之间能正确通讯的话才能算是一个完整的健康检测程序。 git
##1.为Nagios编写健康检测 我对监控框架不是很了解,只知道我司使用的是Zabbix,Zabbix也支持多语言、自定义监控脚本等。Nagios健康检测是一个独立的程序,它在运行时监控服务并在程序终止运行时退出代码来指示服务的健康情况。Nagios健康检测能够用任何语言编写,检测程序须要将可读状态打印到STDOUT上,而且返回下列四种整形退出代码之一:
* 0——OK——接收检测的服务工做正常,而且各项指标都处于经过命令行参数设定的阀值以内。github
* 1——WARNING——服务运行处于退化状态(或者说是遇到了问题),可是这个问题并不紧急。spring
* 2——CRITICAL——服务关闭了,无响应,而且/或者超过了受监控的临界度量阀值。mybatis
* 3——UNKNOWN——从技术上来说,这意味着服务的状态或者监控的度量值没法肯定。框架
在理解Nagios指望从健康检测程序中得到的值以后,首先须要编写一个返回Nagios状态代码的健康检测程序。 ###清单1.1 返回Nagios状态代码的健康检测程序分布式
1.状态码枚举 ExitType.java测试
/** * 健康检测程序的几种状态 */ public enum ExitType { WARN("warning"), CRITICAL("critical"), UNKNOWN("unknown"), OK("ok"); private String value; ExitType(String value) { this.value = value; } public String getValue() { return this.value; } }
2.返回Nagios状态码 ExitUtil.javathis
/** * 接收状态码,并以Nagios状态码退出 */ public class ExitUtil { private final static Logger log = LoggerFactory.getLogger(ExitUtil.class); public static void exit(String type) { if (type.equalsIgnoreCase("warning")) { log.info("Status is WARN"); System.exit(1); } else if (type.equalsIgnoreCase("critical")) { log.info("Status is CRITICAL"); System.exit(2); } else if (type.equalsIgnoreCase("unknown")) { log.info("Status is UNKNOWN"); System.exit(3); } else if (type.equalsIgnoreCase("ok")) { log.info("Status is OK"); System.exit(0); } else { log.error("Unknown exit type"); System.exit(-1); } } }
##2.使用AMQP模拟检测来确认RabbitMQ是否运行 不用编写代码,大多数监控系统附带的TCP健康检测程序都能经过TCP链接测试RabbitMQ是否能在端口上响应。虽然这会告诉你RabbitMQ守护进程是否在运行,但却不能知道它是否正常运做。为了可以真正的判断RabbitMQ是否有能力来服务请求,你须要真实地发送AMQP命令,在这里构造一个AMQP ping健康检测,当下列任何条件之一为真时,该检测程序会返回一个critical状态。仅当这些状态检测都为false时,健康检测程序才会返回OK状态。
* RabbitMQ没有响应TCP链接
* 当发送AMQP命令时,在接收到响应以前超时了。
* 当构造AMQP信道时,遇到了协议错误
###清单2.1 模拟AMQP检测RabbitMQ是否运行
1.RabbitMQ配置文件 rabbitmq-cfg.properties
host=127.0.0.1 port=5672 username=guest password=guest rmq_url=http://127.0.0.1:15672
2.读取配置文件 RMQConfig.java
public class RMQConfig { private final String host; private final int port; private final String username; private final String password; //RabbitMQ REST API URL private final String rmqUrl; private RMQConfig() throws IOException { Properties properties = new Properties(); //读取resources下的properties文件 properties.load(getClass().getClassLoader().getResourceAsStream("rabbitmq-cfg.properties")); host = properties.getProperty("host"); port = Integer.valueOf(properties.getProperty("port")); username = properties.getProperty("username"); password = properties.getProperty("password"); rmqUrl = properties.getProperty("rmq_url"); } public String getHost() { return host; } public int getPort() { return port; } public String getUsername() { return username; } public String getPassword() { return password; } public String getRmqUrl() { return rmqUrl; } public enum Singleton { INSTANCE; private RMQConfig rmqConfig; Singleton() { try { rmqConfig = new RMQConfig(); } catch (IOException e) { e.printStackTrace(); } } public RMQConfig getRmqConfig() { return rmqConfig; } } }
3.建立RabbitMQ链接 ConnectionUtil.java
/** * 获取RabbitMQ链接 */ public class ConnectionUtil { public static Connection getConnection() throws IOException, TimeoutException { RMQConfig config = RMQConfig.Singleton.INSTANCE.getRmqConfig(); String host = config.getHost(); int port = config.getPort(); String username = config.getUsername(); String password = config.getPassword(); ConnectionFactory factory = new ConnectionFactory(); factory.setHost(host); factory.setPort(port); factory.setUsername(username); factory.setPassword(password); return factory.newConnection(); } public static Connection getConnection(String host, int port, String username, String password) throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost(host); factory.setPort(port); factory.setUsername(username); factory.setPassword(password); return factory.newConnection(); } }
4.检测RabbitMQ状态 AMQPPingCheck.java
/** * 检测可否建立RabbitMQ链接 */ public class AMQPPingCheck { private final static Logger log = LoggerFactory.getLogger(AMQPPingCheck.class); public static void checkAMQPPing() { RMQConfig config = RMQConfig.Singleton.INSTANCE.getRmqConfig(); String host = config.getHost(); int port = config.getPort(); String username = config.getUsername(); String password = config.getPassword(); Connection connection = null; try { connection = ConnectionUtil.getConnection(host, port, username, password); } catch (IOException | TimeoutException e) { log.error("Critical : Could not connect to {}, cause {}", host, e.getMessage()); ExitUtil.exit(ExitType.CRITICAL.getValue()); } log.info("OK: Connect to {} successful.", host); ExitUtil.exit(ExitType.OK.getValue()); } }
5.运行检测程序
[@Test](https://my.oschina.net/azibug) public void pingCheck() { AMQPPingCheck.checkAMQPPing(); }
能够看到健康检测程序正常工做:
16:12:57.912 [main] INFO com.lanxiang.rabbitmqmonitor.check.AMQPPingCheck - OK: Connect to 127.0.0.1 successful.
16:12:57.914 [main] INFO com.lanxiang.rabbitmqmonitor.terminate.ExitUtil - Status is OK
##下一章将介绍使用REST API构造一个健康检测程序来进行完整的生产/消费测试。