MQTT研究之EMQ:【基础研究】
EMQ版本V2, emqttd-centos7-v2.3.11-1.el7.centos.x86_64.rpm
下载地址:http://emqtt.com/downloads/2318/centos7-rpm
机器环境: Linux CentOS7.2
安装完成后,默认是匿名用户访问。emq本身不带发布定于工具或者命令,需要借助类似mosquitto_sub、mosquitto_pub或者自己写客户端进行连接测试。关于mosquitto的环境搭建,请参照mosquitto环境搭建
api的http监听端口:默认8080
默认的web界面URL:http://ip:18083
做些基本的配置,配置API的访问端口,改成9909,只有不出现冲突即可。
##--------------------------------------------------------------------
## HTTP Management API Listener ## The IP Address and Port that the EMQ HTTP API will bind.
##
## Value: IP:Port | Port
##
## Default: 0.0.0.0:
listener.api.mgmt = 0.0.0.0:
配置节点参数:
#Value: <name>@<host>
node.name = iotbus3@10.95.197.3
注意,这里格式要用上面的给定风格<name>@<host>,否则会出现启动失败。例如,配置成下面:
node.name = iotbus3
就会出现错误:
[root@ws3 emqttd]# systemctl start emqttd.service
Job for emqttd.service failed because the control process exited with error code. See "systemctl status emqttd.service" and "journalctl -xe" for details. -- Unit emqttd.service has begun starting up.
12月 :: ws3 sh[]: -- :: Can't set long node name!
12月 :: ws3 sh[]: Please check your configuration
12月 :: ws3 sh[]: -- :: crash_report
12月 :: ws3 sh[]: initial_call: pid: registered_name: error_info: ancestors: message_queue_len: messages: links: dictionary: trap_exit: status: heap_size: stack_size: red
12月 :: ws3 sh[]: supervisor: errorContext: reason: offender: -- :: supervisor_report
12月 :: ws3 sh[]: supervisor: errorContext: reason: offender: -- :: crash_report
12月 :: ws3 sh[]: initial_call: pid: registered_name: error_info: ancestors: message_queue_len: messages: links: dictionary: trap_exit: status: heap_size: stack_size: red
12月 :: ws3 sh[]: application: exited: type: Kernel pid terminated (application_controller) ({application_start_failure,kernel,{{shutdown,{failed_to_start_child,net_sup,{shutdown,{failed_to_start_child,net_kernel,{
12月 :: ws3 sh[]: Crash dump is being written to: erl_crash.dump...done
12月 :: ws3 systemd[]: emqttd.service: control process exited, code=exited status=
12月 :: ws3 systemd[]: Failed to start emqtt daemon.
-- Subject: Unit emqttd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit emqttd.service has failed.
--
-- The result is failed.
修改正确后,启动,从/var/log/emqttd/erlang.log.1日志里面可以看到:
xec: /usr/lib64/emqttd/erts-9.0/bin/erlexec -boot /usr/lib64/emqttd/releases/2.3./emqttd -mode embedded -boot_var ERTS_LIB_DIR /usr/lib64/emqttd/erts-9.0/../lib -mnesia dir "/var/lib/emqttd/mnesia/iotbus3@10.95.197.3" -config /var/li
b/emqttd/configs/app.2018.12.11.21.42.27.config -args_file /var/lib/emqttd/configs/vm.2018.12.11.21.42.27.args -vm_args /var/lib/emqttd/configs/vm.2018.12.11.21.42.27.args -- console^M
Root: /usr/lib64/emqttd^M
/usr/lib64/emqttd^M
starting emqttd on node 'iotbus3@10.95.197.3'^M
emqttd ctl is starting...[ok]^M
emqttd hook is starting...[ok]^M
emqttd router is starting...[ok]^M
emqttd pubsub is starting...[ok]^M
emqttd stats is starting...[ok]^M
emqttd metrics is starting...[ok]^M
emqttd pooler is starting...[ok]^M
emqttd trace is starting...[ok]^M
emqttd client manager is starting...[ok]^M
emqttd session manager is starting...[ok]^M
emqttd session supervisor is starting...[ok]^M
emqttd wsclient supervisor is starting...[ok]^M
emqttd broker is starting...[ok]^M
emqttd alarm is starting...[ok]^M
emqttd mod supervisor is starting...[ok]^M
emqttd bridge supervisor is starting...[ok]^M
emqttd access control is starting...[ok]^M
emqttd system monitor is starting...[ok]^M
emqttd 2.3. is running now^M
Eshell V9. (abort with ^G)^M
(iotbus3@10.95.197.3)> Load emq_mod_presence module successfully.^M
(iotbus3@10.95.197.3)1> dashboard:http listen on 0.0.0.0:18083 with 4 acceptors.^M
(iotbus3@10.95.197.3)1> mqtt:tcp listen on 127.0.0.1:11883 with 4 acceptors.^M
(iotbus3@10.95.197.3)1> mqtt:tcp listen on 0.0.0.0:1883 with 16 acceptors.^M
(iotbus3@10.95.197.3)1> mqtt:ws listen on 0.0.0.0:8083 with 4 acceptors.^M
(iotbus3@10.95.197.3)1> mqtt:ssl listen on 0.0.0.0:8883 with 16 acceptors.^M
(iotbus3@10.95.197.3)1> mqtt:wss listen on 0.0.0.0:8084 with 4 acceptors.^M
(iotbus3@10.95.197.3)1> mqtt:api listen on 0.0.0.0:9909 with 4 acceptors.^M
(iotbus3@10.95.197.3)>
重点关注上面红色的部分,dashboard的访问模式,以及各种访问接口的端口和协议类型。
配置ACL,EMQ的ACL做的非常全面,由于这里只是研究,和mosquitto进行性能对比,也将其配置成单节点的username/password的访问方式。
修改/etc/emqtt/emq.conf
#默认这里是true
mqtt.allow_anonymous = false
#默认这里是allow
mqtt.acl_nomatch = deny
mqtt.acl_file = /etc/emqttd/acl.conf
接下来,配置/etc/emqttd/acl.conf
%%--------------------------------------------------------------------
%%
%% [ACL](https://github.com/emqtt/emqttd/wiki/ACL)
%%
%% -type who() :: all | binary() |
%% {ipaddr, esockd_access:cidr()} |
%% {client, binary()} |
%% {user, binary()}.
%%
%% -type access() :: subscribe | publish | pubsub.
%%
%% -type topic() :: binary().
%%
%% -type rule() :: {allow, all} |
%% {allow, who(), access(), list(topic())} |
%% {deny, all} |
%% {deny, who(), access(), list(topic())}.
%%
%%-------------------------------------------------------------------- {allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. {allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}. {deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
这是默认的acl.conf文件,在这里,添加一个ACL元素:
{allow, {user, "shihuc"}, pubsub, ["$SYS/#", "#"]}.
即最终这个配置好的acl.conf文件内容为:
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
{allow, {user, "shihuc"}, pubsub, ["$SYS/#", "#"]}.
加载username鉴权插件emq_auth_username:
[root@ws3 emqttd]# emqttd_ctl plugins load emq_auth_username
Start apps: [emq_auth_username]
Plugin emq_auth_username loaded successfully.
添加新的用户名和密码:
[root@ws3 emqttd]# emqttd_ctl users add shihuc shihuc
ok
测试:
[root@ws2 logs]# mosquitto_sub -t iotbus -u shihuc -P shihuc -h 10.95.197.3 -p
Error: No route to host
两种解决方案:
1. 在10.95.197.3的机器上执行 iptables -F清除防火墙设置。
2. 在10.95.197.3的机器上执行firewall-cmd --add-port=1883/tcp添加一条防火墙规则。
依照第二条,配置好防火墙后,启动ws3上的emq服务,进行订阅没有问题。
基于username/password的方式(emq_auth_username插件)逻辑走通了。
接下来测试,发现一个问题:
[root@ws2 ~]# mosquitto_pub -t iotbus -h 10.95.197.3 -p -u shihuc -P shihuc -q -m "ACL verification"
订阅程序启动没有问题,但是发布消息后,订阅端没有反应,说明消息被拒绝了。
分析:
. 指令订阅和发布不存在鉴权错误,即没有提示用户名和密码错误(如下)。
Connection Refused: bad user name or password.
Error: The connection was refused.
. 发消息后,接收端没有反应,说明acl里面对topic的匹配流程链路出现问题,再次细读EMQ文档:
ACL 访问控制规则定义:
允许(Allow)|拒绝(Deny) 谁(Who) 订阅(Subscribe)|发布(Publish) 主题列表(Topics)
MQTT 客户端发起订阅/发布请求时,EMQ 消息服务器的访问控制模块,会逐条匹配 ACL 规则,直到匹配成功为止:
--------- --------- ---------
Client -> | Rule1 | --nomatch--> | Rule2 | --nomatch--> | Rule3 | --> Default
--------- --------- ---------
| | |
match match match
\|/ \|/ \|/
allow | deny allow | deny allow | deny
结合acl.conf的配置内容:
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
{allow, {user, "shihuc"}, pubsub, ["$SYS/#", "#"]}.
不难发现,新加的一条规则{allow, {user, "shihuc"}, pubsub, ["$SYS/#", "#"]}.被规则{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.deny掉了,所以出现上述订阅端没有反应的问题。将这两条规则调整一下先后顺序即可解决问题(最新的规则):
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
{allow, {user, "shihuc"}, pubsub, ["$SYS/#", "#"]}.
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
调整后,再次验证发布订阅逻辑,一切运行正常,到此,基本的环境构建完成。
补充研究:基于MySQL的认证和授权
1. 首先配置数据库信息 /etc/emqtt/plugins/emq_auth_mysql.conf
##--------------------------------------------------------------------
## MySQL Auth/ACL Plugin
##-------------------------------------------------------------------- ## MySQL server address.
##
## Value: Port | IP:Port
##
## Examples: , 127.0.0.1:, localhost:
auth.mysql.server = 10.95.197.10: ## MySQL pool size.
##
## Value: Number
auth.mysql.pool = ## MySQL username.
##
## Value: String
auth.mysql.username = iotbususer ## MySQL password.
##
## Value: String
auth.mysql.password = iotbus2018! ## MySQL database.
##
## Value: String
auth.mysql.database = mqtt ## Variables: %u = username, %c = clientid ## Authentication query.
##
## Note that column names should be 'password' and 'salt' (if used).
## In case column names differ in your DB - please use aliases,
## e.g. "my_column_name as password".
##
## Value: SQL
##
## Variables:
## - %u: username
## - %c: clientid
##
auth.mysql.auth_query = select password from mqtt_user where username = '%u' limit
## auth.mysql.auth_query = select password_hash as password from mqtt_user where username = '%u' limit ## Password hash.
##
## Value: plain | md5 | sha | sha256 | bcrypt
auth.mysql.password_hash = sha256 ## sha256 with salt prefix
## auth.mysql.password_hash = salt,sha256 ## bcrypt with salt only prefix
## auth.mysql.password_hash = salt,bcrypt ## sha256 with salt suffix
## auth.mysql.password_hash = sha256,salt ## pbkdf2 with macfun iterations dklen
## macfun: md4, md5, ripemd160, sha, sha224, sha256, sha384, sha512
## auth.mysql.password_hash = pbkdf2,sha256,, ## Superuser query.
##
## Value: SQL
##
## Variables:
## - %u: username
## - %c: clientid
auth.mysql.super_query = select is_superuser from mqtt_user where username = '%u' limit ## ACL query.
##
## Value: SQL
##
## Variables:
## - %a: ipaddr
## - %u: username
## - %c: clientid
auth.mysql.acl_query = select allow, ipaddr, username, clientid, access, topic from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'
以上配置中,比较主要配置项是:
auth.mysql.server
auth.mysql.username
auth.mysql.password
auth.mysql.database
auth.mysql.password_hash
2. 创建mqtt所需的鉴权表
MQTT 用户表
CREATE TABLE `mqtt_user` (
`id` int() unsigned NOT NULL AUTO_INCREMENT,
`username` varchar() DEFAULT NULL,
`password` varchar() DEFAULT NULL,
`salt` varchar() DEFAULT NULL,
`is_superuser` tinyint() DEFAULT ,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `mqtt_username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
MQTT 访问控制表
CREATE TABLE `mqtt_acl` (
`id` int() unsigned NOT NULL AUTO_INCREMENT,
`allow` int() DEFAULT NULL COMMENT '0: deny, 1: allow',
`ipaddr` varchar() DEFAULT NULL COMMENT 'IpAddress',
`username` varchar() DEFAULT NULL COMMENT 'Username',
`clientid` varchar() DEFAULT NULL COMMENT 'ClientId',
`access` int() NOT NULL COMMENT '1: subscribe, 2: publish, 3: pubsub',
`topic` varchar() NOT NULL DEFAULT '' COMMENT 'Topic Filter',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `mqtt_acl` (`id`, `allow`, `ipaddr`, `username`, `clientid`, `access`, `topic`)
VALUES
(,,NULL,'$all',NULL,,'#'),
(,,NULL,'$all',NULL,,'$SYS/#'),
(,,NULL,'$all',NULL,,'eq #'),
(,,'127.0.0.1',NULL,NULL,,'$SYS/#'),
(,,'127.0.0.1',NULL,NULL,,'#'),
(,,NULL,'dashboard',NULL,,'$SYS/#');
为了验证自己所加用户是否有权限,做个验证:
mysql> insert into mqtt_acl (allow, ipaddr, username, clientid, access, topic) values (, NULL, "water", NULL, , "/taikang/#");
Query OK, row affected (0.00 sec)
mysql> update mqtt_acl set access= where username="water";
Query OK, row affected (0.01 sec)
Rows matched: Changed: Warnings: mysql>
mysql> select * from mqtt_acl;
+----+-------+-----------+-----------+----------+--------+------------+
| id | allow | ipaddr | username | clientid | access | topic |
+----+-------+-----------+-----------+----------+--------+------------+
| | | NULL | $all | NULL | | # |
| | | NULL | $all | NULL | | $SYS/# |
| | | NULL | $all | NULL | | eq # |
| | | 127.0.0.1 | NULL | NULL | | $SYS/# |
| | | 127.0.0.1 | NULL | NULL | | # |
| | | NULL | dashboard | NULL | | $SYS/# |
| | | NULL | shihuc | NULL | | /taikang/# |
| | | NULL | water | NULL | | /taikang/# |
+----+-------+-----------+-----------+----------+--------+------------+
rows in set (0.00 sec)
注意:这里access是控制访问级别的:1是sub,2是pub,3是pubsub。
mysql> insert into mqtt_user(username, password) values("water", "0f4168490e38b8447e11ba4bd656aa11b925bd22af30bac464bc153fdb608501");
Query OK, row affected (0.00 sec) mysql> select * from mqtt_user;
+----+----------+------------------------------------------------------------------+------+--------------+---------+
| id | username | password | salt | is_superuser | created |
+----+----------+------------------------------------------------------------------+------+--------------+---------+
| | water | 0f4168490e38b8447e11ba4bd656aa11b925bd22af30bac464bc153fdb608501 | NULL | | NULL |
+----+----------+------------------------------------------------------------------+------+--------------+---------+
row in set (0.00 sec)
注意这里insert用户记录的时候,password字段的值是一个sha256加密算法的字符串,我这里是通过在线加密工具获取的密码http://www.ttmd5.com/hash.php?type=9。
3. 加载配置
[root@ws3 ~]# emqttd_ctl plugins load emq_auth_mysql
查看目前有多少加载的plugin:
[root@ws3 ~]# emqttd_ctl plugins list
Plugin(emq_auth_clientid, version=2.3., description=Authentication with ClientId/Password, active=false)
Plugin(emq_auth_http, version=2.3., description=Authentication/ACL with HTTP API, active=false)
Plugin(emq_auth_jwt, version=2.3., description=Authentication with JWT, active=false)
Plugin(emq_auth_ldap, version=2.3., description=Authentication/ACL with LDAP, active=false)
Plugin(emq_auth_mongo, version=2.3., description=Authentication/ACL with MongoDB, active=false)
Plugin(emq_auth_mysql, version=2.3., description=Authentication/ACL with MySQL, active=true)
Plugin(emq_auth_pgsql, version=2.3., description=Authentication/ACL with PostgreSQL, active=false)
Plugin(emq_auth_redis, version=2.3., description=Authentication/ACL with Redis, active=false)
Plugin(emq_auth_username, version=2.3., description=Authentication with Username/Password, active=true)
Plugin(emq_coap, version=2.3., description=CoAP Gateway, active=false)
Plugin(emq_dashboard, version=2.3., description=EMQ Web Dashboard, active=true)
Plugin(emq_lua_hook, version=2.3., description=EMQ Hooks in lua, active=false)
Plugin(emq_modules, version=2.3., description=EMQ Modules, active=true)
Plugin(emq_plugin_template, version=2.3., description=EMQ Plugin Template, active=false)
Plugin(emq_recon, version=2.3., description=Recon Plugin, active=true)
Plugin(emq_reloader, version=2.3., description=Reloader Plugin, active=false)
Plugin(emq_retainer, version=2.3., description=EMQ Retainer, active=true)
Plugin(emq_sn, version=2.3., description=MQTT-SN Gateway, active=false)
Plugin(emq_stomp, version=2.3., description=Stomp Protocol Plugin, active=false)
Plugin(emq_web_hook, version=2.3., description=EMQ Webhook Plugin, active=false)
active是true的是加载运行了的,active是false的,表示未运行的,从下面的图也可以看。
最后,基于mosquitto_sub和mosquitto_pub进行验证:
[root@ws2 ~]# mosquitto_pub -t /taikang/iotbus -h 10.95.197.3 -p -u water -P water -q -m "ACL verification xxxxxxxx"
[root@ws2 logs]# mosquitto_sub -t /taikang/iotbus -u water -P water -h 10.95.197.3 -p
ACL verification xxxxxxxx
基于MySQL的认证和授权,操作非常灵活,具有很大的效用,物联网中物接入很值得借鉴这个能力。
MQTT研究之EMQ:【基础研究】的更多相关文章
- MQTT研究之EMQ:【EMQ之HTTP认证/访问控制】
今天进行验证的逻辑是EMQ的http的Auth以及ACL的逻辑. 首先,参照HTTP插件认证配置的说明文档进行基本的配置, 我的配置内容如下: ##-------------------------- ...
- MQTT研究之EMQ:【CoAP协议应用开发】
本博文的重点是尝试CoAP协议的应用开发,其中包含CoAP协议中一个重要的开源工具libcoap的安装和遇到的问题调研.当然,为了很好的将EMQ的CoAP协议网关用起来,也调研了下EMQ体系下,CoA ...
- MQTT研究之EMQ:【JAVA代码构建X509证书【续集】】
openssl创建私钥,获取公钥,创建证书都是比较简单的,就几个指令,很快就可以搞定,之所以说简单,是因为证书里面的基本参数配置不需要我们组装,只需要将命令行里面需要的几个参数配置进去即可.但是呢,用 ...
- MQTT研究之EMQ:【SSL证书链验证】
1. 创建证书链(shell脚本) 客户端证书链关系: rootCA-->chainca1-->chainca2-->chainca3 ca caCert1 caCert2 caCe ...
- MQTT研究之EMQ:【EMQX使用中的一些问题记录(2)】
我的测试环境: Linux: CentOS7 EMQX:V3.2.3 题外话: 这里主要介绍Websocket的支持问题. 对ws的支持比较正常,但是对wss的支持,调了较长的时间,没有成功. Jav ...
- 关于埃博拉(Ebola)基础研究病毒
关于埃博拉(Ebola)病毒的基础研究 2005年.美国哈佛大学医学研究院(Harvard Medical School)James Cunningham教授关于埃博拉病毒有一项基础研究,研究成果发表 ...
- MQTT研究之EMQ:【JAVA代码构建X509证书】
这篇帖子,不会过多解释X509证书的基础理论知识,也不会介绍太多SSL/TLS的基本信息,重点介绍如何用java实现SSL协议需要的X509规范的证书. 之前的博文,介绍过用openssl创建证书,并 ...
- MQTT研究之EMQ:【EMQX使用中的一些问题记录(4)】
最近比较忙,有些关于EMQ的使用问题,没有时间记录了,趁这个周末抽点时间,将最近遇到的,觉得比较有价值的一个问题,分享给大家吧. 这里是针对前面的一篇博客,做的一个深入研究,关于订阅系统总线判断设备上 ...
- MQTT研究之EMQ:【EMQX使用中的一些问题记录(1)】
issue 1. EMQX的共享订阅 EMQX是一个非常强大的物联网通信消息总线,基于EMQX开展应用开发,要注意很多配置细节问题,这里要说到的就是共享订阅以及和cleanSession之间的关系问题 ...
随机推荐
- chrome console.log失效
把红框里的内容去掉就可以了 那个框是过滤..
- 使用 <embed> 标签显示 flash文件(swf)格式 ,如何设置 width 和 height 宽度,高度.
1. embed 标签 支持 .swf 格式. .flv 的不支持. 2. 通常情况下, 网站中上传 多个 flash文件. 它的默认大小是不一样的. 而且 可以 宽度 大于 高度(横向的) ...
- 从运维的角度理解Iaas、Paas、Saas云计算
平时我们的运维工作,大致就是了解需求.申请服务器.配置网络.服务器软件安装.应用部署.数据存储.系统调优.平台维护等 按照Iaas.Paas.Saas的三层来分工我们平时的任务: 最底层的Iaas层提 ...
- 单链表sLinkList类,模板类
sLinkList模板类,单链表代码 /* 该文件按习惯可以分成.h文件和实现的.cpp文件 */ template <class elemType> class sLinkList { ...
- scrapy框架修改单个爬虫的配置,包括下载延时,下载超时设置
在一个框架里面有多个爬虫时,每个爬虫的需求不相同,例如,延时的时间,所以可以在这里配置一下custom_settings = {},大括号里面写需要修改的配置,然后就能把settings里面的配置给覆 ...
- WebStorm 破解方法
WebStorm 破解方法 第一步 打开 IntelliJ IDEA 注册码 网址,点击下载最新的 破解补丁 第二步 将下载下来的破解补丁,复制到WebStorm 安装目录的bin目录下 第三步 修改 ...
- select默认显示
select默认显示第一个option,但大部分需求都是显示一个请选择,点击后在显示option的内容. 就像上图一样 但如果正常写的话会是像下面这样显示 请选择也会显示在下拉款里面,这样就很不友好 ...
- echarts常见配置项总结,legend、toolbox、tooltip等
1.饼状图指示线改变颜色:series.labelLine.lineStyle series : [ { name: '默认文字', type: 'pie',//类型饼状图 hoverAnimatio ...
- mysqlQL 5.7 安装报错CMake Error at cmake/boost.cmake:81 (MESSAGE)
CMake Error at cmake/boost.cmake:81 (MESSAGE): You can download it with -DDOWNLOAD_BOOST=1 -DWITH_BO ...
- VBO最佳实践
VBO的大小 一个VBO应该多大? 你可以创建一个很小的VBO,但最佳方案是把很多对象放到一个VBO里面,这样的话可以减少调用gl函数的数量,比如glBindBuffer.glVertexPointe ...