Architecture design of high-availability multi-protocol IoT message based on activeMQ broker cluster


activeMQ is a very powerful message middleware.
Supports multiple protocols including MQTT NIO, and is a perfect implementation of jms. When there are millions of end devices that need to connect to the server, proper processing and architecture can provide powerful service capabilities to the outside world.

First of all, you need to solve the performance problem of activeMQ single-node service, and you must not directly use the default configuration for production.
You can Baidu or refer to the log
http://m.blog.csdn.net/truong/article/details/73718621
http://blog.csdn.net/yinwenjie/article/details/50955502
http://blog.csdn. net/yinwenjie/article/details/50991443
http://blog.csdn.net/yinwenjie/article/details/51064242 If

a single node is completed, please refer to the blog post
http://www.cnblogs.com/leihenqianshang/articles/ After the construction of 5623858.html is

completed, the high-performance service architecture has come out. At this time, you need to write some test code.

1 Write first for the case where both the client and the consumer are based on the activeMQ API. The producer code is as follows:





package com.sunshine.mq;
import javax.jms.Connection;  
import javax.jms.DeliveryMode;  
import javax.jms.JMSException;  
import javax.jms.MessageProducer;  
import javax.jms.Session;  
import javax.jms.TextMessage;  
import javax.jms.Topic;  
  
import org.apache.activemq.ActiveMQConnectionFactory;  
  
public class Producer {  
  
    public static void main(String[] args) throws JMSException {  
        // Connect to ActiveMQ server  
        //ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.15:61616)");
        //Here you can use the failover mechanism for multi-node configuration to achieve high availability and backend load balancing  
    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.15:1883)");
        Connection connection = factory.createConnection();  
        connection.start();  
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // create theme  
        Topic topic = session.createTopic("VirtualTopic.virtual-T.100990");  
        MessageProducer producer = session.createProducer(topic);  
        // NON_PERSISTENT non-persistent PERSISTENT persistent, use persistent mode when sending messages  
        //producer.setDeliveryMode(DeliveryMode.PERSISTENT);  
        TextMessage message = session.createTextMessage();
        for(int i = 0;i<10;i++){
        	 message.setText("topic 消息。"+i);  
             message.setStringProperty("property", "消息Property");  
             // publish topic message  
             producer.send(message);  
             System.out.println("Sent message: " + message.getText());
        }
        
        session.close();  
        connection.close();  
    }  
}



We need multiple consumers to consume messages for distributed deployment purposes
Consumer 1


package com.sunshine.mq;
import javax.jms.Connection;  
import javax.jms.JMSException;  
import javax.jms.Message;  
import javax.jms.MessageConsumer;  
import javax.jms.MessageListener;  
import javax.jms.Queue;  
import javax.jms.Session;  
import javax.jms.TextMessage;  
  


import org.apache.activemq.ActiveMQConnectionFactory;  
  
public class ConsumerA {  
  
    public static void main(String[] args) throws JMSException, InterruptedException {  
        // Connect to ActiveMQ server  
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.15:1887)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:61616,tcp://172.16.7.18:61616)");
    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1883,tcp://172.16.7.18:1883)");
        Connection connection = factory.createConnection();  
        connection.start();  
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // create theme   
        Queue topicA = session.createQueue("Consumer.GG.VirtualTopic.virtual-T.*");  
        // Consumer Group A creates a subscription  
        MessageConsumer consumerA1 = session.createConsumer(topicA);
        Integer count = 0;
        while(true){
        	Message message = consumerA1.receive();
        	count++;
        	TextMessage msg = (TextMessage)message;
			final String messageText = msg.getText();
        	System.out.println(messageText +", the total number of consumed messages is: "+count);
        }
        /**consumerA1.setMessageListener(new MessageListener() {  
            // Subscription receive method  
            public void onMessage(Message message) {  
                TextMessage tm = (TextMessage) message;  
                try {  
                    System.out.println("A 收到消息: " + tm.getText()+":"+tm.getStringProperty("property"));  
                } catch (JMSException e) {  
                    e.printStackTrace ();  
                }  
            }  
        });**/  
          
        //session.close();  
        //connection.close();  
    }  
}  


Consumer 2

package com.sunshine.mq;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;
  
public class ConsumerB {  
  
    public static void main(String[] args) throws JMSException, InterruptedException {  
        // Connect to ActiveMQ server  
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(nio://172.16.7.17:1888,nio://172.16.7.18:1889)");
//    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:61616,tcp://172.16.7.18:61616)");
        Connection connection = factory.createConnection();  
        connection.start();
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // create theme   
        Queue topicA = session.createQueue("Consumer.GG.VirtualTopic.virtual-T.*");  
        // Consumer Group A creates a subscription  
        MessageConsumer consumerA1 = session.createConsumer(topicA);
        Integer count = 0;
        while(true){
        	Message message = consumerA1.receive();
        	count++;
        	TextMessage msg = (TextMessage)message;
			final String messageText = msg.getText();
        	System.out.println(messageText +", the total number of consumed messages is: "+count);
        	
        }
        /**consumerA1.setMessageListener(new MessageListener() {  
            // Subscription receive method  
            public void onMessage(Message message) {  
                TextMessage tm = (TextMessage) message;  
                try {  
                    System.out.println("B 收到消息: " + tm.getText()+":"+tm.getStringProperty("property"));  
                } catch (JMSException e) {  
                    e.printStackTrace ();  
                }  
            }  
        });**/  
        //session.close();  
        //connection.close();  
    }  
}  


Consumer 3

package com.sunshine.mq;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;
  
public class ConsumerC {  
  
    public static void main(String[] args) throws JMSException, InterruptedException {  
        // Connect to ActiveMQ server  
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(nio://172.16.7.17:1888,nio://172.16.7.18:1889)");
//    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:61616,tcp://172.16.7.18:61616)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(mqtt://172.16.7.17:1883,mqtt://172.16.7.18:1883)");
        Connection connection = factory.createConnection();  
        connection.start();
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // create theme   
        Queue topicA = session.createQueue("Consumer.GG.VirtualTopic.virtual-T.*");  
        // Consumer Group A creates a subscription  
        MessageConsumer consumerA1 = session.createConsumer(topicA);
        Integer count = 0;
        while(true){
        	Message message = consumerA1.receive();
        	count++;
        	TextMessage msg = (TextMessage)message;
			final String messageText = msg.getText();
        	System.out.println(messageText +", the total number of consumed messages is: "+count);
        	
        }
        /**consumerA1.setMessageListener(new MessageListener() {  
            // Subscription receive method  
            public void onMessage(Message message) {  
                TextMessage tm = (TextMessage) message;  
                try {  
                    System.out.println("B 收到消息: " + tm.getText()+":"+tm.getStringProperty("property"));  
                } catch (JMSException e) {  
                    e.printStackTrace ();  
                }  
            }  
        });**/  
        //session.close();  
        //connection.close();  
    }  
}  



The result of the test is that the messages generated by the producer are loaded to different consumer clients, and each consumer client consumes different messages. Here, no matter whether the message produced by the producer goes to the queue or goes to the topic, the result is to realize the routing of the message.

Suppose there is a situation where the device only supports the MQTT protocol, uses MQTTClient to send messages, or just wants to use MQTT, then how to deal with this architecture? The reason is the same, because of the urgency of linux-c or C++ client developers, the producer simulates the program


package com.sunshine.mqtt;

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.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;


public class MyMqttClient {
	private String host="tcp://172.16.7.15:1887";
	private String userName="admin";
	private String passWord = "activemq.123";
	private MqttConnectOptions options;
	private MqttClient client;
	private MqttMessage message ;
	private String[] myTopics={"test_result/20179112982783"};
	private int[] myQos={2};
	private MqttTopic topic;
	private String myTopic = "test/20179112982783";
	public MyMqttClient(){
		try {
			client=new MqttClient(host,"test99990000",new MemoryPersistence());
			options = new MqttConnectOptions();
			options.setCleanSession(false);
			options.setUserName(userName);
			options.setPassword(passWord.toCharArray());
			options.setConnectionTimeout(10);
			options.setKeepAliveInterval(20);
			client.setCallback(new MqttCallback(){

				@Override
				public void connectionLost(Throwable cause) {
					
				}

				@Override
				public void messageArrived(String topicName, MqttMessage message)
						throws Exception {
					System.out.println("topicName is :"+topicName);
					System.out.println("Message is:"+message.toString());
				}

				@Override
				public void deliveryComplete(IMqttDeliveryToken token) {
					
				}});
			
			client.connect(options);
			client.subscribe(myTopics,myQos);
			
		} catch (Exception e) {
			e.printStackTrace ();
		}
	}
	
	public void sendMessage(String topicT,String messageTest){
		try {
			message = new MqttMessage();
			message.setQos(0);
			message.setRetained(true);
			message.setPayload(messageTest.getBytes());
			topic = client.getTopic(topicT);
			MqttDeliveryToken token = topic.publish(message);
			token.waitForCompletion();
			System.out.println("Send message:"+messageTest);
		} catch (Exception e) {
			e.printStackTrace ();
		}
	}
}



package com.sunshine.mqtt;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.junit.Test;


public class MyMqttTest {
	
	@Test
	public void testMQTT(){
		MyMqtt mqtt = new MyMqtt();
		mqtt.sendMessage("I sent a message to the client");
	}
	
	@Test
	public void testMQTTClient(){
		MyMqttClient client=new MyMqttClient();
		//client.sendMessage("I sent a message to the server, my SN is 20179112982783");
	}
	
	@Test
	public void testIotConnect() throws InterruptedException{
		MyMqttClient client=new MyMqttClient();
		for(int i=0;i<10;i++){
			client.sendMessage("VirtualTopic/100990"+i,"mqtt-msg:"+i+">"+("100990"+i));
		}
	}
}




three consumers

package com.sunshine.mq;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.TopicConnectionFactory;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQBytesMessage;
  
public class ConsumerTopicA {  
  
    public static void main(String[] args) throws JMSException, InterruptedException {  
        // 连接到ActiveMQ服务器  
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.15:1887)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:61616,tcp://172.16.7.18:61616)");
    	//ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1883,tcp://172.16.7.18:1883)");
    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin", "failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
        Connection connection = factory.createConnection();
        connection.start();  
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // 创建主题   
        Queue topicA = session.createQueue("Consumer.GG.VirtualTopic.*");  
        // 消费者A组创建订阅  
        MessageConsumer consumerA1 = session.createConsumer(topicA);
        Integer count = 0;
        while(true){
        	//在实际生产过程中不建议使用receive 会造成阻塞并损耗大量资源 建议直接使用spring jms 监听器
        	ActiveMQBytesMessage message = (ActiveMQBytesMessage) consumerA1.receive();
        	count++;
//        	TextMessage msg = (TextMessage)message;
//			String messageText = msg.getText();
        	System.out.println(new String(message.getMessage().getContent().getData()) +",消费消息总数为:"+count);
        }
        /**consumerA1.setMessageListener(new MessageListener() {  
            // 订阅接收方法  
            public void onMessage(Message message) {  
                TextMessage tm = (TextMessage) message;  
                try {  
                    System.out.println("A 收到消息: " + tm.getText()+":"+tm.getStringProperty("property"));  
                } catch (JMSException e) {  
                    e.printStackTrace();  
                }  
            }  
        });**/  
          
        //session.close();  
        //connection.close();  
    }  
}  





package com.sunshine.mq;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.TopicConnectionFactory;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQBytesMessage;
  
public class ConsumerTopicB {  
  
    public static void main(String[] args) throws JMSException, InterruptedException {  
        // 连接到ActiveMQ服务器  
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.15:1887)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:61616,tcp://172.16.7.18:61616)");
    	//ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1883,tcp://172.16.7.18:1883)");
    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin", "failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
        Connection connection = factory.createConnection();
        connection.start();  
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // 创建主题   
        Queue topicA = session.createQueue("Consumer.GG.VirtualTopic.*");  
        // 消费者A组创建订阅  
        MessageConsumer consumerA1 = session.createConsumer(topicA);
        Integer count = 0;
        while(true){
        	ActiveMQBytesMessage message = (ActiveMQBytesMessage) consumerA1.receive();
        	count++;
//        	TextMessage msg = (TextMessage)message;
//			String messageText = msg.getText();
        	System.out.println(new String(message.getMessage().getContent().getData()) +",消费消息总数为:"+count);
        }
        /**consumerA1.setMessageListener(new MessageListener() {  
            // 订阅接收方法  
            public void onMessage(Message message) {  
                TextMessage tm = (TextMessage) message;  
                try {  
                    System.out.println("A 收到消息: " + tm.getText()+":"+tm.getStringProperty("property"));  
                } catch (JMSException e) {  
                    e.printStackTrace();  
                }  
            }  
        });**/  
          
        //session.close();  
        //connection.close();  
    }  
}  


package com.sunshine.mq;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.TopicConnectionFactory;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQBytesMessage;
  
public class ConsumerTopicC {  
  
    public static void main(String[] args) throws JMSException, InterruptedException {  
        // 连接到ActiveMQ服务器  
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.15:1887)");
//        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:61616,tcp://172.16.7.18:61616)");
    	//ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin","failover:(tcp://172.16.7.17:1883,tcp://172.16.7.18:1883)");
    	ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin", "failover:(tcp://172.16.7.17:1888,tcp://172.16.7.18:1889)");
        Connection connection = factory.createConnection();
        connection.start();  
        Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  
        // 创建主题   
        Queue topicA = session.createQueue("Consumer.GG.VirtualTopic.*");  
        // 消费者A组创建订阅  
        MessageConsumer consumerA1 = session.createConsumer(topicA);
        Integer count = 0;
        while(true){
        	ActiveMQBytesMessage message = (ActiveMQBytesMessage) consumerA1.receive();
        	count++;
//        	TextMessage msg = (TextMessage)message;
//			String messageText = msg.getText();
        	System.out.println(new String(message.getMessage().getContent().getData()) +",消费消息总数为:"+count);
        }
        /**consumerA1.setMessageListener(new MessageListener() {  
            // 订阅接收方法  
            public void onMessage(Message message) {  
                TextMessage tm = (TextMessage) message;  
                try {  
                    System.out.println("A 收到消息: " + tm.getText()+":"+tm.getStringProperty("property"));  
                } catch (JMSException e) {  
                    e.printStackTrace();  
                }  
            }  
        });**/  
          
        //session.close();  
        //connection.close();  
    }  
}  




此时客户端只支持单个broker地址,可以通过一些策略分配给客户端相对比较空闲的broker

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326174821&siteId=291194637