因为公司的产品架构有用到ActiveMQ消息队列,在之前的压力测试上有发现ActiveMQ存在消费不过来的情况,这里记录下在Linux系统下如何实现通过Java对ActiveMQ消息队列的监控。
Java是通过配置JMX来监控ActiveMQ的消息队列的,这里用到消息队列工具类,放下实现类:
import java.io.IOException;
import java.util.PriorityQueue;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.broker.jmx.QueueViewMBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import cn.itcast.ssm.po.MQQue;
public class ActiveMqKit {
public static final String reportQueueName ="zc-queue-actual";//生成核对报告队列名
private static Log log = LogFactory.getLog(ActiveMqKit.class);
private static final String connectorPort = "11099";
private static final String connectorPath = "/jmxrmi";
private static final String jmxDomain = "org.apache.activemq";
public static PriorityQueue getAllQueue(String ip)throws Exception {
BrokerViewMBean mBean=null;
MBeanServerConnection connection=null;
PriorityQueue ques=new PriorityQueue();
try{
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+ip+":" + connectorPort + connectorPath);
JMXConnector connector = JMXConnectorFactory.connect(url);
connector.connect();
connection = connector.getMBeanServerConnection();
ObjectName name = new ObjectName(jmxDomain + ":brokerName=localhost,type=Broker");
mBean = MBeanServerInvocationHandler.newProxyInstance(connection, name, BrokerViewMBean.class, true);
}catch (IOException e){
log.error("ActiveMQUtil.getAllQueueSize",e);
}catch (MalformedObjectNameException e){
log.error("ActiveMQUtil.getAllQueueSize",e);
}
if(mBean!=null){
for (ObjectName queueName : mBean.getQueues()) {
QueueViewMBean queueMBean = MBeanServerInvocationHandler.newProxyInstance(connection, queueName, QueueViewMBean.class, true);
MQQue que=new MQQue();
que.setName(queueMBean.getName());
que.setQueueSize(queueMBean.getQueueSize());
que.setConsumerCount(queueMBean.getConsumerCount());
que.setDequeueCount(queueMBean.getDequeueCount());
if(ques.size()<=2) {
ques.add(que);
}else {
if(que.getQueueSize()>ques.peek().getQueueSize()) {
ques.poll();
ques.add(que);
}
}
//System.out.println("Queue Name --- " + queueMBean.getName());// 消息队列名称
// System.out.println("Queue Size --- " + queueMBean.getQueueSize());// 队列中剩余的消息数
//System.out.println("Number of Consumers --- " + queueMBean.getConsumerCount());// 消费者数
// System.out.println("Number of Dequeue ---" + queueMBean.getDequeueCount());// 出队数
}
}
return ques;
}
}
这里有几点说下:
1.mq默认的后台端口号是61616,很多博客上也有写连接端口号是1093的,其实不对,应该是11099,当然可能1093是用于监控Windows系统下的mq的,一开始我照搬一些博客端口号是用1093,结果运行一直报拒绝连接的错误,不明所以,直到用了11099才豁然开朗。
2.mq的消费队列可能有很多,在做性能测试的时候可能重点关注的是发现消费不过来的队列(就是队列中剩余消费数特别多的队列),我在获取到每个队列的信息后用一个MQQue 类进行包装,设置一个大小为2的最小堆,以队列中剩余的消息数为比较找出剩余消费数最多的TOP2队列(消费不过来的队列)。
MQQue类实现如下:
public class MQQue implements Comparable {
private String name;// 消息队列名称
private long queueSize;// 队列中剩余的消息数
private long consumerCount;// 消费者数
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;
}
@Override
public int compareTo(MQQue o1) {
// TODO Auto-generated method stub
long res=this.getQueueSize()-o1.getQueueSize();
if(res>0) return 1;
else if(res<0) return -1;
else return 0;
}
}
这样代码就算写完了,但是你以为这样就完事了那真是too young too simple,这样运行程序还是会报错的,在Linux系统下还需要对ActiveMQ修改相应的配置才能开启jmx监控。
1.首先修改/etc目录下的hosts文件:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
将 127.0.0.1修改为 ActiveMQ 所在服务器的ip:
1.32.160.240 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
2.在activemq文件夹下的conf目录中,找到activemq.xml,在broker节点增加useJmx="true"属性:
3.继续修改activemq.xml的managementContext 节点:
这里的connectorPort="11099"要加上,否则会出现java.lang.RuntimeException: java.rmi.ConnectException: Connection refused to host: 127.0.0.1的错误。
4.在mq的bin 目录的 activemq 文件最后一行加上如下配置:
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"
5.修改conf目录下jmx.password和jmx.access 文件的权限:
chmod 400 …/conf/jmx.*
这两个文件权限必须是当前用户只读(也就是400)否则会使得activemq无法启动,而且没有任何地方报错。
6.重启mq:
systemctl stop mq;
systemctl start mq;
当环境配置好后再运行前面写的代码,就可以获取到mq的消费者数、剩余消费数、已消费数、队列名称等信息了,实现对ActiveMQ的监控。