JMX远程监控ActiveMQ设置

本地消息队列:我们在下载好的 activemq 文件夹下的 config 文件夹下,找到 activemq.bat 文件运行,浏览器访问 http://activemq-host:8161/admin。

activemq-host 是启动机器的 ip 地址,8161 是 activemq 的默认端口号,默认用户名和密码是 admin。会进入一下界面:

image

当然,这是本地的消息队列,访问,我们启动之后也可以通过 jdk 自带的 jconsole 来监控。这里重点介绍怎样远程监控 activemq。

远程监控 activemq:这里涉及到 JMX 的概念,网上我也搜了很多,我也看的不是很明白,这里大家知道由 Java 开发的程序,一般都是 jmx 来监控就可以了,当然,activemq 也是通过 Jmx 来监控的。这里首先我们来配置一些东西。

1. 在你下载 activemq 文件夹下的 config 中,找到 activemq.xml,在 broker 节点增加 useJmx="true"
image

2. 在 managementContext 节点更改成下面的截图的样子(这里我直接截图了,增加的东西不多,我就不把能复制的放进来了,自己敲敲,熟悉一下~)
image

3. 在你 activemq 文件夹下的 bin 找到 activemq(${active_home}/bin/activemq),找到下面截图中出出现的代码,应该是注释掉的,解除注释就行了,我下载的版本是 5.13.4,有的没有下面的代码,不知道是什么原因,这个弄明白之后,会再更新。
代码版 (这个可以直接粘贴过去):

1
2
3
4
ACTIVEMQ_SUNJMX_START="-Dcom.sun.management.jmxremote.port=11099"
ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.password.file=${ACTIVEMQ_CONF}/jmx.password"
ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.access.file=${ACTIVEMQ_CONF}/jmx.access"
ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.ssl=false"

截图版:
image

4. 在 Linux 上进入 ${active_home}/bin 中执行 chmod 655 activemq 用来获取 active 的权限,我们解压 activemq 之后,发现在 bin 的 activemq 是灰色,不能正常启动就执行 activemq restart 这条命令。执行完这条命令之后,会变成绿色。
image

然后执行 chmod 400 ${activemq_home}/conf/jmx . 意思是设置当前用户只读,其他用户没有权限。

接下来在 ${activemq_home}/bin 下执行 activemq start 或者 activemq restart ,一般在前面加 sudo,一般用户没权限。
activemq stop 来停止或者用 ps 显示当前运行的 activemq 的线程号,然后 kill 即可。

好了,接下来,我们来用 jdk 自带的 jconsole 来检测一下。
image

默认用户名:admin
密码:activemq

这里有可能出现还远程不上的情况:这里有我尝试了下有两种解决办法

  • 关闭远程服务器上的防火墙 (当然,这个不推荐,容易被黑客攻击)
  • 修改 hosts 文件,添加远程实际的 Ip 地址

image
当然,我们在实际项目中可能不单单登录 activemq 的 web console 或者 jconsole 来实现监控,我在项目中就是用 java 程序来实现跟 web console 一样的页面展示的形式。接下来引用我实际项目中的代码。

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
String surl = Constant.MQ_URL;  
String userName = Constant.MQ_USERNAME;
String userPwd = Constant.MQ_USERPWD;
Map<String, String[]> env = new HashMap<>();
String[] credentials = {userName, userPwd};
env.put(JMXConnector.CREDENTIALS, credentials);
JMXServiceURL url = new JMXServiceURL(surl);
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
// JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName("org.apache.activemq:brokerName=localhost,type=Broker");
//MBeanInfo info = mbsc.getMBeanInfo(mbeanName);
BrokerViewMBean mbean =(BrokerViewMBean) MBeanServerInvocationHandler.newProxyInstance(mbsc, mbeanName, BrokerViewMBean.class, true);
List<MqModel> mqList = new ArrayList<MqModel>();
OrganizationService organizationService = (OrganizationService) SpringBeanUtil.getBean("organizationService");
for (ObjectName na : mbean.getQueues()) {
QueueViewMBean queueBean = (QueueViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbsc, na, QueueViewMBean.class, true);
MqModel mq = new MqModel();
Organization organ = organizationService.getOrganization(queueBean.getName());
if(organ!=null){
mq.setName(organ.getOrgName());
}else{
mq.setName(queueBean.getName());

}
mq.setQueueSize(queueBean.getQueueSize());
mq.setConsumerCount(queueBean.getConsumerCount());
mq.setDequeueCount(queueBean.getDequeueCount());
mq.setEnqueueCount(queueBean.getEnqueueCount());
queueBean.getEnqueueCount();
mqList.add(mq);

}

上面的代码中获取实际数据通过 queueBean.__来获取,这里我用一个 model 来接收了。下面会引入 model 的代码

Constant:

1
2
3
public static final String MQ_URL = properties.getProperty("mq.url");//获取mq远程链接地址   
public static final String MQ_USERNAME = properties.getProperty("mq.userName");//mq用户名
public static final String MQ_USERPWD = properties.getProperty("mq.userPwd");//mq密码

Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/** 
* 这里自定义一个Model来接收队列的信息
* @author LY
* @date 2016-08-10 11:11
*/
public class MqModel {
private String name;//队列的名称
private Long queueSize;//队列中剩余的消息数
private Long consumerCount;//消费者数
private Long enqueueCount;//进入队列的总数量
private Long dequeueCount;//出队列的数量

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Long getQueueSize() {
return queueSize;
}

public void setQueueSize(Long queueSize) {
this.queueSize = queueSize;
}

public Long getConsumerCount() {
return consumerCount;
}

public void setConsumerCount(Long consumerCount) {
this.consumerCount = consumerCount;
}

public Long getDequeueCount() {
return dequeueCount;
}

public void setDequeueCount(Long dequeueCount) {
this.dequeueCount = dequeueCount;
}

public Long getEnqueueCount() {
return enqueueCount;
}

public void setEnqueueCount(Long enqueueCount) {
this.enqueueCount = enqueueCount;
}

}

application.properties:

1
2
3
4
#消息队列服务配置  
my.url = service:jmx:rmi:///jndi/rmi://198.9.4.167:11099/jmxrmi
mq.userName = admin
mq.userPwd = activemq

最后,说下我遇到的问题:
在刚接到这个需求的时候,我搜了很多,把 activemq 的远程配置第一步完成之后,发现用代码在 java 程序中控制台总是报权限的错误,不知道为什么,配置也配置好了,后来在 stackoverflow 看到其他程序猿也遇到这个问题,我看他们怎么实现,修改了下我的代码,就可以了。controller 注释的部分是我以前的代码。

1
2
3
Map<String, String[]> env = new HashMap<>();  
String[] credentials = {userName, userPwd};
env.put(JMXConnector.CREDENTIALS, credentials);

我发现必须把 activemq 远程的用户名和密码放在 map 才可以~~~~