ActiveMQ和Mosquitto研究和实现 多种环境测试 (有码慎入)(一)

本文探讨了ActiveMQ和Mosquitto在消息持久化方面的实现,包括ActiveMQ的KahaDB和JDBC存储以及Mosquitto的配置。通过分析两者存储结构和配置,展示了它们在性能和使用场景上的差异。
摘要由CSDN通过智能技术生成
Mosquitto和ActiveMQ配置安装网上一搜一大堆所以这里就不重复了。

首先来看看ActiveMQ和Mosquitto实现 这里用的paho实现的 pub和sub模型

pub端


package mqtt.mosquitto;


import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;

import mqtt.mosquitto.base.MqttBase;
/**
* 生产者
*
* */
public class MqttPublisher extends MqttBase{


/**
* 构建生产者链接
* */
MqttPublisher(){
try {
//本地化信息
// MqttClientPersistence dsSubscriberA = new MqttDefaultFilePersistence("F:\\mqttFile\\subscriberA");
//创建mqtt链接
sampleClient = new MqttClient(BROKER, "Publisher");
} catch (MqttException e) {
e.printStackTrace();
}
}

/**
* 发送消息任务
* @param topic 订阅主题名称
* @param str 消息内容
* */
public void sendMessage(String topic,String str) throws MqttSecurityException, MqttException{
//mqtt配置
MqttConnectOptions connOpts = new MqttConnectOptions();
//设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
connOpts.setCleanSession(false);
//mqtt回调对象
PubMqttCallback callback = new PubMqttCallback();
//设置客户端回调方式
sampleClient.setCallback(callback);
// String haURIs[] = new String[]{"tcp://192.168.56.3:61666","tcp://192.168.56.4:61666"};
// //集群高可用配置
// connOpts.setServerURIs(haURIs);
//链接boker
sampleClient.connect(connOpts);
//拼接格式ID=消息体
StringBuffer sb = new StringBuffer();
// sb.append(id);
// sb.append("=");
sb.append(str+" ");
System.out.println(sb);
MqttMessage message = new MqttMessage(sb.toString().getBytes());

//设置消息类型
message.setQos(QOS);
//将一条消息发布到服务器上的一个主题中
sampleClient.publish("Queues",message);
// System.out.println(message.getId()+" "+sb);
//从服务器断开连接0
sampleClient.disconnect();
}

public static void main(String[] args) throws MqttSecurityException, MqttException {
final MqttPublisher pub = new MqttPublisher();

for (int i = 0; i <50; i++) {
pub.sendMessage("mark",i+"");
}


}

}




package mqtt.mosquitto;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;


/**
* 生产者回掉接口
* */
public class PubMqttCallback implements MqttCallback{
static int i = 0;

public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub

}

public void deliveryComplete(IMqttDeliveryToken arg0) {
i++;
if(arg0.isComplete()){//判断消息是否发送成功

}
}

public void messageArrived(String arg0, MqttMessage arg1) throws Exception {
// TODO Auto-generated method stub

}

}




sub端


package mqtt.mosquitto;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;

import mqtt.mosquitto.base.MqttBase;
/**
* 消费者
*
* */
public class MqttSubscribe extends MqttBase{
//客户端Id
String clientId ="";
/**
* 构建消费者链接
* */
public MqttSubscribe(){
try {
//判断客户端链接是否已经建立
if(sampleClient == null){
//生成客户端唯一ID
// UUID uuid = UUID.randomUUID();
String clientId = "sub1";
//持久化
// MqttClientPersistence dsSubscriberA = new MqttDefaultFilePersistence("F:\\mqttFile\\sub1");
// 链接MQTT服务
sampleClient = new MqttClient(BROKER, clientId);
//链接MQTT服务
// sampleClient = new MqttClient(BROKER, clientId);
}
} catch (MqttException e) {
e.printStackTrace();
}
}


/**
* 接受消息方法
* */
public void receive() throws MqttException{
//配置项设置
MqttConnectOptions connOpts = new MqttConnectOptions();
//设置会话
connOpts.setCleanSession(false);
//mqtt回调对象
SubMqttCallback callback = new SubMqttCallback();
//设置客户端回调方式
sampleClient.setCallback(callback);
//传递客户端连接
callback.setSampleClient(sampleClient);
//传递客户端Id
callback.setClientId("Publisher");
//链接客户端
sampleClient.connect(connOpts);
//订阅主题416
sampleClient.subscribe("Queues", 2);
//退订
// sampleClient.unsubscribe("Queues");
}

public static void main(String[] args) throws MqttException {
new MqttSubscribe().receive();

}

}




package mqtt.mosquitto;


import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
* 消费者回调接口
* */
public class SubMqttCallback implements MqttCallback{

Logger logger = Logger.getLogger(SubMqttCallback.class);

private static List<String> list= new ArrayList<String>();
//客户端ID
private String clientId;
//客户端连接
private MqttClient sampleClient;

static int count = 0;

public SubMqttCallback(){

}


/**
* 执行任务出错或者断开连接会执行到的方法
* */
public void connectionLost(Throwable cause) {
System.out.println("自行恢复链接");
//自行恢复链接
new Thread(){
public void run() {
boolean flg = true;
while(flg){
try {
Thread.sleep(1000);
MqttSubscribe client =new MqttSubscribe();
//断开重连
client.setSampleClient(sampleClient);
client.receive();
//链接恢复退出重连
flg = false;
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接断开尝试重连");
}
}
}
}.start();
}

/**
* 接收回调方法
* */
public void messageArrived(String topic, MqttMessage message) throws Exception {
String messageStr = new String(message.getPayload());
try{
/**
* 执行任务块
* */
//测试异常
// count++;
// if(count >5){
// count = count/0;
// }
list.add(messageStr);

System.out.println(" 接收消息为:"+messageStr);
// System.out.println(" 条数为:"+list.size());
}catch(Exception e){
StringBuffer sb = new StringBuffer();
sb.append(" pubId :");
sb.append(clientId);
sb.append(" ,任务内容:");
sb.append(messageStr);
sb.append(" ,订阅主题:");
sb.append(topic);
sb.append(" ,异常信息:");
sb.append(e.getMessage());
sb.append(topic);
//将执行错误的任务保存起来
logger.error(sb);
}

}

public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("deliveryComplete---------"+token.isComplete());
}



public MqttClient getSampleClient() {
return sampleClient;
}

public void setSampleClient(MqttClient sampleClient) {
this.sampleClient = sampleClient;
}


public static void main(String[] args) {
Logger logger = Logger.getLogger(SubMqttCallback.class);

logger.error("测试!");
}


public String getClientId() {
return clientId;
}

public void setClientId(String clientId) {
this.clientId = clientId;
}




}




这里就是实现


关于消息持久化mosquitto

# 消息自动保存的间隔时间
#autosave_interval 1800

# 消息自动保存功能的开关
#autosave_on_changes false

# 持久化功能的开关
persistence true

# 持久化DB文件
#persistence_file mosquitto.db

# 持久化DB文件目录
#persistence_location /var/lib/mosquitto/

ActiveMQ持久化分为4中 AMQ KahaDB JDBC Memory

AMQ 配置



<broker brokerName="broker" persistent="true" useShutdownHook ="false"> <persistenceAdapter>
<amqPersistenceAdapter directory="${activemq.base}/da ta" maxFileLength="32mb"/> </persistenceAdapter>


AMQ Message 内部存储结构


[img]http://dl2.iteye.com/upload/attachment/0121/8100/112f54bf-f47c-3a56-9fcd-aae6447c1deb.png[/img]

它是 ActiveMQ 默认的消息存储,是在消息存储实现中 最快的消息存储了。
它势必会产生快速事务持久、高优化消息索引 id 和内存消息缓存。

KahaDB Message Store 持久

KahaDB 是一种新的消息消息存储,而且解决了 AMQ 的一些不足,提高了性
能。AMQ 消息存储用两个分离的文件对于每一个索引和如果 broker 没有彻底关闭
则恢复很麻烦,所有的索引文件需要重新构建,broker 需要遍历所有的消息日志文
件。
为了克服以上限制,KahaDB 消息存储对于它的索引用一个事务日志和仅仅用
一个索引文件来存储它所有的地址。不同于 AMQ。而且在生成环境测试链接数到
10000,而且每一个链接对应一个队列。
Kaha Persistence 是一个专门针对消息持久化的解决方案。它对典型的消息使
用模式进行了优化。在 Kaha 中,数据被追加到 data logs 中。当不再需要 log 文件
中的数据的时候,log 文件会被丢弃。以下是其配置的一个例子:


<broker brokerName="broker" persistent="true" useShutdownHook ="false"> <persistenceAdapter>
<kahaPersistenceAdapter directory="activemq-dat a" maxDataFileLength="33554432"/>

</persistenceAdapter>
</broker>




[img]http://dl2.iteye.com/upload/attachment/0121/8102/04aa4653-4fd2-3a19-b2fe-c877e20cfe85.png[/img]

KahaDB 的存储结构和 AMQ 的存储结构类似。
也包括 Cache、Reference Indexes、message Journal,所有的索引文件更新的记
录存在 Redo Log 中,这样就不用更新没有变化的索引数据了,仅仅更新变化的数
据。额外的,KahaDB 消息存储用了一个 B-Tree 布局恰恰和 AMQ 消息存储相反,
KahaBD 消息存储保持所有的索引在一个持久的 hash 表中,然而 hash 索引在时刻
的变化,KahaBD 在这方面已经有了很好的新能特征。

KahaDB 配置方式如下:


<broker brokerName="broker" persistent="true" useShutdownHook="false"> <persistenceAdapter>
<kahaDB directory="activemq-data" journalMaxFileLength="32mb"/> </persistenceAdapter>
<transportConnectors>
<transportConnector uri="tcp://localhost:61616"/> </transportConnectors>

</broker>

KahaDB 属性


[img]http://dl2.iteye.com/upload/attachment/0121/8104/42bde5a3-e937-3139-914c-25e8fe037ac2.png[/img]


[img]http://dl2.iteye.com/upload/attachment/0121/8106/716f85b0-a436-39e3-a8d3-b751a717e95b.png[/img]

JDBC Message Store 持久

消息存储基于 JDBC。
ActiveMQ插件式的消息存储具有的不同的消息存储实现而且具有很强的易用
性。最常见的和最原始的消息存储 JDBC 存储也被 AactiveMQ 支持。
当我们使用 JDBC 消息存储默认的驱动使用 Apache Derby 数据库。同时也支
持其它关系数据库:MySQL、Oracle、SQLServer、Sybase、Informix、MaxDB。
很多用户用一个关系数据库对于消息持久来说可以简单的查询去验证消息等
功能。讨论以下一个话题:
在 ActiveMQ 中使用 Apache Derby。
Apache Derby 是一个 ActiveMQ 默认的数据库用于 JDBC 存储。只是因为它是
一个很棒的数据库。不仅仅是它由 100%java 写的,而且它被设计成一个嵌入式的
数据库。Derby 提供了一个很全的功能特征,性能很好和提供了一个很小容量,然
Alisd Apache ActiveMQ 笔记
- 48 -
而,它对于 ActiveMQ 用户来书仅仅这能一个人可以使用,用 Derby 的感受,它在
虚拟内存中提供了一个垃圾回收机制,它将代替在数据库中删除存储的消息,
Derby 在它的 jvm 实例中允许 ActiveMQ 执行更加优化。
JDBC 消息存储提供了三张表,其中两种表是用于存储消息和第三张表是用于
类似与排他锁似的,这样确保 ActiveMQ 仅仅由一个用户进入数据库。
消息表默认的名称 ACTIVEMQ_MSGS.


[img]http://dl2.iteye.com/upload/attachment/0121/8108/d102960e-e2b2-3a4f-be21-02da516e3aa6.png[/img]

消息(队列和主题)存进 ACTIVEMQ_MSGS 表中。
ACTIVEMQ_ACKS 表存储持久订阅的信息和最后一个持久订阅接收的消息
ID。


[img]http://dl2.iteye.com/upload/attachment/0121/8110/4cf2bb8f-5ff0-3374-9381-8011348fc27d.png[/img]

[img]http://dl2.iteye.com/upload/attachment/0121/8112/973a9810-a730-31ab-86a8-795aedda87df.png[/img]

配置方式

[img]http://dl2.iteye.com/upload/attachment/0121/8114/142b5826-e43f-3ce1-8fbf-4ff3e00e366e.png[/img]


[img]http://dl2.iteye.com/upload/attachment/0121/8116/543e87cc-c87b-3cdd-9604-5bf1e7f65443.png[/img]


附上 ActiveMQ参考配置

未完待续...
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值