最近的开发中用到MQTT协议和EMQ消息服务器,MQTT和EMQ是物联网的产物,想必会随着5G时代和万物互联的到来而逐渐火热。
# EMQ:
是一个MQTT消息服务器
### 基于 Apache 2.0 协议许可,完全开源。
EMQ X 的代码都放在 Github 中,用户可以查看所有源代码。
EMQ X 3.0 支持 MQTT 5.0 协议,是 开源社区中第一个 支持 5.0 协议规范的消息服务器,并且完全兼容 MQTT V3.1 和 V3.1.1 协议。除了 MQTT 协议之外,EMQ X 还支持别的一些物联网协议(具体请参见下文的 EMQ X Broker 产品功能介绍)。
### 单机支持百万连接,集群支持千万级连接;毫秒级消息转发。
EMQ X 中应用了多种技术以实现上述功能,
利用 Erlang/OTP 平台的软实时、高并发和容错
全异步架构
连接、会话、路由、集群的分层设计
消息平面和控制平面的分离等
扩展模块和插件,EMQ X 提供了灵活的扩展机制,可以实现私有协议、认证鉴权、数据持久化、桥接转发和管理控制台等的扩展
桥接:EMQ X 可以跟别的消息系统进行对接,比如 EMQ X Enterprise 版本中可以支持将消息转发到 Kafka、RabbitMQ 或者别的 EMQ 节点等
共享订阅:共享订阅支持通过负载均衡的方式在多个订阅者之间来分发 MQTT 消息。比如针对物联网等数据采集场景,会有比较多的设备在发送数据,通过共享订阅的方式可以在订阅端设置多个订阅者来实现这几个订阅者之间的工作负载均衡
### MQTT:
MQTT 是 Message Queuing Telemetry Transport(消息队列遥测传输)的缩写,是 IBM 开发的一个即时通讯协议,它比较适合于在低带宽、不可靠的网络的进行远程传感器和控制设备通讯等,正在日益成为物联网通信协议的重要组成部分。
基于发布 / 订阅范式的 “轻量级” 消息协议(头部 2 字节)
专为资源受限的设备、低带宽占用高延时或者不可靠的网络设计,适用于 IoT 与 M2M
基于 TCP/IP 协议栈
事实的 IoT 通讯的标准协议
该协议于 1999 年由 IBM 的 Dr Andy Stanford-Clark 和 Arcom(现为 Eurotech)的 Arlen Nipper 提出,协议版本经历了多次升级和改进,于 2013 年成立 OASIS MQTT 技术规范委员会,并持续发布协议的新版本,
#### 版本
2015 年,MQTT3.1.1 协议发布
2018 年,MQTT5.0 协议发布
#### MQTT 协议的主要特性
MQTT 协议使用发布 / 订阅消息范式来做到一对多的消息分发以及应用程序的解耦
MQTT 协议提供了 3 种(QoS)服务质量用于消息传输,适应不同的物联网数据传输场景
QoS 0:最多一次传送 (只负责传送,发送过后就不管数据的传送情况)
QoS 1:至少一次传送 (确认数据交付)
QoS 2:正好一次传送 (保证数据交付成功)
通过很小的传输开销,以及最小化的协议交换来减少网络流量
发生异常断线时通知各方的机制
#### MQTT 服务器
MQTT 服务器是发布者和订阅者之间通信的代理(因此中文也有将 MQTT 服务器翻译为 MQTT 代理),主要提供了以下的功能,
基于主题的 Pub/Sub 模式,将发布者和订阅着解耦
对于服务器来说,发布者和订阅者都是“客户端”
客户端与服务器连接都通过 TCP、TLS 或者 WebSocket
客户端(发布者)发送一条消息到服务器
一个或者多个客户端(订阅者)从服务器接收消息
##### 按照 MQTT 协议标准,服务器提供三种连接方式,
TCP:默认端口为 1883
TLS:默认端口为 8883
WebSocket:默认端口为 8083
##启动
centos:
emqx start
emqx_ctl status
sudo systemctl start emq
*** sudo service emqx start
windows:
cd emqx/bin
emqx start
java使用
maven依赖
建立连接,
MemoryPersistence persistence = new MemoryPersistence();
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
//设置连接参数
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
sampleClient.connect(connOpts);
生产者:
向指定的topic发送消息
String content = "Message from MqttPublishSample";
int qos = 2;
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
消费者:
从指定的topic订阅消息
String topic = "demo/topics";
sampleClient.subscribe(topic);
sampleClient.setCallback(new MqttCallback() {
public void messageArrived(String topic, MqttMessage message) throws Exception {
String theMsg = MessageFormat.format("{0} is arrived for topic {1}.", new String(message.getPayload()), topic);
System.out.println(theMsg);
}
public void deliveryComplete(IMqttDeliveryToken token) {
}
public void connectionLost(Throwable throwable) {
}
});
集群中,消息生产者通过负载均衡实现主题订阅和消息发布,那消息消费者如何准确的在集群中订阅主题和消费消息
EMQ X 消息服务器每个集群节点,都保存一份主题树(Topic Trie)和路由表。
最终会生成主题树(Topic Trie)和路由表(Route Table):
##集群的配置
1、修改配置文件etc/emqx.conf
修改节点名字
node.name [email protected]
通过命令
export [email protected] && ./bin/emqx start
2、将节点加入集群
./bin/emqx_ctl cluster join [email protected]
创建集群的策略
manual 手动命令创建集群
static 静态节点列表自动集群
mcast UDP 组播方式自动集群
dns DNS A 记录自动集群
etcd 通过 etcd 自动集群
k8s Kubernetes 服务自动集群
配置:
etc/emqx.conf EMQ X Edge 消息服务器配置文件
etc/acl.conf EMQ X Edge 默认ACL规则配置文件
etc/plugins/*.conf EMQ X Edge 各类插件配置文件
用户管理
1、配置文件emqx.conf
allow_anonymous = false
2、添加用户密码
emqx_ctl plugins load emqx_auth_username #加载用户权限验证插件
emqx_ctl users add
如:emqx_ctl users add myemq jack666
服务质量qos
MQTT发布消息QoS保证不是端到端的,是客户端与服务器之间的。订阅者收到MQTT消息的QoS级别,最终取决于发布消息的QoS和主题订阅的QoS。只有QoS==1,2时候,才有Store(Msg)之说,,通过Store(Msg)和唯一的MessageID来保证消息不会重复接收和发送!;QoS==0时没有
EMQ的共享订阅和保留消息
共享订阅模式:多人订阅,不重复消费,实现消息消费的负载均衡
$queue 和 $share 之间的差异:
$queue 之后的主题中所有消息将轮流发送到客户端,
$share 之后,您可以添加不同的组,例如:
$share/group_1/topic
$share/group_2/topic
$share/group_3/topic
当 EMQ X 向 topic 发送消息时,每个组都会收到该消息,并依次将其发送到该组中的设备。
保留消息,
message.setRetained(true);保留消息每次订阅都会被消费一次,重新发布只会保留最新的一条