BlueXIII's Blog

热爱技术,持续学习

0%

Whisper自动语音识别

参考

官网

语义相似度比对

参考

Sentence Similarity

Feature Extraction

其它

压测目的

本次压测意在寻找性能拐点,评估最大处理能力,并不断摸索操作系统与应用的调优参数

压测方案

压测场景

模拟单灯控制器,建立TCP链接,发送登录报文。登录成功后,不间断的发送属性上报消息。

创建虚拟设备

编写简易的JUnit脚本,以便于批量创建删除设备

录入10万个设备,设备ID为: 000000000001~000000100000

编写设备模拟器

由于单灯控制器通过TCP私有协议与平台进行通信,且上报消息的内容不固定,所以很难使用JMeter等常规压测工具进行测试。

需要自行编写单灯控制器模拟器,做为压测客户端,使用VertX异步框架开发以提高并发性能。

服务器指标监控

部署Prometheus+Grafana,进行图形化监控,方便查询历史指标并找出瓶颈点

消息样例

  • 登录(42字节): 68230068000000002000002226130007500100020802034C4F43373930302D4331454C36313000A35116
  • 属性上报(58字节): 68330068010000001300000e0000002001011003112700010fce590000003b400000dd242a426400000000000000000000000014000000f01216

压测环境搭建

服务端配置

  • 1台普通台式机,配置为i7-7700 4核8线程/16G/256G/千兆LAN
  • 最小化部署,应用及中间件混合部署在同一台服务器

服务端组件清单

类别 名称 版本号
应用 bifrost-ui 1.0.0
应用 bifrost-app 1.0.0
中间件 redis 5.0.4
中间件 elasticsearch 6.8.11
中间件 kibana 6.8.11
中间件 postgres 11-alpine
JDK openjdk 1.8.0_382
监控 grafana 10.3.3
监控 prometheus 2.50.1
监控 nodeExporter 1.7.0

服务端地址信息

类别 地址 帐密
单灯TCP端口 10.90.22.200:1886
UI http://10.90.22.200:9000 admin/1qaz@WSX
Redis 10.90.22.200:6379 仅密码:bifrost!23
ES6 http://10.90.22.200:9200
Kibana http://10.90.22.200:5601
Postgres postgres://10.90.22.200:5432/bifrost postgres/bifrost!23
Grafana http://10.90.22.200:3000 admin/1qaz@WSX

压测客户端

  • 4台Ubuntu虚拟机,配置为:8C/16G/500G/千兆LAN(实际只用到2台)
  • Ulimit与内核参数的优化,与服务端保持一致
  • 部署自行编写的单灯控制器模拟器

启动参数(以1万并发,120秒为例):

1
java -jar catonelight-simulator-1.0.0-SNAPSHOT.jar --host=10.90.22.200 --port=1886 --start=1 --parallels=10000 --duration=120

压测详细记录

请参考11~12轮的结果即可,点击跳转至语雀在线表格:
https://tc-aiot.yuque.com/org-wiki-tc-aiot-ms6e4o/tabv3n/zug68i5yymut8vlg#CyG5

结果分析

  • 8核16G的单机配置下,极限吞吐量为95502 TPS,极限并发数约为80000个设备
  • 随着并发数的不断提升,TPS保待不变,响应时间成比例的增加。系统并未出现明显拐点。
  • 内存占用量平稳,6-8G,基本无变化,上下文切换保持在60K左右
  • 系统负载稳定保持在15左右(处理器为8核心),以上都是Reactor带来的收益
  • 日志IO对性能的影响比预想中大很多,需要最先调优,同时需要兼顾实用性,不能完全关闭。优化后的性能提升约15倍。
  • Docker方式和原生JDK方式,在参数相同的情况下,TPS会有较大差异,各有胜负,原因不明
  • 关闭TCP粘拆包处理,可获得约30%的性能提升
  • 关闭Reactor的DebugAgent后,可获得约40%的性能提升

参数调优

操作系统Ulimit

1
2
3
4
5
6
7
# Ulimit设置
cat <<EOF >> /etc/security/limits.conf
root soft nofile 1048576
root hard nofile 1048576
root soft stack 1048576
EOF
sysctl --system

操作系统内核参数(修改前)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
cat <<EOF >> /etc/sysctl.conf
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.core.netdev_max_backlog = 30000
net.core.somaxconn = 262144
net.ipv4.neigh.default.gc_stale_time=120
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce=2
net.ipv4.conf.all.arp_announce=2
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65535 16777216
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_sack = 0
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_no_metrics_save=1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
vm.swappiness = 0
kernel.sysrq=1
fs.file-max=1000000
#fs.file-nr=1000000
vm.overcommit_memory = 1
EOF
sysctl -p

操作系统内核参数(修改后)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
net.ipv4.tcp_max_tw_buckets=50000
net.ipv4.tcp_max_syn_backlog=262144
net.core.somaxconn=262144
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65535 16777216
net.ipv4.tcp_mem=786432 2097152 3145728
net.ipv4.ip_local_port_range=1024 65535
vm.swappiness=0
kernel.sysrq=1
#fs.file-nr=100096 0 1531742
fs.file-max=1048576
vm.overcommit_memory=1

TCP粘拆包脚本

1
2
3
4
5
6
7
8
parser.fixed(4)
.handler(function (buffer, parser) {
var len = buffer.getShortLE(1);
parser.fixed(len + 3).result(buffer);
})
.handler(function (buffer, parser) {
parser.result(buffer).complete();
});

默认情况下,可以不启用粘拆包,以获得30%以上的性能提升

日志优化

  • 开启Console日志+文件日志+设备ES日志
  • 并逐行调整日志级别,大部分置为INFO级,兼顾实用
  • 关闭Logback的ES日志(怀疑这部分程序有问题会产生阻塞,关闭后TPS提升20倍)

应用优化

  • 关闭Reactor调试模式 spring.reactor.debug-agent.enabled=false,可获得约40%的性能提升
  • 关闭平台链路跟踪 trace.enabled=false
  • 后续如有必要时,将单个TCP连接的接收队列长度由默认256调高到65535,以应对单一设备连续上报的场景。需要修改VertX代码。

JVM优化

1
2
3
4
5
6
java -Duser.language=zh -XX:+UseG1GC -server \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XX:-OmitStackTraceInFastThrow \
-Djava.security.egd=file:/dev/./urandom \
-jar bifrost-standalone.jar

hsweb-easy-orm

https://github.com/hs-web/hsweb-easy-orm
org.hswebframework:hsweb-easy-orm:4.1.2-SNAPSHOT

hsweb-framework

https://github.com/hs-web/hsweb-framework
org.hswebframework.web:4.0.17-SNAPSHOT

reactor-excel

https://github.com/hs-web/reactor-excel
org.hswebframework:reactor-excel:1.0.6-SNAPSHOT

https://github.com/jetlinks/jetlinks-core
org.jetlinks:jetlinks-core:1.2.2-SNAPSHOT

https://github.com/jetlinks/jetlinks-supports
org.jetlinks:jetlinks-supports:1.2.2-SNAPSHOT

rule-engine

https://github.com/jetlinks/rule-engine
org.jetlinks:rule-engine:1.2.2-SNAPSHOT

reactor-ql

https://github.com/jetlinks/reactor-ql
org.jetlinks:reactor-ql:1.0.17-SNAPSHOT

https://github.com/jetlinks/jetlinks-plugin
org.jetlinks.plugin:jetlinks-plugin:1.0.2-SNAPSHOT

https://github.com/jetlinks/jetlinks-community
org.jetlinks.community:jetlinks-community:2.2.0-SNAPSHOT

https://github.com/jetlinks/jetlinks-ui-vue

参考

异步转Reactor

原生方式部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 版本 5.1.4

# 启动
nohup sh bin/mqnamesrv &
nohup sh bin/mqbroker -n localhost:9876 &

# 关闭
sh bin/mqshutdown broker
sh bin/mqshutdown namesrv

# 验证
export NAMESRV_ADDR=10.10.51.4:9876
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

# dashboard
docker run -d --name rocketmq-dashboard -e "JAVA_OPTS=-Drocketmq.namesrv.addr=10.10.51.4:9876" -p 38080:8080 -t apacherocketmq/rocketmq-dashboard:latest

控制台

10.10.51.4:9876
http://10.10.51.4:38080

常用操作

1
sh bin/mqadmin updateTopic -c DefaultCluster -t TopicTest2 -n 10.10.51.4:9876

https://www.jaegertracing.io/
https://www.jaegertracing.io/docs/1.52/getting-started/

启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
docker run --rm --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-e COLLECTOR_OTLP_ENABLED=true \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:1.45

docker run --rm --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-e COLLECTOR_OTLP_ENABLED=true \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:1.52

endpoint

http://10.10.51.4:14250

Console

http://10.10.51.4:16686

参考

ffmpeg

gb28181-client

开发环境SRS

http://10.10.51.4:8180

rtmp://10.10.51.4/live/livestream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

docker run --name bifrost-srs \
-e TZ=Asia/Shanghai \
-e CANDIDATE=10.10.51.4 \
-p 1935:1935 \
-p 1985:1985 \
-p 8080:8080 \
-p 9000:9000 \
-p 9000:9000/udp \
-p 8000:8000/udp \
-p 58300:58300 \
-p 58300:58300/udp \
-p 5060:5060/udp \
-v ./srs.conf:/usr/local/srs/conf/srs.conf \
registry.cn-shenzhen.aliyuncs.com/jetlinks/srs:v4.0.56

SRS

https://github.com/ossrs/srs
https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started
https://ossrs.net/lts/zh-cn/docs/v6/doc/gb28181
https://github.com/ossrs/srs/blob/develop/trunk/conf/gb28181.conf

1
2
3
4
5
6
7
8
9
10
11
12

docker run --rm --name srs \
-e CANDIDATE=10.10.51.3 \
--network host \
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 ./objs/srs -c conf/gb28181.conf

# -v ./srs.conf:/usr/local/srs/conf/srs.conf \

http://10.10.51.3:8080

rtmp://10.10.51.3/live/obs
http://10.10.51.3:8080/live/obs.flv

zlmediakit

https://docs.zlmediakit.com/
https://github.com/ZLMediaKit/ZLMediaKit
https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B
https://github.com/ZLMediaKit/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81
https://notemi.cn/wvp---zlmedia-kit---mediaserverui-to-realize-streaming-playback-and-recording-of-camera-gb28181.html
http://dlgcy.com/gb28181-solution-zlmediakit-mediaserverui/

1
2
3
4
docker run -id -p 1935:1935 -p 8080:80 -p 8443:443 -p 8554:554 -p 10000:10000 -p 10000:10000/udp -p 8000:8000/udp -p 9000:9000/udp zlmediakit/zlmediakit:master

https://10.10.51.3:8080
https://10.10.51.3:8080/webassist/

livegbs

https://www.liveqing.com/docs/products/LiveGBS.html

学习路径

  • 响应式: Java8 -> Netty -> VertX -> Reactor -> WebFlux
  • 周边组件: r2dbc
  • 后端框架: hs-web、easy-orm
  • 其它: NIO/AIO/Reactor、IO多路复用

Java8

  • Java8 in Action

Netty

VertX

Reactor

WebFlux

HsWeb

r2dbc

其它工具

BlockHound

reactor-ql

其它参考文档

编程范式

参考文档

官网

源码

使用手册

企业版功能

后端开发

前端开发

协议开发


物模型

  • 属性 用于描述设备运行时的状态,分为可读写和只读属性,比如温度传感器所读取的环境温度或者是插座的开关状态
  • 方法 设备可被用户调用并执行的方法,包含输入参数和返回参数,前者用于方法执行时的参数,后者用于上报方法执行后的结果。方法分为异步和同步执行两种类型
  • 事件 用于定义设备运行过程中所产生的消息,包括“信息”、“告警”和“错误”三种类型

前端工程启动

1
2
yarn install --update-checksums
yarn dev

创建协议工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mvn dependency:get \
-DremoteRepositories=https://nexus.hsweb.me/content/groups/public \
-DgroupId=org.jetlinks.protocol \
-DartifactId=protocol-archetype \
-Dversion=1.0.0-SNAPSHOT \
&& \
mvn archetype:generate \
-DarchetypeGroupId=org.jetlinks.protocol \
-DarchetypeArtifactId=protocol-archetype \
-DarchetypeVersion=1.0.0-SNAPSHOT \
-DoutputDirectory=./ \
-DgroupId=com.telchina \
-DartifactId=jetlinks-tc-protocol \
-Dversion=1.0 \
-DarchetypeCatalog=local \
-DinteractiveMode=false

官网

参考

开发环境

1
2
3
4
5
6
7
8
9
10
11
12
13
# 安装erlang版本25
brew install erlang@25
# rebar3下载
wget https://s3.amazonaws.com/rebar3/rebar3 && chmod +x rebar3
# 新建一个简单app项目
$ rebar3 new app <projName>
# 新建一个多app项目
$ rebar3 new release <projName>
# 新建一个简单app项目
$ rebar3 new lib <projName>
# 新建一个rebar插件
$ rebar3 new plugin <projName>