随着互联网进入移动互联时代,公司的移动业务增多,推送服务的需求越来越大,公司自主研发了一套基于 Miop 协议的 push 服务。
MIOP (Message I/O Protocol) 协议是基于 TCP 的通信协议,用于手机端(C)与消息推送服务端(S)的通信。
MIOP 链接由设备端发起,且双方可以随时交换信息。
Push 服务依赖 Miop 协议,广泛应用于移动业务,用户量较大,且持续占用 Tcp 连接,应对百万级用户使用,需要验证服务承载能力,以及高并发情况下,验证服务的稳定性,以及数据准确性。
设备通过 Miop 协议发送 Bind 消息,建立链接通道。服务器通过 Bind 消息,判定客户端上线,同时保存状态到内存,实时同步在线状态到 redis。服务器进行注册心跳消息管理,处理心跳超时、上下线等事件,管理推送数据以及设备上报数据。
满足业务需求的前提下,验证单机可承受链接上限,并发链接上限(测试目标 100w 链接)。验证并发情况下,redis 降级机制处理是否正常。
针对长连做大规模并发,影响性能的因素较多。要更准确的分析各个环节对服务性能的影响,需要有足够的客户端资源进行加压测试。
服务端的部署尽可能与线上保持一致,在资源允许的情况下,服务器与数据库、客户端单独部署,防止资源争用影响测试结果。
本次压测之前,已经进行了一轮功能性压测验证,得出的结论就是:高并发情况下,redis 性能不会受到影响。由于资源的问题,本次测试服务端与 redis 集群共用一台服务器。
●服务端单机部署 push 服务 +redis 集群
●客户端使用 17 台物理机,通过修改服务器套接字配置 echo 1024 65535 > /proc/sys/net/ipv4/ip_local_port_range,保证客户端资源充足,每台客户端配置 6 万用户。
要进行长连压测,首先需要实现客户端的 miop 协议,同时要保证客户端性能因素不会影响测试结果。因此需要选择高性能的服务框架开发客户端工具,要快速的实现客户端功能,就需要依赖成熟的高性能框架,本次测试采用的是 c 语言实现的 wrk 工具。
Wrk 工具是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,通过多线程和事件模式,可以利用很小的线程,产生很大的负载。
研发人员在 wrk 工具中添加了 miop 协议的功能,通过指令启动长连,--latency 打印延迟直方图信息,-d 标识测试持续时长,-c 标识打开的连接数, –t 标识打开的线程数,-s 加入网络延时。
./wrk miop://$HOSTNAME:pk@serverIp:serverPort/ -t 12 -c 60000 --latency -d 120m --timeout 15 -s delay.lua
运行结束后,可快速统计,形成测试报告,分析连接建立的成功率,失败率,以及响应耗时等。
要达到 100 万长连的目标需要经历以下几个阶段,阶梯性进行压测,对比不同阶梯系统性能比对评估。
●测试指标分析:
客户端连接建立时长
客户端连接超时次数
客户端连接建立成功率
客户端生命周期完整性
Tcp 连接错误率、错误原因分析
客户端不同量级并发延时分布
服务端 TCP 连接增长趋势
服务端 CPU、内存使用率、磁盘读写耗时、网卡收发数量等
客户端注册心跳数据包丢弃率
服务端内存溢出情况
服务端事件处理能力、异常处理能力
Redis 同步延时、数据状态一致性
服务端异常处理能力、容错处理机制等
●第一阶段,链接上限测试:
逐步提升在线客户端数量,每启动 6 万连接,观察内存在线数量。依次启动 17 个客户端,观察连接增长速度,验证服务器的链接上限,同时观察系统性能指标是否达到饱和。随着链接数的增长,观察每个客户端建立链接耗时情况,以及 TCP 链接错误率分布,以及链接重连等情况。
●第二阶段,稳定性测试:
测试不同量级链接并发,持续运行一段时间是否稳定,分析错误率,客户端响应分布以及服务端各性能指标是否正常。
●第三阶段,并发测试:
确定服务链接上限之后,测试服务并发,设备并发数为 12 万、24 万、30 万、54 万、60 万、70 万、100 万等阶梯性增长。观察不同量级链接同时启动,对服务器的影响。
比对不同并发下链接建立时间,错误率,服务器处理各项指标。
●第四阶段,异常测试:
验证不同并发情况下频繁上下线操作对服务器的影响,验证状态同步机制是否正常,并发操作下其他业务操作是否会受影响。
验证异常断网、数据库重连等操作,服务器是否能正常处理,异常恢复后,设备状态同步是否正常。
①.依次启动客户端观察系统瓶颈
客户端执行指令,启动连接: ./wrk miop://$HOSTNAME:pk@serverIp:serverPort/ -t 12 -c 60000 --latency -d 120m --timeout 15 -s delay.lua
一次客户端执行,可以看到 50% 响应时间在 23.20ms,从打印结果可以分析错误数据分布,其中 1391 个错误为获取套接字失败,6181 错误为连接被意外关闭。
②.依次启动 17 个客户端,启动过程中观察系统连接波动频率,当系统出现瓶颈时分析服务端性能指标,服务端启动 100 万连接,曲线图如下:
观察系统各项指标是否正常,CPU、内存使用率较稳定。网卡收发 IO 读写根据客户端在线数量基本成比例递增。
编写脚本查看 tcp 连接增长速度,统计每秒链接数量。
cat <<EOF >> tcp.sh
#!/bin/sh
while [ true ]; do
date >>tcp.txt
ss -s >>tcp.txt
/bin/sleep 1
/bin/data >>/home/test/data.txt
done
EOF
nohup ./tcp.sh 2>&1 > /dev/null &执行脚本,将结果保存到文件:
验证不同量级客户端同时启动,服务端的承载能力。
通过 10 万、20 万、30 万、60 万、100 万等不同量级并发操作,启动链接,进行性能对比,观察不同并发情况下客户端的延时分布情况,以及服务端各项性能指标是否满足预期。
并发执行过程中,客户端同时向服务端发起 Bind 请求,客户端响应时间有延迟,并发启动
10 万连接,50% 响应时间在 407us,
20 万连接,50% 响应时间在 585us,连接超时数量为 6692
60 万连接,响应时间明显增加,连接超时数量增加
从客户端的结果和服务端指标监控分析,TCP 连接每秒增长数量为 1 万-3 万,服务端并发连接为 1 万-2 万时较稳定,多余连接会被抛弃或超时,服务端 TCP 队列存在溢出情况:
此时可以通过调整服务端 TCP 连接池大小来提高服务端的并发效率,服务端会抑制客户端重连操作,客户端不断进行重试直到连接建立成功。
分别启动不同量级的客户端连接,持续运行两小时,观察服务性能指标,从曲线图可以分析服务端性能是否受到影响。网卡收发、磁盘读写成等比增加,CPU、内存消耗差别不大。
频繁进行 redis 重连操作,观察状态是否同步。
要对比百万级用户状态是否同步,要对比数据的一致性,需要研发提供两个接口同时对用户状态进行比对。
①.内存状态查询接口
②.查询数据库状态接口
③.通过查询两个接口进行结果比对。编写自动化脚本批量查询,将结果写入文件,直观查看结果。
从结果中,能够快速筛选出状态不一致的数据,可通过日志跟踪定位问题。
频繁操作客户端进行上下线操作,查看服务器性能指标,客户端上下线流程,事件上报等流程是否正常。
问题一:redis 断开重连,导致客户端链接波动,通过 ss –s 指令查看客户端以及服务端 tcp 状态,发现为客户端主动断开连接,定位为客户端问题。
问题二:频繁压测,发现数据库与内存状态同步不一致
用户在大并发情况下,会出现频繁上下线操作,可以增加记录几次用户上下线操作,同时根据最终操作数据库时间查看日志进行分析,根本原因就是客户端瞬时的上下线,服务器兼容处理机制不到位,导致数据状态不一致。
问题三:压测执行过程中,服务端出现大量连接超时,且连接不能快速恢复。此时可以同时分析客户端和服务端。通过连接状态查询,日志分析等手段快速定位问题。
以下现象为:服务端 open files 配置太小,导致 tcp 连接失败,可以通过修改配置进行优化。
八.结束语
长连压测的关键因素是 TCP 连接,通过不同手段,不同的压测频率对服务器进行施压。可以快速的发现问题。
长连处理过程是一个变化的过程,复现难度较大,因此需要借助不同手段实时跟踪定位,发现服务隐藏的漏洞。这是一个漫长学习的过程。在测试过程中不断总结经验,学习不同的手段跟踪异常漏洞,可以快速的提升产品质量。