公司业务访问量大,因此需要对后端emq服务器进行性能调优,在前端配置,以提高服务的健壮性。同时,由于mqtts传输方式中加解密的操作较占资源,所以需要把这部分操作让nginx服务器完成,让后端通信均为mqtt方式,减少服务器压力。

本文所有配置基于nginx-plus R17版本。

nginx的安装和简单配置参考其他网页。

  1. SSL Termination,翻译中文大概意思为ssl卸载(?),目的就是要在nginx端进行加解密操作。首先需要在emq的安装目录使用OpenSSL生成证书。以下为测试时使用的nginx配置文件,由于mqtt协议属于TCP/UDP协议集,因此使用stream模块。配置上游服务器188和190,监听mqtt协议的1883端口。nginx监听9993的加密协议端口,使用ssl_certificate命令指定证书路径(必须PEM格式),使用ssl_certificate_key指定私钥地址,此外,ssl_protocols和ssl_ciphers指令可用于限制连接,并仅包含SSL / TLS的强版本和密码。
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log debug;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

# TCP/UDP proxy and load balancing block
#
stream {
    upstream mqtt_cluster {
      server 192.168.100.188:1883;
      server 192.168.100.190:1883;
    }

    server {
        listen 9993 ssl;
        proxy_pass mqtt_cluster;
        
        ssl_certificate /etc/ssl/certs/cert.crt;
        ssl_certificate_key /etc/ssl/certs/key.key;
        ssl_protocols TLSv1 TLSV1.1 TLSv1.2;
        ssl_session_cache     shared:SSL:10m;
        ssl_session_timeout   10m;
        
    }
}

以上配置已经可以实现在nginx端进行mqtts的ssl加解密操作。测试时使用一个加密的pub端发送消息,一个加密的sub端,一个不加密的sub端接收消息。结果不论加密或不加密的sub端都可以收到消息。

  1. 负载均衡。是通过upstream模块来实现的,内置实现了五种负载策略,分别是轮询、最少连接、最少时间(仅nginxPlus支持)、hash和random。由于业务需求,负载均衡的同时必须保证用户进行订阅时,同一个clientID必须始终是同一台服务器进行处理,除非该服务器宕机不可用,即要保证会话持久性。所以使用hash算法配置负载均衡。使用的配置文件在上文的基础上添加了一行hash 192.168.100.187 consistent;,即从187这个ip发送的mqtt消息始终有同一个上游服务器处理,但这种方式并不符合业务需求,因为无法在配置文件中写出所有客户的IP。因此需要通过mqtt客户端的唯一标识clientID来做hash算法,但由于时间关系没有深入研究,在此记录github项目连接以便空闲的时候继续。
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log debug;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

# TCP/UDP proxy and load balancing block
#
stream {
    upstream mqtt_cluster {
    hash 192.168.100.187 consistent;
    server 192.168.100.188:1883;
    server 192.168.100.190:1883;
    }

    server {
        listen 9993 ssl;
        proxy_pass mqtt_cluster;
        
        ssl_certificate /etc/ssl/certs/cert.crt;
        ssl_certificate_key /etc/ssl/certs/key.key;
        ssl_protocols TLSv1 TLSV1.1 TLSv1.2;
        ssl_session_cache     shared:SSL:10m;
        ssl_session_timeout   10m;
        
    }
}