ActiveMQ和Mosquitto研究和實現 多種環境測試 (有碼慎入)(一)

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參考配置

未完待續...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章