5.4.4 WebSocket未竟事宜

上述用例已覆盖大部分WebSocket接口测试需求,但仍有优化空间,留作读者实践:

  • 异步连接创建:多线程并行创建WebSocket连接,缩短前置准备时间,使用CountDownLatch同步任务。
  • 验证结果统计:记录验证成功/失败次数,生成测试报告,提升用例精细度。
  • 价格验证:校验响应中的价格字段,确保VIP用户和普通用户的价格差异正确。
  • 延迟测试:记录请求发送和响应接收的时间戳,计算异步响应延迟。
  • TPS模型引擎:基于事件驱动的TPS模型,替代线程模型,优化高并发场景。

这些优化点可进一步提升测试的全面性和准确性。例如,在延迟测试中,可模拟网络抖动场景,验证系统在不稳定网络下的表现。

5.4.5 Netty-WebSocket订阅测试

随着小八超市用户规模扩大,在线人数突破1万,需测试服务端推送能力,验证系统支持的订阅用户上限。Netty-WebSocket以其低资源消耗和高并发能力,成为理想选择。以下代码实现1万用户订阅商品价格和库存推送:

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

import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.funtester.performance.books.chapter05.section3.NettyWebSocketClient;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * FunTester Netty-WebSocket订阅测试
 */
public class SubscribeTest {

    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        String url = "ws://localhost:12345/websocket/FunTester"; // 服务端地址
        URI uri = new URI(url);
        List<ChannelPromise> promises = new ArrayList<>(); // 存储连接Promise
        for (int i = 0; i < 10000; i++) {
            NettyWebSocketClient client = new NettyWebSocketClient(uri); // 创建客户端
            ChannelPromise connect = client.connect(); // 发起连接
            promises.add(connect);
        }
        for (ChannelPromise promise : promises) {
            promise.get(); // 等待握手完成
        }
        NettyWebSocketClient.channels.writeAndFlush(new TextWebSocketFrame("FunTester: 订阅蔬菜水果价格和数量频道")).sync(); // 批量发送订阅消息
        System.out.println("FunTester: 订阅成功");
    }
}

分析

Netty-WebSocket通过事件驱动和线程复用,支持1万连接的高效创建和消息发送。测试验证了服务端推送能力,适合评估系统在超大规模用户场景下的表现。实际场景中,可结合推送频率和消息大小,进一步压测服务端资源消耗。

5.4.6 连接保活

在海量连接订阅场景中,需通过心跳消息维持连接,防止服务端因超时剔除连接。以下分别展示Java-WebSocket和Netty-WebSocket的保活实现。

1. Java-WebSocket保活

通过异步线程定时发送ping消息,检查连接状态并利用重连机制处理异常:

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

import org.funtester.performance.books.chapter05.section2.JavaWebSocketClient;
import org.java_websocket.enums.ReadyState;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * FunTester Java-WebSocket保活实践
 */
public class JavaWebSocketKeepAlive {

    public static void main(String[] args) throws URISyntaxException {
        String url = "ws://localhost:12345/websocket/FunTester"; // 服务端地址
        URI uri = new URI(url);
        List<JavaWebSocketClient> clients = new ArrayList<>(); // 存储客户端
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(10000); // 每10秒发送心跳
                    for (JavaWebSocketClient client : clients) {
                        if (client.getReadyState() == ReadyState.OPEN) {
                            client.sendPing(); // 发送心跳
                            System.out.println("FunTester: 发送心跳");
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start(); // 启动心跳线程
        for (int i = 0; i < 1000; i++) {
            JavaWebSocketClient client = new JavaWebSocketClient(uri) {
                @Override
                public void onMessage(String s) {
                    // 忽略响应,仅保持连接
                }
            };
            client.connect();
            clients.add(client);
        }
        // 性能测试逻辑
    }
}

2. Netty-WebSocket保活

利用ChannelGroup批量发送PingWebSocketFrame,简化保活逻辑: