跳到主要内容
版本:2.1.x

测试报告

测试目的

BifroMQ Standard模式开始支持集群部署,集群在不同使用场景及配置下的性能表现差异性较大。

本报告目的是为了给出BifroMQ在标准集群模式部署下,各常见使用场景的性能指标及结果分析,为使用者提供集群部署、规格评估、参数配置等方面的参考。

测试环境

发压工具

基于vertx-mqtt开发的测试工具,具有较灵活的使用方式及优良的性能表现,后续会一并开源。

部署机规格

BifroMQ部署机:CentOS release 7.6, 32核, 128G内存(实际配置JVM内存40G) 发压机:CentOS release 7.6, 16核, 128G内存(实际配置JVM内存32G)

集群构建配置及步骤

BifroMQ内置了消息路由及持久化消息的存储引擎,属于有状态服务,因此初次构建集群时需要按照一定的顺序进行。

下面以三节点部署为例进行介绍。

node1: 192.168.0.11

node2: 192.168.0.12

Node3: 192.168.0.13

修改conf文件夹下的standalone.yml

node1最简配置:

bootstrap: true

mqttServerConfig:
tcpListener:
port: 1883

clusterConfig:
env: Test
host:
port: 8899
clusterDomainName:
seedEndpoints: 192.168.0.11:8899,192.168.0.12:8899,192.168.0.13:8899

node2 & node3最简配置:

bootstrap: false

mqttServerConfig:
tcpListener:
port: 1883

clusterConfig:
env: Test
host:
port: 8899
clusterDomainName:
seedEndpoints: 192.168.0.11:8899,192.168.0.12:8899,192.168.0.13:8899

按顺序依次启动node1、node2、node3即可。

注:整个集群生命周期中,仅第一次启动第一个节点时需要将bootstrap置为true,以进行持久化存储元数据的初始化,后续无需再关注此配置及启动顺序。

测试说明

场景介绍

测试维度介绍:

  • cleanSession:true | false,对应MQTT协议中连接时的Clean Session标志位,false代表支持离线订阅及消息存储。
  • Pub & Sub比例
    • 1对1:表示每个pub客户端的消息只由一个sub客户端接收。
    • 共享订阅:表示较多个pub客户端的消息,由n个sub客户端共同分享,每个客户端接收 1/n 份消息。
    • fan-out订阅:表示一个pub客户端的消息,由较多数量sub客户端接收,类似于广播。
  • QoS:0 | 1,pub消息与sub订阅采取同样的消息等级。
  • payload大小:每条测试消息的大小,单位byte。
  • 单连接消息频率:低频指每个pub连接每秒发送一条消息,高频指每个pub连接每秒发送50 ~ 100条消息。

各个场景的测试由以上维度组合而来。

注:默认单个连接的每秒进出口带宽为512KB/s,超出带宽限制会引起消息的延迟。此限制主要用作系统保护而并非性能瓶颈,可以通过启动时的配置参数进行修改。

cleanSession=true与false

BifroMQ对MQTT协议进行了完整的支持,尤其是保留会话方面。服务端会持久化所有客户端的订阅信息、cleanSession=false的客户端在线及离线时的所有QoS级别的消息,因此对于cleanSession=true和false的连接及消息的处理方式有很大区别。

BifroMQ采取了基于磁盘而非内存的持久化策略,在宕机或重启时不会丢失数据,在集群模式下可以根据需要配置持久化数据的副本数量,进一步的提高数据的高可用性。

基于以上设计,cleanSession=false连接使用时的资源消耗与true相比较重,且在离线后仍会占用一定的系统资源。因此相同部署规格下true和false能达到的性能指标会存在较大的差异,需要根据实际需求情况合理选取。

注:BifroMQ的离线持久化设计是为了保证服务SLA而非作为存储引擎使用,因此需要避免反协议的非常规使用方式。例如在cleanSession=false的模式下,每次连接使用不同的clientId,这样既无法真正利用到离线持久化的能力,又会造成脏数据给系统带来额外的负载。

持久化消息性能影响因素

BifroMQ在集群化部署时,存储引擎也同样会组成分布式集群,BifroMQ的存储引擎是基于RAFT协议的多副本架构,同时支持多分片。

每个BifroMQ实例内部有三个独立的存储引擎,分别负责订阅信息、cleanSession=false连接消息、retain消息的存储,每个存储引擎可以分别进行配置。其中对于cleanSession=false连接的消息收发来说,分片数及副本数对性能均会有较大的影响。

持久化消息存储引擎的副本数可以通过启动时附带系统变量(inbox_store_replica_voter_count,详见配置手册)进行配置,默认为1。若要保持高可用,副本数需要大于等于3。

注:增加副本数会将写入的数据量放大N倍,因此消耗的系统资源及消息延迟都会随之增大。

存储引擎的多分片是基于Multi-RAFT协议实现的,每个分片及其副本组成一个RAFT复制集群,在未达到系统资源瓶颈之前,适当的增加分片数可以有效的提高存储引擎的写入及查询效率。

持久化消息存储引擎内置了基于负载的自动化分片策略,每个分片会根据当前读写负载及系统的繁忙情况决定是否进行分裂,一般无需额外进行配置。若对BifroMQ代码及分片原理有一定的研究了解,可通过在启动时附带以下系统变量进行调优:

  • inbox_store_io_nanos_limit:存储引擎IO延迟限制,默认30,000纳秒,内部读写延迟超过此值后暂停分裂。

  • inbox_store_max_io_density:存储引擎IO负责情况,若当前分片的实时负载统计超过此限制则开始规划分片。

分片策略采用插件化机制进行加载并配置生效,对于深度使用用户来说,可以自行开发适合自身使用场景的分片策略。

测试报告

参数说明

场景名称由测试用例中各维度参数组合而来,例如30k_30k_qos1_p256_1mps_3n_3v表示:

  • 30,000个Pub MQTT client

  • 30,000个Sub MQTT client

  • 消息及订阅质量使用QoS1

  • 单个消息payload大小256 bytes

  • 单个Pub client每秒发送1条message至BifroMQ,并转发至Sub client

  • 3n表示部署三个BifroMQ节点

  • 3v表示持久化引擎中的数据为三副本存储,主要影响cleanSession=false场景

结果分析及说明

  1. cleanSession=true高频场景单节点消息总吞吐(pub客户端发送消息与sub客户端接收消息之和)可达40W/s以上,三节点部署消息吞吐可达100W/s以上;低频场景单节点消息吞吐最高可达20W/s以上,三节点部署消息吞吐可达60W/s以上;吞吐量可以随节点数进行水平扩展。 注:低频场景达到预设吞吐值时,需要维持的连接数较多,会消耗更多的服务资源,因此与高频发送场景相比能够达成的吞吐上限会有所降低。

  2. cleanSession=true的共享订阅及fanOut能力可以随着节点数进行水平扩展。

  3. cleanSession=false高频场景单节点消息吞吐可达3W/s以上,三节点单副本部署消息吞吐可达9W/s以上;低频场景单节点消息吞吐可达2W/s以上,三节点单副本部署消息吞吐可达6W/s以上;基本达到水平扩展的效果。

  4. cleanSession=false在三节点三副本部署的情况下,高频及低频场景消息吞吐均可达3W/s以上,与单节点单副本部署场景类似。原因是三副本部署时会将持久化消息写入的负载放大三倍,因此三节点处理三倍负载与单节点单副本能支撑的性能类似。若要对多副本部署的cleanSession=false消息吞吐能力进行拓展,可根据以上规律进行大致计算,得出合适的节点数及副本数部署集。

  5. 系统吞吐及时延指标会受消息及订阅QoS质量影响,相同的测试载荷下,QoS1场景比QoS0场景消耗更多的系统资源略,消息延迟稍也会有所增加,增加量为毫秒量级,且尽在较高吞吐及系统负载的情况下,才会表现出可观测到的区别。

  6. cleanSession=false与cleanSession=true场景的性能结果存在数倍的差距。原因是BifroMQ的架构是为构建serverless云服务而设计的,离线消息的可靠性是云服务SLA的重要指标,因此BifroMQ选择了基于磁盘而非内存的持久化策略,在宕机或重启时不会丢失数据。存储引擎性能受到当前测试机器本地磁盘 IO 性能的限制,采用高性能磁盘替换,或在集群环境下搭配合适的负载策略,都可以有效提升性能。

  7. 结果附图的p99及max视图中会有偶发的毛刺,与测试发压端的实现有关(Java GC)。

  8. BifroMQ内部消息链路采用全异步实现,能够充分的利用CPU多核的能力。此报告所列测试场景属于压力测试,已经将系统负载使用时较高水平,因此消息时延指标会有所增大,BifroMQ在无压力下的消息时延可以控制在1ms左右。同时在更高可用CPU核数的运行环境中,BifroMQ可以达到比报告中更高的吞吐及时延指标。

cleanSession=true

高频场景

场景组合QoS单连接m/s消息byte连接数C总消息m/s平均响应时间msP99响应时间msCPU内存占用GB
2k_2k_qos0_p32_100mps_1n0100324k200k3.2224.1180%5 ~ 10
2k_2k_qos1_p32_100mps_1n1100324k200k38.92184.5485%5 ~ 15
5k_5k_qos0_p32_100mps_3n01003210k500k3.3824.1183%5 ~ 20
4k_4k_qos1_p32_100mps_3n1100328k400k9.6265.085%5 ~ 18

2k_2k_qos0_p32_100mps_1n场景附图:

qpsmean
p99max
cpumem

2k_2k_qos1_p32_100mps_1n场景附图:

qpsmean
p99max
cpumem

5k_5k_qos0_p32_100mps_3n场景附图:

qpsmean
p99max
cpumem

4k_4k_qos1_p32_100mps_3n场景附图:

qpsmean
p99max
cpumem

低频场景

场景组合QoS单连接m/s消息byte连接数C总消息m/s平均响应时间msP99响应时间msCPU内存占用GB
100k_100k_qos0_p256_1mps_1n01256200k100k2.1417.8280%6 ~ 12
100k_100k_qos1_p256_1mps_1n11256200k100k13.56104.8483%8 ~ 13
300k_300k_qos0_p256_1mps_3n01256600k300k17.03113.2383%10 ~ 20
200k_200k_qos1_p256_1mps_3n11256400k200k3.8629.3481%7 ~ 12

100k_100k_qos0_p256_1mps_1n场景附图:

qpsmean
p99max
cpumem

100k_100k_qos1_p256_1mps_1n场景附图:

qpsmean
p99max
cpumem

300k_300k_qos0_p256_1mps_3n场景附图:

qpsmean
p99max
cpumem

共享订阅场景

场景组合QoS单连接m/s消息byte连接数C总消息m/s平均响应时间msP99响应时间msCPU内存占用GB
100k_1000_qos0_p256_1mps_1n01256101k100k1.1711.082%6 ~ 20
100k_1000_qos1_p256_1mps_1n11256101k100k1.8214.6778%5 ~ 18
300k_3000_qos0_p256_1mps_3n01256303k300k3.1719.9180%10 ~ 20
200k_2000_qos1_p256_1mps_3n11256202k200k5.943.8477%5 ~ 20

100k_1000_qos0_p256_1mps_1n场景附图:

qpsmean
p99max
cpumem

100k_1000_qos1_p256_1mps_1n场景附图:

qpsmean
p99max
cpumem

300k_3000_qos0_p256_1mps_3n场景附图:

qpsmean
p99max
cpumem

200k_2000_qos1_p256_1mps_3n场景附图:

qpsmean
p99max
cpumem

fanOut场景

少量客户端作为Publisher,大量客户端订阅相同的topic作为Subscriber,形成每条消息被大规模fanOut广播的场景。

场景组合QoS单连接m/s消息byte连接数C总消息m/s平均响应时间msP99响应时间msCPU内存占用GB
1_100000_qos0_p256_1mps_1n01256100k100k282.61465.5715%2 ~ 5
1_100000_qos1_p256_1mps_1n11256100k100k312.11515.920%2 ~ 7
1_300000_qos0_p256_1mps_3n01256300k300k593.23889.1920%2 ~ 10
1_200000_qos1_p256_1mps_3n11256200k200k395.96595.5912%2~ 8

1_100000_qos0_p256_1mps_1n场景附图:

qpsmean
p99max
cpumem

1_100000_qos1_p256_1mps_1n场景附图:

qpsmean
p99max
cpumem

1_300000_qos0_p256_1mps_3n场景附图:

qpsmean
p99max
cpumem

1_200000_qos1_p256_1mps_3n场景附图:

qpsmean
p99max
cpumem

cleanSession=false

1对1 低频场景

场景组合QoS单连接m/sPayload (byte)连接数C总消息m/s平均响应时间msP99响应时间msCPU内存占用GB
15k_15k_qos0_p256_1mps_1n_1v0125620k15k10.2452.465%5~15
15k_15k_qos1_p256_1mps_1n_1v1125620k15k13.6467.0870%5~18
30k_30k_qos0_p256_1mps_3n_1v0125660k30k70.34285.1860%5~20
30k_30k_qos1_p256_1mps_3n_1v1125660k30k90.2352.2962%7~20
15k_15k_qos0_p256_1mps_3n_3v0125630k15k27.32142.5465%5~20
15k_15k_qos1_p256_1mps_3n_3v1125630k15k31.01167.7165%5~20

15k_15k_qos0_p256_1mps_1n_1v场景附图:

qpsmean
p99max
cpumem

15k_15k_qos1_p256_1mps_1n_1v场景附图:

qpsmean
p99max
cpumem

30k_30k_qos0_p256_1mps_3n_1v场景附图:

qpsmean
p99max
cpumem

30k_30k_qos1_p256_1mps_3n_1v场景附图:

qpsmean
p99max
cpumem

15k_15k_qos0_p256_1mps_3n_3v场景附图:

qpsmean
p99max
cpumem

15k_15k_qos1_p256_1mps_3n_3v场景附图:

qpsmean
p99max
cpumem

1对1 高频场景

场景组合QoS单连接m/sPayload (byte)连接数C总消息m/s平均响应时间msP99响应时间msCPU内存占用GB
300_300_qos0_p32_50mps_1n_1v050320.6k15k14.3850.2770%3~15
300_300_qos1_p32_50mps_1n_1v150320.6k15k16.552.475%5~15
900_900_qos0_p32_50mps_3n_1v050321.8k45k82.36243.255%5~18
900_900_qos1_p32_50mps_3n_1v150321.8k45k95.74369.0365%5~20
300_300_qos0_p32_50mps_3n_3v050320.6k15k22.9175.4370%5~15
300_300_qos1_p32_50mps_3n_3v150320.6k15k26.9688.0170%5~15

300_300_qos0_p32_50mps_1n_1v场景附图:

qpsmean
p99max
cpumem

300_300_qos1_p32_50mps_1n_1v场景附图:

qpsmean
p99max
cpumem

900_900_qos0_p32_50mps_3n_1v场景附图:

qpsmean
p99max
cpumem

900_900_qos1_p32_50mps_3n_1v场景附图:

qpsmean
p99max
cpumem

300_300_qos0_p32_50mps_3n_3v场景附图:

qpsmean
p99max
cpumem

300_300_qos1_p32_50mps_3n_3v场景附图:

qpsmean
p99max
cpumem

冷启动场景

冷启动即集群启动后,直接开始以大压力开始cleansession=false的测试,此时集群内部存储引擎会先随着压力进行分片,达到合适的数目后,开始稳定工作。

场景组合QoS单连接m/sPayload (byte)连接数C总消息m/s
30k_30k_qos1_p256_1mps_3n_1v1125660k30k

冷启动场景附图:

qpsmean
p99max
cpumem

百万连接

此场景主要为了测试BifroMQ在承载大量连接时的资源消耗。

场景组合cleansession连接数建立连接速率cpu内存占用GB
conn-tcp-1M-5K_1n_truetrue1M5k30%7.2G
conn-tcp-1M-5K_1n_falsefalse1M5k40%13G

conn-tcp-1M-5K_1n_true场景附图:

conn

mem

cpu

conn-tcp-1M-5K_1n_false场景附图:

conn

mem

cpu

系统参数优化

以下Kernel参数会影响BifroMQ所在机器能接受的最大连接数

内存

  • vm.max_map_count: 限制一个进程可以拥有的VMA(虚拟内存区域)的数量, 可放大到221184

最大打开文件数

  • nofile: 指单进程的最大打开文件数
  • nr_open: 指单个进程可分配的最大文件数,通常默认值为1024*1024=1048576
  • file-max: 系统内核一共可以打开的最大值,默认值是185745

NetFilter调优

通过sysctl -a | grep conntrack查看当前的参数,以下几个参数决定了最大连接数:

  • net.netfilter.nf_conntrack_buckets: 记录连接条目的hashtable的bucket大小
    • 修改命令:echo 262144 > /sys/module/nf_conntrack/parameters/hashsize
  • net.netfilter.nf_conntrack_max: hashtable最大的条目数,一般为nf_conntrack_buckets * 4
  • net.nf_conntrack_max: 同net.netfilter.nf_conntrack_max
  • net.netfilter.nf_conntrack_tcp_timeout_fin_wait: 默认 120s -> 30s
  • net.netfilter.nf_conntrack_tcp_timeout_time_wait: 默认 120s -> 30s
  • net.netfilter.nf_conntrack_tcp_timeout_close_wait: 默认 60s -> 15s
  • net.netfilter.nf_conntrack_tcp_timeout_established: 默认 432000 秒(5天)-> 300s

以下sysctl参数会影响大压力下tcp channel性能表现

Server端及测试发压端TCP相关调优

推荐使用centos7环境进行部署及压力测试。

centos6环境需要进行系统参数调优:

  • net.core.wmem_max: 最大的TCP数据发送窗口大小(字节)
    • 修改命令:echo 'net.core.wmem_max=16777216' >> /etc/sysctl.conf
  • net.core.wmem_default: 默认的TCP数据发送窗口大小(字节)
    • 修改命令:echo 'net.core.wmem_default=262144' >> /etc/sysctl.conf
  • net.core.rmem_max: 最大的TCP数据接收窗口大小(字节)
    • 修改命令:echo 'net.core.rmem_max=16777216' >> /etc/sysctl.conf
  • net.core.rmem_default: 默认的TCP数据接收窗口大小(字节)
    • 修改命令:echo 'net.core.rmem_default=262144' >> /etc/sysctl.conf
  • net.ipv4.tcp_rmem: socket接收缓冲区内存使用的下限 警戒值 上限
    • 修改命令:echo 'net.ipv4.tcp_rmem= 1024 4096 16777216' >> /etc/sysctl.conf
  • net.ipv4.tcp_rmem: socket发送缓冲区内存使用的下限 警戒值 上限
    • 修改命令:echo 'net.ipv4.tcp_wmem= 1024 4096 16777216' >> /etc/sysctl.conf
  • net.core.optmem_max: 每个socket所允许的最大缓冲区的大小 (字节)
    • 修改命令:echo 'net.core.optmem_max = 16777216' >> /etc/sysctl.conf
  • net.core.netdev_max_backlog: 网卡设备将请求放入队列的长度
    • 修改命令:echo 'net.core.netdev_max_backlog = 16384' >> /etc/sysctl.conf

修改完配置通过sysctl -p并重启服务器生效。