EMQX物联网MQTT消息服务器集群搭建
莱昂纳多迪卡普利奥 2024-08-14 12:37:02 阅读 82
EMQX官方介绍
1 环境准备
两台Ubuntu 20.04 作为EMQX节点
一台Ubuntu 20.04安装MYSQL数据库
2 搭建EMQX集群
2.1 下载EMQX开源版安装包
1访问https://www.emqx.com/zh/try?product=broker,选择对应的EMQX版本
2 点击免费下载,选择安装方式和CPU架构
3 下载EMQX安装包并解压
执行下面的命令下载EMQX安装包
<code>
wget https://www.emqx.com/zh/downloads/broker/4.4.5/emqx-4.4.5-otp24.1.5-3-ubuntu20.04-amd64.zip
解压安装包
2.2 修改EMQX配置文件
安装包解压后进入emqx文件夹
修改emqx.conf文件
<code>vim etc/emqx.conf
(1)修改节点名称
节点1 node.name=emqx1@IP
节点2 node.name=emqx2@IP
(2)修改创建集群方式
方式一:使用 static模式
根据节点列表自动创建集群
修改cluster.discovery = static
修改cluster.static.seeds = emqx1@IP,emqx2@IP(多个节点以逗号分割)
修改完成后保存
方式二:手动(manual) 方式管理集群
# 配置集群名称
cluster.name = emqxcl
# 配置集群发现方式
cluster.discovery = manual
# 配置节点名称,节点名格式为 Name@Host, Host 必须是 IP 地址或 FQDN (主机名。域名)
node.name = emqx1@IP
2.3 防火墙配置
使用下面的命令在防火墙开放端口号
sudo ufw allow 端口号
防火墙开放以下端口:
(1)Dashboard访问端口18083
(2)ekka 模式(4.0 版本之后的默认模式):
在ekka 模式下,集群发现端口的映射关系是约定好的,而不是动态的。 node.dist_listen_min 和 node.dist_listen_max 两个配置在ekka 模式下不起作用。
如果集群节点间存在防火墙,防火墙需要放开这个约定的端口。约定端口的规则如下:
ListeningPort = BasePort + Offset
其中 BasePort 为 4370 (不可配置), Offset 为节点名的数字后缀. 如果节点名没有数字后缀的话, Offsset 为 0。
举例来说, 如果 emqx.conf 里配置了节点名:node.name = emqx@192.168.0.12,那么监听端口为 4370, 但对于 emqx1 (或者 emqx-1) 端口就是 4371,以此类推。
(3)The Cluster RPC Port
每个节点还需要监听一个 RPC 端口,也需要被防火墙也放开。跟上面说的ekka 模式下的集群发现端口一样,这个 RPC 端口也是约定式的。
RPC 端口的规则跟ekka 模式下的集群发现端口类似,只不过 BasePort = 5370。就是说,如果 emqx.conf 里配置了节点名:node.name = emqx@192.168.0.12,那么监听端口为 5370, 但对于 emqx1 (或者 emqx-1) 端口就是 5371,以此类推。
2.4 启动EMQX集群
(1)分别启动EMQX集群的每个节点
进入emqx文件夹执行下面的命令启动EMQX Broker
./bin/emqx start
使用 static模式创建集群时,当节点全部启动后,会自动创建集群
使用手动(manual) 方式管理集群:
在节点1加入节点2形成集群
# 在节点emqx1@IP上执行
./bin/emqx_ctl cluster join emqx2@IP
# 或者在节点在节点emqx2@IP执行
./bin/emqx_ctl cluster join emqx1@IP
节点退出集群:
# 让本节点退出集群
./bin/emqx_ctl cluster leave
# 从集群删除其他节点
./bin/emqx_ctl cluster force-leave emqx1@IP
(2)查看节点状态:
./bin/emqx_ctl status
(3)查看emqx集群状态:
./bin/emqx_ctl cluster status
2.5 访问EMQX Dashboard
访问 http://ip:18083 来查看Dashboard,默认用户名是 admin,密码是 public
3 EMQX认证
EMQX 的认证支持包括两个层面:
MQTT 协议本身在 CONNECT 报文中指定用户名和密码,EMQX 以插件形式支持基于 Username、ClientID、HTTP、JWT、LDAP 及各类数据库如 MongoDB、MySQL、PostgreSQL、Redis 等多种形式的认证。
在传输层上,TLS 可以保证使用客户端证书的客户端到服务器的身份验证,并确保服务器向客户端验证服务器证书。也支持基于 PSK 的 TLS/DTLS 认证。
本章节介绍了 EMQX 的MySQL认证插件的配置方法以及TLS认证配置。
3.1 开启认证模式
EMQ X 默认配置中启用了匿名认证,任何客户端都能接入 EMQX,因此,EMQX开启认证首先要关闭匿名认证。
vim etc/emqx.conf
将allow_anonymous设为false,关闭匿名访问,关闭后EMQX将不允许匿名用户连接,需要通过用户名密码连接。
3.2 MySQL认证
MySQL 认证使用外部 MySQL 数据库作为认证数据源,可以存储大量数据,同时方便与外部设备管理系统集成。
3.2.1 安装MySQL数据库
MySQL数据库配置
3.2.2 MySQL认证配置
1 在MySQL中创建emqx所需的数据库和用户认证表
(1)创建用户名emqx密码emqx
<code>CREATE USER emqx@'%' IDENTIFIED BY 'emqx';
(2)创建emqx数据库
create database emqx character set utf8;
(3)将数据库emqx下的所有表授权给emqx用户
grant all privileges on emqx.* to 'emqx'@'%';
(4)创建认证用户表
CREATE TABLE `mqtt_user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`salt` varchar(35) DEFAULT NULL,
`is_superuser` tinyint(1) DEFAULT 0,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `mqtt_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
创建好数据库相关用户和表结构后在每个节点的配置文件etc/plugins/emqx_auth_mysql.conf 中配置以下内容:
2 修改MySQL认证配置文件
创建好数据库相关用户和表结构后在每个节点的配置文件etc/plugins/emqx_auth_mysql.conf 中配置以下内容:
(1)配置 MySQL 服务相关的连接地址,用户名密码和数据库
(2) 配置认证SQL
进行身份认证时,EMQX 将使用当前客户端信息填充并执行用户配置的认证 SQL,查询出该客户端在数据库中的认证数据。
你可以在认证 SQL 中使用以下占位符,执行时 EMQX 将自动填充为客户端信息:
%u:用户名
%c:Client ID
%C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
%d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整认证 SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下认证 SQL 需要满足以下条件:
a.查询结果中必须包含 password 字段,EMQX 使用该字段与客户端密码比对
b.如果启用了加盐配置,查询结果中必须包含 salt 字段,EMQX 使用该字段作为 salt(盐)值
c.查询结果只能有一条,多条结果时只取第一条作为有效数据
(3) 配置加盐规则与哈希方法
配置密码加密方式,本文密码加密采用加盐+sha256方式
3.3 TLS认证双向认证
1 MQTT TLS 的默认端口是 8883:
2 配置证书和 CA
开启TLS双向认证时需要创建客户端和服务端证书,并在此处配置服务端证书的位置,在使用TLS双向认证连接时,需要在客户端配置客户端证书。
创建自签名证书方法参考附录6.1章节
3 开启双向认证
以下两个配置是 打开服务端 验证客户端证书 (默认关闭 即单向验证 打开即可实现双向认证)
作为一种性能优化设置,它允许客户端重用预先存在的会话,而不是初始化新的会话。
EMQX集群所有节点配置完成后,分别重启每个节点
3.4 认证验证
3.4.1 开启emqx_auth_mysql插件认证
开启所有节点的emqx_auth_mysql插件认证,打开emqx Dashboard界面,点击插件模块,启动emqx_auth_mysql插件。
3.4.2 创建emqx用户名和密码
在emqx数据库的mqtt_user表中新增一个用户
<code>INSERT INTO `mqtt_user` ( `username`, `password`, `salt`) VALUES
(‘test’, ‘62a11257d24e7b577b87936eaf7931a0f15bc7b4e52f2c37507b7792c38b6d0c’, ‘secret’);
注意:
密码是经过加密后的密文,如果采用了加盐,需要添加加盐字段,可以在网上搜索加密工具,本文使用的加密工具地址:md5加密,sha1加密--md5在线解密
选择正确的加密方式生成的密码hash值(本文是采用salt+sha256)
3.4.3 验证
3.4.3.1 使用WebSocket工具
使用EMQX Dashboard Websocket工具可以进行简单的客户端连接服务端测试,主题订阅和发布消息。
开启MYSQL认证后,需要通过已创建的用户名和密码连接,否则会显示连接失败。
使用WebSocket工具的SSL连接需要安装客户端证书,否则无法连接,本文推荐使用MQTTX客户端工具进行SSL认证连接测试。
3.4.3.2 MQTTX客户端连接工具
1 安装MQTTX客户端
访问MQTTX:全功能 MQTT 客户端工具下载安装MQTTX客户端
2 打开客户端新建连接
(1)新建一个连接,填写服务端地址、端口号、用户名和密码,开启SSL/TLS双向认证,选择自定义证书,开启SSL Secure。
(2)选择本地客户端证书的位置
点击connect进行连接
MQTTX其他功能可以参考官方文档,在次不做过多介绍
MQTTX:全功能 MQTT 客户端工具
4 发布订阅 ACL
发布订阅 ACL 指对 发布 (PUBLISH)/订阅 (SUBSCRIBE) 操作的 权限控制。例如拒绝用户名为 Anna 向 open/elsa/door 发布消息。
EMQX 支持通过客户端发布订阅 ACL 进行客户端权限的管理,本章节介绍了 EMQX 发布订阅 ACL 以及对应MYSQL插件的配置方法。
4.1 MySQL插件配置
发布订阅 ACL功能包含在emqx_auth_mysql 插件中,在3.2MySQL认证小节中已经开启了此插件,并进行了数据库配置,在此基础上还需进行如下配置。
4.1.1 创建ACL规则表
在emqx数据库中创建acl规则表mqtt_acl
<code>CREATE TABLE `mqtt_acl` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`allow` int(1) DEFAULT 1 COMMENT '0: deny, 1: allow',
`ipaddr` varchar(60) DEFAULT NULL COMMENT 'IpAddress',
`username` varchar(100) DEFAULT NULL COMMENT 'Username',
`clientid` varchar(100) DEFAULT NULL COMMENT 'ClientId',
`access` int(2) NOT NULL COMMENT '1: subscribe, 2: publish, 3: pubsub',
`topic` varchar(100) NOT NULL DEFAULT '' COMMENT 'Topic Filter',
PRIMARY KEY (`id`),
INDEX (ipaddr),
INDEX (username),
INDEX (clientid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
规则表字段说明:
allow:禁止(0),允许(1)
ipaddr:设置 IP 地址
username:连接客户端的用户名,此处的值如果设置为 $all 表示该规则适用于所有的用户
clientid:连接客户端的 Client ID
access:允许的操作:订阅(1),发布(2),订阅发布都可以(3)
topic:控制的主题,可以使用通配符,并且可以在主题中加入占位符来匹配客户端信息,例如 t/%c 则在匹配时主题将会替换为当前客户端的 Client ID
%u:用户名
%c:Client ID
4.1.2 超级用户 SQL(super_query)
进行 ACL 鉴权时,EMQX 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,查询客户端是否为超级用户。客户端为超级用户时将跳过 ACL SQL。
在etc/plugins/emqx_auth_mysql.conf配置中做如下修改
你可以在 SQL 中使用以下占位符,执行时 EMQX 将自动填充为客户端信息:
%u:用户名
%c:Client ID
%C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
%d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整超级用户 SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下超级用户 SQL 需要满足以下条件:
(1)查询结果中必须包含 is_superuser 字段,is_superuser 应该显式的为 true;
(2)查询结果只能有一条,多条结果时只取第一条作为有效数据。
提示
如果不需要超级用户功能,注释并禁用该选项能有效提高效率
4.1.3 ACL SQL(acl_query)
进行 ACL 鉴权时,EMQX 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,如果没有启用超级用户 SQL 或客户端不是超级用户,则使用 ACL SQL 查询出该客户端在数据库中的 ACL 规则。
在etc/plugins/emqx_auth_mysql.conf配置中做如下修改
你可以在 ACL SQL 中使用以下占位符,执行时 EMQX 将自动填充为客户端信息:
%u:用户名
%c:Client ID
%C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
%d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整 ACL SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下 ACL SQL 需要满足以下条件:
查询结果中必须包含 allow、access、topic、clientid、username、ipaddr 字段,如果字段不想参与比对则使用 $all 字符串或者数据库 NULL 值
查询结果可以有多条,多条结果时按照从上到下的顺序进行匹配
提示
可以在 SQL 中调整查询条件、指定排序方式实现更高效率的查询。
4.2 ACL全局配置
修改etc/emqx.conf 中的 ACL 配置
(1)acl_nomatch
ACL 未匹配时默认授权,deny拒绝授权
(2)acl_file
配置默认 ACL 文件,使用文件定义默认 ACL 规则
(3)acl_deny_action
配置 ACL 授权结果为禁止的响应动作,为 disconnect 时将断开设备
(4)enable_acl_cache
ACL 缓存开关
(5)acl_cache_max_size
单个客户端最大缓存规则数量
(6)acl_cache_ttl
缓存失效时间,超时后缓存将被清除
ACL 缓存允许客户端在命中某条 ACL 规则后,便将其缓存至内存中,以便下次直接使用,客户端发布、订阅频率较高的情况下开启 ACL 缓存可以提高 ACL 检查性能。
4.3 内置ACL配置
通过etc/acl.conf文件配置ACL内置规则
内置 ACL 优先级最低,可以被 ACL 插件覆盖,如需禁用全部注释即可。规则文件更改后需重启 EMQX 以应用生效。
内置 ACL 是优先级最低规则表,在所有的 ACL 检查完成后,如果仍然未命中则检查默认的 ACL 规则。
本文在此配置几条ACL默认规则
(1)允许 "dashboard" 用户 订阅 "$SYS/#" 主题
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
(2) 允许 IP 地址为 "127.0.0.1" 的用户 发布/订阅 "$SYS/#","#" 主题
{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
(3)拒绝 "所有用户" 订阅 "$SYS/#" "#" 主题
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
acl.conf具体编写规则请参考官方文档
内置 ACL | EMQX 4.4 文档
将每个节点上述配置修改完毕后重启后生效
重启EMQX节点命令
./bin/emqx restart
4.4 ACL功能验证
使用EMQX Dashboard Websocket工具可以进行简单验证,开启topic发布订阅ACL后,必须在mqtt_acl表中为用户配置topic权限后,用户才可以发布或订阅该topic。
如下图,为test用户赋予test-topic主题的发布订阅权限
使用Websocket工具进行验证:
(1)首先使用test用户连接服务端
(2)连接服务端后尝试订阅其他未授权主题会显示订阅失败,只能订阅test-topic,订阅成功后可以在订阅模块显示订阅信息
(3)向已授权的指定topic发送信息
(4)向未授权的topic发送消息
向未授权的topic发送消息时在websocket工具界面仍会显示消息已发出,但可以在emqx日志查看到不能向未授权的topic发送消息。
5 EMQX系统优化
5.1 Linux 操作系统参数
1 系统全局允许分配的最大文件句柄数:
<code># 2 millions system-wide
sysctl -w fs.file-max=2097152
sysctl -w fs.nr_open=2097152
echo 2097152 > /proc/sys/fs/nr_open
2 允许当前会话 / 进程打开文件句柄数:
ulimit -n 1048576
3 /etc/sysctl.conf
持久化 'fs.file-max' 设置到 /etc/sysctl.conf 文件:
fs.file-max = 1048576
4 /etc/systemd/system.conf 设置服务最大文件句柄数
DefaultLimitNOFILE=1048576
5 /etc/security/limits.conf
/etc/security/limits.conf 持久化设置允许用户 / 进程打开文件句柄数:
* soft nofile 1048576
* hard nofile 1048576
5.2 TCP 协议栈网络参数
1 并发连接 backlog 设置:
sysctl -w net.core.somaxconn=32768
sysctl -w net.ipv4.tcp_max_syn_backlog=16384
sysctl -w net.core.netdev_max_backlog=16384
2 可用知名端口范围:
sysctl -w net.ipv4.ip_local_port_range='1000 65535'code>
3 TCP Socket 读写 Buffer 设置:
sysctl -w net.core.rmem_default=262144
sysctl -w net.core.wmem_default=262144
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.core.optmem_max=16777216
sysctl -w net.ipv4.tcp_rmem='1024 4096 16777216'code>
sysctl -w net.ipv4.tcp_wmem='1024 4096 16777216'code>
4 TCP 连接追踪设置:
sysctl -w net.netfilter.nf_conntrack_max=1000000
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
5 TIME-WAIT Socket 最大数量、回收与重用设置:
sysctl -w net.ipv4.tcp_max_tw_buckets=1048576
6 FIN-WAIT-2 Socket 超时设置:
sysctl -w net.ipv4.tcp_fin_timeout=15
5.3 Erlang 虚拟机参数
优化设置 Erlang 虚拟机启动参数,配置文件 emqx/etc/emqx.conf:
## Erlang Process Limit
node.process_limit = 2097152
## Sets the maximum number of simultaneously existing ports for this system
node.max_ports = 1048576
5.4 EMQX 消息服务器参数
ceptor 池大小,最大允许连接数。 emqx/etc/emqx.conf
## TCP Listener
listener.tcp.external = 0.0.0.0:1883
listener.tcp.external.acceptors = 64
listener.tcp.external.max_connections = 1024000
注意:EMQX节点参数的配置需要重启节点后生效
6 附录
6.1 openssl生成证书
6.1.1 生成自签名 CA 证书
首先,我们需要一个自签名的 CA 证书。生成这个证书需要有一个私钥为它签名,可以执行以下命令来生成私钥:
openssl genrsa -out ca.key 2048
这个命令将生成一个密钥长度为 2048 的密钥并保存在 ca.key 中。有了这个密钥,就可以用它来生成 EMQX 的根证书了:
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem
根证书是整个信任链的起点,如果一个证书的每一级签发者向上一直到根证书都是可信的,那个我们就可以认为这个证书也是可信的。有了这个根证书,我们就可以用它来给其他实体签发实体证书了。
6.1.2 生成服务端证书
实体(在这里指的是 EMQX)也需要一个自己的私钥对来保证它对自己证书的控制权。生成这个密钥的过程和上面类似:
openssl genrsa -out emqx.key 2048
新建 openssl.cnf 文件,
req_distinguished_name :根据情况进行修改,
alt_names: BROKER_ADDRESS 修改为 EMQX 服务器实际的 IP 或 DNS 地址,例如:IP.1 = 127.0.0.1,或 DNS.1 = broker.xxx.com
注意:IP 和 DNS 二者保留其一即可,如果已购买域名,只需保留 DNS 并修改为你所使用的域名地址。
[req]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
countryName = CN
stateOrProvinceName = Zhejiang
localityName = Hangzhou
organizationName = EMQX
commonName = CA
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = BROKER_ADDRESS
DNS.1 = BROKER_ADDRESS
然后以这个密钥和配置签发一个证书请求:
openssl req -new -key ./emqx.key -config openssl.cnf -out emqx.csr
然后以根证书来签发 EMQX 的实体证书:
openssl x509 -req -in ./emqx.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out emqx.pem -days 3650 -sha256 -extensions v3_req -extfile openssl.cnf
6.1.3 生成客户端证书
双向连接认证还需要创建客户端证书,首先需要创建客户端密钥:
openssl genrsa -out client.key 2048
使用生成的客户端密钥来创建一个客户端请求文件:
openssl req -new -key client.key -out client.csr -subj "/C=CN/ST=Zhejiang/L=Hangzhou/O=EMQX/CN=client"
最后使用先前生成好的服务端 CA 证书来给客户端签名,生成一个客户端证书:
openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem
准备好服务端和客户端证书后,我们就可以在 EMQX 中启用 TLS/SSL 双向认证功能。
上一篇: Ubuntu20.04(64位)下搭建arm-gcc交叉编译环境
下一篇: Minecraft 1.20.1 Forge服务器保姆级搭建教程 (使用mcsm面板 | 两种启动方式)
本文标签
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。