• Apache JMeter进行TCP并发压力测试初尝试


    前言

    由于互联网编程实验二第三题要求比较使用线程池与否的服务器的并发性能,遂检索信息并了解到Apache JMeter这个工具

    本文主要介绍了在已有Java JDK的情况下对Apache JMeter的安装及配置,以及利用JMeter进行TCP压力测试

    一、安装及配置

    先在官网下载压缩包:Apache JMeter - Download Apache JMeter

    image.png

    将文件apache-jmeter-5.6.3.zip解压到自己选择的目录中

    在根目录下,找到bin文件夹,进入文件夹中,找到jmeter.bat,双击即可打开软件

    二、TCP服务器

    编写Java代码,在Server类的main函数中,指定一个端口作为服务器端口,并在while死循环中不断接收客户端的请求,对于每一个请求新开一个线程ThreadServer,并在其中处理请求

    public class Server {  
        static int PORT = 9000;  
        static int MAX_POOL = 100;  
        public static void main(String[] args) throws IOException {  
            ServerSocket server = new ServerSocket(PORT);  
    
            // without thread pool
    
            while (true) {  
                Socket accept = server.accept();  
                Thread thread = new Thread(new ThreadServer(accept));  
                thread.start();  
            }  
    
            // with thread pool 
    
            // ExecutorService service = Executors.newFixedThreadPool(MAX_POOL);  
            // while (true) {  
            //   Socket accept = server.accept();  
            //   service.submit(new ThreadServer(accept));  
            // }  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    代码中将服务器分为两种模式,第一段为没有线程池的模式,第二段为使用线程池的模式。通过分别注释并重新编译运行来启动不同模式的服务器

    为了简化服务端和客户端的交互,我们在ThreadServer中仅仅打印连接成功以及断开连接的信息,而不进行多余的通信,如下

    public class ThreadServer implements Runnable{  
        Socket socket;  
        static int BUFFER_SIZE = 1024;  
        static String EXIT_STR = "exit";  
        public ThreadServer(Socket socket){  
            this.socket = socket;  
        }  
        @Override  
        public void run(){  
            try{  
                System.out.println("connection start");  
                OutputStream out = socket.getOutputStream();  
                out.write("connect successfully".getBytes());  
                // echo service  
                // InputStream in = socket.getInputStream();  
                // byte[] inBytes = new byte[BUFFER_SIZE];  
                // int len;  
                // while((len = in.read(inBytes)) != 0){  
                //   String str = new String(inBytes, 0, len);  
                //   if(str.equals(EXIT_STR))  
                //     break;  
                //   System.out.println("received: " + str);  
                //   out.write(str.getBytes());  
                // }  
                System.out.println("connection end");  
                socket.close();  
            }catch (IOException e){  
                e.printStackTrace();  
            }  
        }  
    }
    
    • 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

    注释部分是提供echo服务,需要客户端同步实现,在本题中无需使用,客户端参考以下代码:

    public class Client {  
        static String SERVER_HOST = "127.0.0.1";  
        static int SERVER_PORT = 9000;  
        static int BUFFER_SIZE = 1024;  
        static String EXIT_STR = "exit";  
        public static void main(String[] args) throws IOException {  
            Socket client = new Socket(SERVER_HOST, SERVER_PORT);  
            Scanner scanner = new Scanner(System.in);  
            OutputStream out = client.getOutputStream();  
            InputStream in = client.getInputStream();  
            byte[] buffer = new byte[BUFFER_SIZE];  
    
            // echo  
            while(scanner.hasNextLine()){  
                String lineOfWord = scanner.nextLine();  
                out.write(lineOfWord.getBytes());  
                if(lineOfWord.equals(EXIT_STR))  
                    break;  
                int len = in.read(buffer);  
                System.out.println("echo: " + new String(buffer, 0, len));  
            }  
            client.close();  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    三、并发测试

    1. 创建测试计划

    打开JMeter,右键单击测试计划(test plan),一直选择到新建线程组,如下

    image.png

    右键单击新建的线程组,分别新建TCP Sampler和Response Time Graph,分别用于TCP连接以及输出响应时间与时间的折线图

    image.png

    image.png

    注意到TCP Sampler属于Sampler模块,我们也可在此模块中选择HTTP Request进行HTTP请求的测试;Response Time Graph属于Listener模块,我们可以在此模块中选择Aggregate Report输出测试的聚合报告,包括响应时间的平均值、最小值,以及吞吐量等

    在TCP Sampler中,指定服务器的地址及端口号如下

    image.png

    在Response Time Graph指定记录的间隔,单位为ms,这里设置为1000

    image.png

    2. 正式测试

    首先启动服务端

    D:\idea project\internetprog\exp2\exp2\src>javac Server.java
    
    D:\idea project\internetprog\exp2\exp2\src>java Server
    
    • 1
    • 2
    • 3

    单击Thread Group,不断更改以下几个参数,测试不同程度的并发下服务的响应时间

    image.png

    其中

    1. Number of Threads即创建的线程数
    2. Ramp-up period即在多长时间内创建以上线程数,单位为s
    3. Loop Count即执行的次数,勾选Infinite代表无限次执行

    在本例中,我选择固定Ramp-up period为1,Loop Count为5,修改Number of Threads依次为2000、4000、6000、8000以及10000,分别对比在有无线程池的服务器中,出现较长延迟的响应时间。每种情况分别测试3~5次。

    测试结果如下

    线程数无线程池有线程池
    20001ms内1ms内
    40001s内1s内
    60002s内2s内
    80004s ~ 8s3s ~ 6s
    1000010s ~ 16s3s ~ 7s

    可以看出,当并发压力增大时,无线程池出现的长延迟响应时间,相比有线程池的情况增长要快

  • 相关阅读:
    搭建自己的OCR服务,第一步:选择合适的开源OCR项目
    Pandas小白入门散记(3)---Series.str--源代码定位问题
    使用koa搭建服务器(一)
    轻量封装WebGPU渲染系统示例<12>- 基础3D对象实体(源码)
    RSA加密和解密原理及过程(非对称加密)
    C++ 游戏飞机大战, 字符型的
    C#事件详解及应用示例
    SEO搜索引擎优化-SEO搜索引擎优化软件
    Maven 使用教程(三)
    【星海随笔】Ubuntu22.04忘记密码
  • 原文地址:https://blog.csdn.net/andrew_1219/article/details/138191053