#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構造一個健康檢測程序來進行完整的生產/消費測試。