环境
服务器配置:
- ubuntu 18.04 16核32G
ZLMediaKit版本
- git hash:f69f3b302971edb539fa256c514c0678af6c3169
- branch:master
- build time:2023-09-22T23:17:20
测试协议
- flv、rtmp
压力测试工具
- test_bench_pull (zlm自带)
带宽测试工具
ifstat
本地电脑推流或ffmpeg转推摄像头的流,我选择第二种,比较符合实际的场景
rtmp推流桌面流,这种方式码率不稳定:
ffmpeg -f gdigrab -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f flv -s 1280x720 -q 10
rtmp://1.14.58.180:1935/live/test 转推摄像头的流,摄像头的带宽稳定2M,跟实际场景比较符合 ffmpeg -rtsp_transport tcp -i rtsp://xxx/xxx -c:v copy -c:a copy -f flv rtmp://1.14.58.180:1935/live/test
test_player
./test_player rtmp://1.14.58.180:1935/live/test
./test_player http://1.14.58.180/live/test.live.flv
ZLM的配置
; auto-generated by mINI class {
[api]
apiDebug=1
defaultSnap=./www/logo.png
secret=bmHZUf11Q46LLnX781d26LPqyzx91bfMr3
snapRoot=./www/snap/
[cluster]
origin_url=
retry_count=3
timeout_sec=15
[ffmpeg]
bin=/usr/bin/ffmpeg
cmd=%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s
log=./ffmpeg/ffmpeg.log
restart_sec=0
snap=%s -i %s -y -f mjpeg -frames:v 1 %s
[general]
check_nvidia_dev=1
enableVhost=0
enable_ffmpeg_log=0
flowThreshold=1024
maxStreamWaitMS=15000
mediaServerId=your_server_id
mergeWriteMS=300
resetWhenRePlay=1
streamNoneReaderDelayMS=20000
unready_frame_cache=100
wait_add_track_ms=3000
wait_track_ready_ms=10000
[hls]
broadcastRecordTs=0
deleteDelaySec=10
fileBufSize=65536
segDur=2
segKeep=0
segNum=3
segRetain=5
[hook]
alive_interval=10.0
enable=0
on_flow_report=https://127.0.0.1/index/hook/on_flow_report
on_http_access=https://127.0.0.1/index/hook/on_http_access
on_play=https://127.0.0.1/index/hook/on_play
on_publish=https://127.0.0.1/index/hook/on_publish
on_record_mp4=https://127.0.0.1/index/hook/on_record_mp4
on_record_ts=https://127.0.0.1/index/hook/on_record_ts
on_rtp_server_timeout=https://127.0.0.1/index/hook/on_rtp_server_timeout
on_rtsp_auth=https://127.0.0.1/index/hook/on_rtsp_auth
on_rtsp_realm=https://127.0.0.1/index/hook/on_rtsp_realm
on_send_rtp_stopped=https://127.0.0.1/index/hook/on_send_rtp_stopped
on_server_exited=https://127.0.0.1/index/hook/on_server_exited
on_server_keepalive=https://127.0.0.1/index/hook/on_server_keepalive
on_server_started=https://127.0.0.1/index/hook/on_server_started
on_shell_login=https://127.0.0.1/index/hook/on_shell_login
on_stream_changed=https://127.0.0.1/index/hook/on_stream_changed
on_stream_none_reader=https://127.0.0.1/index/hook/on_stream_none_reader
on_stream_not_found=https://127.0.0.1/index/hook/on_stream_not_found
retry=1
retry_delay=3.0
stream_changed_schemas=rtsp/rtmp/fmp4/ts/hls/hls.fmp4
timeoutSec=10
[http]
allow_cross_domains=1
allow_ip_range=
charSet=utf-8
dirMenu=1
forbidCacheSuffix=
forwarded_ip_header=
keepAliveSecond=30
maxReqSize=40960
notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>您访问的资源不存在!</h1></center><hr><center>ZLMediaKit(git hash:f69f3b3/%aI,branch:master,build time:2023-09-22T23:17:20)</center></body></html>
port=80
rootPath=./www
sendBufSize=65536
sslport=443
virtualPath=
[multicast]
addrMax=239.255.255.255
addrMin=239.0.0.0
udpTTL=64
[protocol]
add_mute_audio=1
auto_close=0
continue_push_ms=15000
enable_audio=1
enable_fmp4=0
enable_hls=0
enable_hls_fmp4=0
enable_mp4=0
enable_rtmp=1
enable_rtsp=1
enable_ts=0
fmp4_demand=0
hls_demand=0
hls_save_path=./www
modify_stamp=2
mp4_as_player=0
mp4_max_second=3600
mp4_save_path=./www
rtmp_demand=0
rtsp_demand=0
ts_demand=0
[record]
appName=record
fastStart=0
fileBufSize=65536
fileRepeat=0
sampleMS=500
[rtc]
externIP=
port=8000
preferredCodecA=PCMU,PCMA,opus,mpeg4-generic
preferredCodecV=H264,H265,AV1,VP9,VP8
rembBitRate=0
tcpPort=8000
timeoutSec=15
[rtmp]
handshakeSecond=15
keepAliveSecond=15
port=1935
sslport=0
[rtp]
audioMtuSize=600
h264_stap_a=1
lowLatency=0
rtpMaxSize=10
videoMtuSize=1400
[rtp_proxy]
dumpDir=
gop_cache=1
h264_pt=98
h265_pt=99
opus_pt=100
port=10000
port_range=1-65535
ps_pt=96
timeoutSec=15
[rtsp]
authBasic=0
directProxy=1
handshakeSecond=15
keepAliveSecond=15
lowLatency=0
port=554
rtpTransportType=-1
sslport=0
[shell]
maxReqSize=1024
port=0
[srt]
latencyMul=4
pktBufSize=8192
port=9000
timeoutSec=5
; } ---
以上配置,我将随机端口范围改成1-65535,随机端口最大为65535
这里服务+客户端在同一台,所以可用的端口实际最多是30000多一点,而我实际上测试在28000+个播放器时,端口就不够用了
1000个播放器
-
性能
CPU | 内存 | |
MediaServer | 16% (峰值) | 0.1% |
test_bench_pull | 7.3%(峰值) | 0.5% |
-
带宽
eth0网卡为1路推流的带宽,本地回环的带宽是开启1000路播放器的带宽
可以看出平均带宽大概是2000M,而摄像头推流的带宽是2M。
在本地回环中,随机选一个KB/s out的值,如242044.4这个值,计算公式如下:
242044.4 X 8 ÷ 1000 = 1936.3552 Mbps
所以1000路所需要的带宽是2000Mbps
-
延时
我这边手机拍照的场景是:
摄像头对准一台电脑的屏幕,在这台电脑上开启秒表,然后另一台电脑用向日葵远程到这台电脑
然后在拿一个电脑,我这里是rk3588,使用test_player分别播放flv流和rtmp流,延时情况如图所示
5000个播放器
-
性能
CPU | 内存 | |
MediaServer | 81% (峰值) | 0.2% |
test_bench_pull | 33.3%(峰值) | 2.4% |
-
带宽
可以看出平均带宽大概是10000M,而摄像头推流的带宽是2M
拿1.37e+06来算,带宽就是10960Mbps
-
延时
5000路播放的情况下,延时没有增加
10000个播放器
-
性能
CPU | 内存 | |
MediaServer | 149% (峰值) | 0.3% |
test_bench_pull | 67.3%(峰值) | 4.8% |
-
带宽
本地回环网络吞吐量刚好是5000个播放器的两倍,按比较均值的2.50e+06这个值算,就是20000Mbps
-
延时
20000个播放器
-
性能
CPU
内存
MediaServer
420% (峰值)
1.3%
test_bench_pull
148.5%(峰值)
9.6%
-
带宽
差不多吞吐量是10000个播放器的两倍,没啥问题
-
延时
28000个播放器
-
性能
CPU | 内存 | |
MediaServer | 560% (峰值) | 1.6% |
test_bench_pull | 215.3%(峰值) | 8.8% |
-
带宽
-
延时
内存带宽跟20000个播放器时的量是差不多的
1、说明内存带宽在20000个以后的某个点之后,到达极限
2、zlm负债比较高,现场出线延时,通过/index/api/getThreadsLoad这个接口,查看到线程延迟已经不正常了,高的时候延迟到200多
{
"code" : 0,
"data" :
[
{
"delay" : 142,
"load" : 59
},
{
"delay" : 17,
"load" : 9
},
{
"delay" : 23,
"load" : 6
},
{
"delay" : 18,
"load" : 7
},
{
"delay" : 18,
"load" : 5
},
{
"delay" : 22,
"load" : 4
},
{
"delay" : 21,
"load" : 7
},
{
"delay" : 20,
"load" : 5
},
{
"delay" : 2,
"load" : 11
},
{
"delay" : 5,
"load" : 8
},
{
"delay" : 11,
"load" : 5
},
{
"delay" : 7,
"load" : 4
},
{
"delay" : 3,
"load" : 7
},
{
"delay" : 6,
"load" : 7
},
{
"delay" : 12,
"load" : 6
},
{
"delay" : 17,
"load" : 7
}
]
}
此时,回过头看一下20000个播放器时,线程的负载,100多延时也是比较常见的,与28000的负载是差不多的
{
"code" : 0,
"data" :
[
{
"delay" : 129,
"load" : 66
},
{
"delay" : 2,
"load" : 19
},
{
"delay" : 3,
"load" : 20
},
{
"delay" : 1,
"load" : 24
},
{
"delay" : 12,
"load" : 18
},
{
"delay" : 21,
"load" : 32
},
{
"delay" : 13,
"load" : 18
},
{
"delay" : 2,
"load" : 19
},
{
"delay" : 0,
"load" : 19
},
{
"delay" : 1,
"load" : 19
},
{
"delay" : 1,
"load" : 19
},
{
"delay" : 1,
"load" : 19
},
{
"delay" : 0,
"load" : 19
},
{
"delay" : 0,
"load" : 19
},
{
"delay" : 0,
"load" : 20
},
{
"delay" : 0,
"load" : 21
}
]
}
总结:
-
MediaServer
1000个播放器 | 5000个播放器 | 10000个播放器 | 20000个播放器 | 28000个播放器 | |
CPU | 16% (峰值) | 81% (峰值) | 149% (峰值) | 420% (峰值) | 560% (峰值) |
内存 | 0.1% | 0.2% | 1.3% | 1.3% | 1.8% |
-
test_bench_pull
1000个播放器 | 5000个播放器 | 10000个播放器 | 20000个播放器 | 28000个播放器 | |
CPU | 7.3%(峰值) | 33.3%(峰值) | 67.3%(峰值) | 168% (峰值) | 215.3%(峰值) |
内存 | 0.5% | 2.4% | 4.8% | 9.6% | 8.8% |
28000个播放器已经快到单台的极限了,端口原因,跑着一起双倍端口。如果有很大的内网带宽支持的话,可以分开跑MediaServer和test_bench_pull,将端口和带宽跑满。
条件比较苛刻,我做不到,我这台服务器内网带宽最大是7GB,一小时2.3 RMB左右。如果有必要的话大家可去去租两台内网带宽特别高的服务器,然后分开跑这两个程序。可以租高IO型的服务器,看下是否是内存带宽达到极限导致的延时。