Operations 9 min read

How to Stress‑Test a WebSocket Product Query API with Java

This guide walks you through designing, implementing, and analyzing a Java‑based performance test for a WebSocket product‑query interface, covering request/response formats, thread‑driven load generation, TPS control, console metrics, and response validation techniques.

FunTester
FunTester
FunTester
How to Stress‑Test a WebSocket Product Query API with Java

Overview

This section demonstrates how to load‑test a WebSocket product‑query API that returns real‑time price and inventory information. The test simulates concurrent users querying a small‑scale supermarket scenario, where traditional HTTP would become a bottleneck under high concurrency.

WebSocket Interface Specification

Endpoint : /websocket Message format : JSON string

Request fields : name (String, product name), index (int, unique request identifier)

Example request : {"name":"西瓜","index":1} Example response :

{"Name":"西瓜","Price":45,"Size":62,"Timestamp":1701589121943}

Test Design and Rate Control

WebSocket’s asynchronous nature allows a very high request rate. To avoid overwhelming the server, the test limits the transaction‑per‑second (TPS) by inserting a fixed sleep interval (10 ms) after each send. Authentication is simulated via HTTP headers name and password. A single WebSocket connection is shared among all threads to keep the client logic simple.

Performance Test Implementation (Java)

package org.funtester.performance.books.chapter05.section4;

import com.alibaba.fastjson.JSONObject;
import org.funtester.performance.books.chapter03.common.ThreadTool;
import org.funtester.performance.books.chapter03.section3.ThreadTask;
import org.funtester.performance.books.chapter03.section4.TaskExecutor;
import org.funtester.performance.books.chapter04.section3.RandomTool;
import org.funtester.performance.books.chapter05.section2.JavaWebSocketClient;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocket product‑query performance test using a thread‑per‑task model.
 */
public class QueryGoodsThreadTestFirst {
    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        // Server address
        String url = "ws://localhost:12345/websocket/FunTester";
        URI uri = new URI(url);
        // HTTP headers for authentication
        HashMap<String, String> headers = new HashMap<>();
        headers.put("name", "user1");
        headers.put("password", "123456");
        // Product list used for random selection
        List<String> goods = Arrays.asList(
                "苹果", "西瓜", "香蕉", "橘子", "梨子",
                "西红柿", "胡萝卜", "青椒", "洋葱", "黄瓜");
        // Counter for unique request indices
        AtomicInteger requestIndex = new AtomicInteger(0);
        // Create and connect a single WebSocket client
        JavaWebSocketClient client = new JavaWebSocketClient(uri, headers);
        client.connect();
        int totalNum = 1000; // requests per thread
        List<ThreadTask> tasks = new ArrayList<>();
        // Create 8 concurrent tasks
        for (int i = 0; i < 8; i++) {
            ThreadTask threadTask = new ThreadTask() {
                @Override
                public void test() {
                    JSONObject params = new JSONObject();
                    // Random product name
                    params.put("name", RandomTool.getRandomElement(goods));
                    // Incremental request index
                    params.put("index", requestIndex.incrementAndGet());
                    client.send(params);
                    // Sleep 10 ms to keep TPS ≈ 700
                    ThreadTool.sleep(10);
                }
            };
            threadTask.totalNum = totalNum;
            threadTask.costTime = new ArrayList<>(totalNum);
            tasks.add(threadTask);
        }
        // Execute all tasks with a 20‑thread pool
        TaskExecutor taskExecutor = new TaskExecutor(tasks,
                "FunTester WebSocket product‑query performance test", 20);
        taskExecutor.start();
        client.close();
    }
}

/** Utility to pick a random element from a list */
public static <T> T getRandomElement(List<T> list) {
    int randomIndex = ThreadLocalRandom.current().nextInt(list.size());
    return list.get(randomIndex);
}

Execution Output

FunTester: 正在连接...
FunTester: 连接已打开
握手信息 key: Connection value: Upgrade
握手信息 key: Sec-WebSocket-Accept value: 3lwrnuOahBiw6oENmzVlKllB+mE=
握手信息 key: Upgrade value: websocket
FunTester: WebSocket客户端状态: OPEN
FunTester: 连接成功
实时统计TPS: 80, 平均耗时: 12ms
实时统计TPS: 704, 平均耗时: 11ms
Rump-Up结束,开始执行测试任务!
实时统计TPS: 691, 平均耗时: 11ms
实时统计TPS: 706, 平均耗时: 11ms
任务执行完毕! 预期执行次数: 1000, 实际执行次数: 998, 错误次数: 0, 耗时收集数量: 998
任务执行完毕! 预期执行次数: 1000, 实际执行次数: 1000, 错误次数: 0, 耗时收集数量: 1000
测试TPS: 726, 总执行次数: 7989
任务执行完毕! 压测时长: 11秒, 预期执行次数: 8000, 实际执行次数: 7989, 错误次数: 0, 耗时收集数量: 7989

Result Analysis

The eight‑thread workload generated roughly 700 TPS with an average response latency of 11 ms, confirming that the server can handle the simulated load without errors. The test deliberately caps the request rate to avoid a “ramp‑up” overload, making the observed metrics reliable for capacity planning.

Response Validation

To verify that each response matches its request, the following strategy is used:

Maintain a ConcurrentHashMap<Integer, String> that maps the index of each request to the expected product name.

Override the client’s onMessage callback, parse the incoming JSON, and compare the returned Name field with the stored expectation.

Log a warning if the names differ; otherwise remove the entry from the map to mark the request as successfully validated.

The modified validation logic resides in the QueryGoodsThreadTestSecond class (full source omitted for brevity).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaPerformance TestingLoad TestingWebSocket
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.