Socket接口固定QPS性能测试实践

Stella981
• 阅读 973

在学习了Socket协议的知识和完善固定QPS压测模型之后,打算对Socket.IO协议的接口进行一波压测实践,来验证自己写的功能是否存在BUG和更多能做的优化空间。

总结下来,修复了两三个BUG,性能测试进度条的计算方式进行了优化,不然在类似Socket这种异步处理的请求,可能会由于统计的doing()方法耗时太少,导致计算出错,会出现突然跳到循环展示程序,直接显示100%,当然这也是一个BUG

思路

首先由一个老师和一个学生连接Socket.IO,然后老师进入一个房间(提前构造测试数据),不停地发送某个获取数据的指令,这里采取固定QPS性能测试模型。为了更好描述性能,我引入了一个指标,消息响应延迟,用来表示Socket服务对于正常业务的处理能力。

监控线程

依然采用了内部静态类的形式,用的顺了就习惯了,比较简单,就是Groovy访问静态属性的时候有点问题,捯饬了好一阵子才解决编译报错的问题。其实直接运行Groovy脚本完全可以,大家用的时候可以不用理会编译报错。

`/**
     * 监控延迟
     */
    static class ListenThread extends SourceCode implements Runnable {

        public boolean key = true;

        public ScoketIOFunClient listen;

        public List delays = []

        ListenThread(ScoketIOFunClient listen) {
            this.listen = listen
        }

        @Override
        void run() {
            listen.send(OkayScoketConstant.EVENT, getChat(roomId + 1, sbase.uname as long, tbase.uid, kid, ktype, DEFAULT_STRING, true))
            sleep(3.0)
            while (key) {
                def msg = StringUtil.getString(20)
                def start = Time.getTimeStamp()
                listen.send(OkayScoketConstant.EVENT, getChat(roomId + 1, sbase.uname as long, tbase.uid, kid, ktype, msg, true))
                for (int i = 0; i < 10; i++) {
                    def last = listen.msgs.getLast()
                    if (last.contains(msg)) break
                }
                def end = Time.getTimeStamp()
                def l = end - start
                delays << l
                logger.info("响应延迟时间:{}ms", l)
                sleep(3.0)
            }
        }

        public void stop() {
            key = false
            Save.saveLongList(delays, "delays")
        }
    }
`

多线程任务

这里采用了FixedQpsThread<ScoketIOFunClient>这个模式,目前全局使用一个Socket实例,并发完全满足,因为是异步的,所以毫无压力,若是测试多用户在线的场景,需要提前向房间内加入用户。

  • 这里我取消了 Socket.IO响应消息的打印,为了防止日志太多,导致性能下降。

`static class SendMsg extends FixedQpsThread {

        SendMsg(ScoketIOFunClient scoketIOFunClient) {
            super(scoketIOFunClient, getNum(), getQps(), null, true)
        }

        @Override
        protected void doing() throws Exception {
            t.send(OkayScoketConstant.EVENT, getCorrect(sbase.getUid(), 1, 24, 4))
        }

        @Override
        FixedQpsThread clone() {
           new SendMsg(this.t)
        }
    }
`

测试脚本

这个没啥好说的,可以翻看以前的文章。

`class ST1 extends SocketBase {

    private static Logger logger = LoggerFactory.getLogger(ST1.class)

    static int roomId = 44465

    static int kid = 540

    static int ktype = 1

    static IBase tbase

    static IBase sbase

    static int qps = 200

    static int num = 4000

    public static void main(String[] args) {
        tbase = getTeaBase()
        sbase = getStuBase()
        ScoketIOFunClient teacher = getSocket(tbase)
        ScoketIOFunClient student = getSocket(sbase)

        initAll()
        registerAll()
        joinRoom(roomId)

        teacher.send(OkayScoketConstant.EVENT, getCorrect(sbase.getUid(), 1, 24, 4))

        def thread = new ListenThread(student)
        def thread1 = new Thread(thread)
        thread1.start()
        new FixedQpsConcurrent(new SendMsg(teacher), "测试不同压力下消息延迟").start()

        thread.stop()
        thread1.join()
        leaveRoom(roomId)

        ScoketIOFunClient.closeAll()
    }
}
`

控制台输出

`INFO-> 当前用户:fv,IP:10.60.193.37,工作目录:/Users/fv/Documents/workspace/okay_test/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 请求uri:https://teacherpad-***.cn/api/t_pad/user/login,耗时:985 ms, requestId:Fun20210220090333dMSx
INFO-> 教师:62951571858,学科:null,名称:背锅侠六二六,登录成功!
INFO-> 请求uri:https://stupad-dev***.cn/api/pad/user/login,耗时:187 ms, requestId:Fun20210220090334etdZ
INFO-> 用户:82951571513,登录成功!
INFO-> Socket 连接: http://aileaidGltZ97Fs&userType=1,客户端名称: 老师:62951571858
INFO-> Socket 连接: http://1MPkp-zlk&userType=2,客户端名称: 学生:82951571513
INFO-> 学生:82951571513 开始连接...
INFO-> 学生:82951571513 连接成功!
INFO-> 老师:62951571858 开始连接...
INFO-> 老师:62951571858 连接成功!
INFO-> 补偿线程开始!
INFO-> 响应延迟时间:7ms
INFO-> 测试不同压力下消息延迟进度:▍▍▍▍▍▍▍▍▍▍▍▍▍  20.35%
INFO-> 响应延迟时间:1ms
INFO-> 响应延迟时间:1ms
INFO-> 期望执行数:2000,实际执行数:1652,设置QPS:200
INFO-> 测试不同压力下消息延迟进度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍  41.4%
INFO-> 响应延迟时间:1ms
INFO-> 响应延迟时间:2ms
INFO-> 测试不同压力下消息延迟进度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍  63.9%
INFO-> 响应延迟时间:1ms
INFO-> 测试不同压力下消息延迟进度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍  86.78%
INFO-> 响应延迟时间:1ms
INFO-> 测试不同压力下消息延迟进度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍  100%
INFO-> 总计执行 4000次任务 ,共用时:23.715 s,执行总数:4133,错误数:0!
INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/okay_test/long/data/测试不同压力下消息延迟200903_1
INFO->
☢~~☢ JSON ☢~~☢
>  {
>  ① . "rt":0,
>  ① . "total":4133,
>  ① . "qps":-6.829,
>  ① . "failRate":0.0,
>  ① . "threads":1,
>  ① . "startTime":"2021-02-20 09:03:41",
>  ① . "endTime":"2021-02-20 09:04:04",
>  ① . "errorRate":0.0,
>  ① . "executeTotal":4133,
>  ① . "mark":"测试不同压力下消息延迟200903",
>  ① . "table":"eJzj5VIgDjzb2v1i/dQnO3qfTuh52tf9tGv2kx3dz7Z1PGtc/3T3thf75xsZGFgaGBsSaRwvFy9+m4NSiwvy84pTFUIyc1OtFCp0i1OLMhNzFPJKc3UUKnVzU1MyE/MI2UGMS3Iz8xQgplkZKOQW6+QmVlgZAxnE+YIYVWSDR9M6gGjUllFbRm0ZUbY8mtYERPSxCWzFqE2jNo3aNGJtejStFYgop6jpImSzqEONumjURaMuGnXRqItwuwgADK4ysA=="
>  }
☢~~☢ JSON ☢~~☢
INFO->
                                       测试不同压力下消息延迟2009031                                       

                             Response Time: x-serial num, y-median                              
                                    min median:0 ms,max:3 ms                                    

见下图*

INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/okay_test/long/delays
INFO-> 老师:62951571858 socket链接关闭!
INFO-> 学生:82951571513 socket链接关闭!
INFO-> 关闭所有Socket客户端!
INFO-> 测试不同压力下消息延迟进度:  0%
INFO-> 补偿线程结束!

Process finished with exit code 0

`

Socket接口固定QPS性能测试实践

测试不同压力下消息延迟2009161

这里依然存在一些问题,如下:

  • QPS计算出错,这里是因为补偿线程导致的,因为太快了,补偿线程应该处理的这些问题,哈哈,这个我在 HTTP接口测试时候没有这个问题的。

  • 由于测试时间偏短,其他辅助线程都是循环机制,所以导致日志可能会出错。比如 INFO-> 测试不同压力下消息延迟进度: 0%这个是因为在测试任务结束后,我会把执行数重置为 0,但是此时进度条任务还未结束,所以多打印了一次。这个已经确认了优化方式。

  • 补偿的请求的时机和补偿机制还有优化空间,总执行数 4133比设定值 4000高了不少,后面因为是固定量然后循环补偿,可能这个时候任务发生了变化,所以待优化。

参考文章:


FunTester腾讯云社区钦定年度作者,非著名测试开发er,欢迎关注。

Socket接口固定QPS性能测试实践

点击阅读原文,查看公众号历史文章

本文分享自微信公众号 - FunTester(NuclearTester)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这