php rabbitmq mqtt,使用RabbitMQ和Spring Cloud进行MQTT客户端负载平衡

扩展您对MQTT客户端和负载平衡的了解。

介绍

MQTT是一种机器对机器(M2M),物联网连接协议。它被设计为一个非常轻量级的发布和订阅消息传输。对于需要较小代码占用空间和/或网络带宽非常宝贵的远程位置的连接非常有用。

每个MQTT客户端都订阅某些主题,并在发布者开始推送有关这些主题的消息时接收消息。

如何扩展?

水平扩展的目的是在同一应用程序的多个实例之间分配负载。如果这些实例中的MQTT客户端订阅了相同的主题,则将向每个实例传递相同的MQTT消息,这不是所理想的行为。

38cd4a268a9179ba029bbebca4b768c2.png

竞争消费者

Spring Cloud Stream定义了“Consumer Groups”的概念,如下所示:

“虽然发布 - 订阅模型可以轻松地通过共享主题连接应用程序,但通过创建给定应用程序的多个实例来扩展的能力同样重要。当这样做时, 应用程序的不同实例被置于竞争的消费者关系中,其中只有一个实例可以处理给定的消息。“

基于此定义,Spring Cloud Stream允许跨多个客户端分配主题的负载,如下图所示。a58b353ccefbcf0c77a277e7f9d057f7.png示例

在此示例中,MQTT客户端将消息发布到RabbitMQ中的一个主题,并且多个消费者将共享该主题的消息。

安装RabbitMQ和MQTT插件

首先,我们将使用Docker镜像运行RabbitMQ的实例。然后,我们将安装MQTT插件。

>docker run   -d  --hostname vs29 --name vs29 -p  8081:15672 -p  5672:5672 -p  1883:1883 rabbitmq:3-management

现在,让我们检查一下该容器的启动日志:

>docker ps

CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                                                                                                               NAMES

fbd443154bf6        rabbitmq:3-management     "docker-entrypoint.s..."   6 seconds ago       Up 2 seconds        4369/tcp, 0.0.0.0:1883->1883/tcp, 5671/tcp, 15671/tcp, 0.0.0.0:5672->5672/tcp, 25672/tcp, 0.0.0.0:8081->15672/tcp   vs29>docker logs fbd443154bf6 -f

....

....

...

2019-02-03 07:34:16.709 [info] <0.198.0>

node : rabbit@vs29

home dir : /var/lib/rabbitmq

config file(s) : /etc/rabbitmq/rabbitmq.conf

cookie hash : O+z+vUDvSh3J1vK/lV08Xw==

log(s) :

database dir : /var/lib/rabbitmq/mnesia/rabbit@vs29

日志的最后几行表示现在正在读取服务器。现在,让我们安装MQTT插件:

Navigate to the container first:>dockerexec-u 0 -it fbd443154bf6 /bin/bash

Enable the plugin now:

root@vs29:/#rabbitmq-plugins enable rabbitmq_mqtt

在RabbitMQ中添加新用户

让我们使用管理UI在RabbitMQ中添加一个新用户。打开URL http:// RabbitMQhost:8081 /然后导航到“Admin”选项卡(RabbitMQ中的默认凭据是guest / guest)。

要创建新用户:

在“用户名”字段中添加用户名。然后,让我们添加用户'client1'。在“密码”字段中设置密码,让我们将密码设置为“client1”

点击“添加用户”43542f3772adfaf24c094bc6bfabc32a.png

默认用户无权访问任何虚拟主机。单击“client1”以编辑此用户的权限。在新页面中,单击“设置权限”以授予用户访问所有虚拟主机的权限。

要验证一切正常,请使用MQTT客户端将数据推送到新服务器。在本教程中,我们将使用Mosquitto服务器提供的命令'mosquitto_pub'和'mosquitto_sub'。首先,让我们订阅服务器中的所有主题。其次,我们将一些数据推送到服务器。

..>mosquitto_pub -h xxx.xxx.xxx.xxx -t /my/topic -m "Hello World" -u client1 -P client1 -p 1883

..>mosquitto_sub -h xxx.xxx.xxx.xxx -t "#" -u client1 -P client1

Hello World

如果一切顺利,你应该收到'Hello World'

创建消息接收器服务

本教程的目标是在同一应用程序的多个实例之间分配负载。因此,让我们使用Spring Boot和Spring Cloud Stream创建一个使用消息的简单服务。

创建一个新的Spring Boot项目。您可以使用IDE或Spring Initializer

调整您的mvn文件以包含以下内容:

org.springframework.bootspring-boot-starter-parent2.1.2.RELEASE1.8Greenwich.RELEASEorg.springframework.bootspring-boot-starter-amqporg.springframework.cloudspring-cloud-streamorg.springframework.cloudspring-cloud-stream-binder-rabbitorg.springframework.bootspring-boot-starter-testtestorg.springframework.cloudspring-cloud-stream-test-supporttestorg.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportorg.springframework.bootspring-boot-maven-pluginspring-milestonesSpring Milestoneshttps://repo.spring.io/milestone

现在,让我们添加我们的流监听器:

import org.springframework.cloud.stream.annotation.EnableBinding;

import org.springframework.cloud.stream.annotation.Input;

import org.springframework.cloud.stream.annotation.StreamListener;

import org.springframework.messaging.SubscribableChannel;

@EnableBinding(MessageSink.InputChannel.class)

public class MessageSink {

@StreamListener(InputChannel.SINK)

public void handle(String message) {

System.out.println("new message:" + message + ", from worker :" + Thread.currentThread().getName());

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public interface InputChannel {

String SINK = "message-sink";

@Input(SINK)

SubscribableChannel sink();

}

}

下一步是定义和配置我们的Channel(这是本教程中最重要的部分)。配置将添加到application.yml文件中:

spring:

cloud:

stream:

bindings:

message-sink :

destination: amq.topic

binder: rabbit

group: messages-consumer-group

consumer :

concurrency: 1

rabbit:

bindings:

message-sink:

consumer:

durableSubscription: true

declareExchange: true

exchangeDurable: true

exchangeType: topic

queueNameGroupOnly: true

rabbitmq:

host: xxx.xxx.xxx.xxx

password: client1

username: client1

我们来讨论application.yml中的重要配置:

destination:amq.topic是MQTT插件使用的默认Exchange,因此我们需要订阅它。

group:根据Spring Cloud Documents,“订阅给定目标的所有组都会收到已发布数据的副本,但每个组中只有一个成员从该目标收到给定的消息”

consumer.concurrency:可用于处理此使用者中收到的消息的最大线程数。我们将此数字修改为任何正值,并且仍然应用“分组消费者”的概念。

queueNameGroupOnly:根据Spring Cloud Documents,'当为true时,从名称等于的队列中使用group。否则,队列名称为destination.group。例如,当使用Spring Cloud Stream从现有RabbitMQ队列中使用时,这很有用。实际上,这是一个非常重要的配置。省略此属性将在启动服务时导致许多错误,因为Spring将生成以'amq'开头的队列名称,这是RabbitMQ不允许的。您将在此主题中获得更多详细信息

验证负载分配

让我们启动服务的两个实例,并使用MQTT客户端推送一些数据。首先,打开命令Shell窗口,导航到项目源,然后使用该命令构建项目

>mvn clean compile package

其次,打开两个命令Shell窗口,导航到项目文件夹,然后使用该命令启动服务

>java -jar target\balanced_mqtt_client-0.0.1-SNAPSHOT.jar

现在,我们将从MQTT客户端推送一些数据:

>mosquitto_pub -h xxx.xxx.xxx.xxx -t /my/topic -m"message 1"-u client1 -P client1 -p 1883>mosquitto_pub -h xxx.xxx.xxx.xxx -t /my/topic -m"message 2"-u client1 -P client1 -p 1883>mosquitto_pub -h xxx.xxx.xxx.xxx -t /my/topic -m"message 3"-u client1 -P client1 -p 1883>mosquitto_pub -h xxx.xxx.xxx.xxx -t /my/topic -m"message 4"-u client1 -P client1 -p 1883>mosquitto_pub -h xxx.xxx.xxx.xxx -t /my/topic -m"message 5"-u client1 -P client1 -p 1883

在消费者方面,将看到以下消息:

消费者1:

2019-02-07 10:33:55.848  INFO 14284 --- [           main] o.s.i.a.i.AmqpInboundChannelAdapter      : started inbound.messages-consumer-group

2019-02-07 10:33:55.858  INFO 14284 --- [           main] r.n.cloud.rabbitmq.mqtt.MqttApplication  : Started MqttApplication in 8.824 seconds (JVM running for 9.318)

new message:message 1, from worker :messages-consumer-group-1

new message:message 3, from worker :messages-consumer-group-1

new message:message 5, from worker :messages-consumer-group-1

消费者2:

O 13832 --- [           main] o.s.i.a.i.AmqpInboundChannelAdapter      : started inbound.messages-consumer-group

O 13832 --- [           main] r.n.cloud.rabbitmq.mqtt.MqttApplication  : Started MqttApplication in 7.8 seconds (JVM running for 8.495)

worker :messages-consumer-group-1

worker :messages-consumer-group-1

我们可以看到,消息是在两个消费者之间分配的。

结论

本教程将介绍如何使用RabbitMQ服务器和“分组使用者”功能实现负载均衡的MQTT使用者。本文示例代码下载地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot集成RabbitMQMQTT可以使用Spring Boot的AMQP和Paho客户端库。以下是集成步骤: 1. 添加依赖 在pom.xml中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.0</version> </dependency> ``` 2. 配置RabbitMQ连接 在application.properties中配置RabbitMQ连接信息: ``` spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest ``` 3. 创建RabbitMQ消息接收者 创建一个类来接收RabbitMQ消息。在该类中,使用@RabbitListener注解标记方法,指定队列名称和消息处理方法。 ``` @Component public class RabbitMQReceiver { @RabbitListener(queues = "test") public void receive(String message) { // 处理消息 } } ``` 4. 创建MQTT消息接收者 创建一个类来接收MQTT消息。在该类中,实现MqttCallback接口,重写messageArrived方法来处理接收到的消息。 ``` @Component public class MQTTReceiver implements MqttCallback { @Override public void connectionLost(Throwable throwable) { // 连接丢失 } @Override public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { // 处理消息 } @Override public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { // 消息发送完成 } } ``` 5. 创建RabbitMQ消息发送者 创建一个类来发送RabbitMQ消息。在该类中,注入AmqpTemplate并调用convertAndSend方法来发送消息到指定队列。 ``` @Component public class RabbitMQSender { @Autowired private AmqpTemplate amqpTemplate; public void send(String message) { amqpTemplate.convertAndSend("test", message); } } ``` 6. 创建MQTT消息发送者 创建一个类来发送MQTT消息。在该类中,注入MqttClient并调用connect、publish和disconnect方法来发送消息。 ``` @Component public class MQTTSender { @Autowired private MqttClient mqttClient; @Autowired private MqttConnectOptions mqttConnectOptions; public void send(String topic, String message) throws MqttException { MqttMessage mqttMessage = new MqttMessage(message.getBytes()); mqttClient.connect(mqttConnectOptions); mqttClient.publish(topic, mqttMessage); mqttClient.disconnect(); } } ``` 以上是在Spring Boot中集成RabbitMQMQTT实现消息订阅和发送的基本步骤。需要注意的是,AMQP和MQTT是不同的消息协议,需要根据实际情况选择使用哪个协议。另外,需要确保网络通畅,否则可能会出现消息丢失等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值