JMeter WebSockets 发布/订阅 - 编写异步响应脚本

Posted

技术标签:

【中文标题】JMeter WebSockets 发布/订阅 - 编写异步响应脚本【英文标题】:JMeter WebSockets Publish/Subscribe - scripting aschronous responses 【发布时间】:2017-02-23 12:29:01 【问题描述】:

我们通过 WebSockets 在我们的应用程序中构建了一个发布/订阅模型,因此用户可以在数据更改时接收“动态更新”。我现在希望使用 JMeter 对此进行负载测试。

有没有办法配置 JMeter 测试以对收到 WebSocket“已发布”消息做出反应,然后运行进一步的采样器,即发出进一步的 Web 请求?

我查看了插件示例,但它们似乎专注于请求/回复模型(例如 https://bitbucket.org/pjtr/jmeter-websocket-samplers)而不是发布/订阅。

编辑:

我已经使用 WebSocketSampler 开发了一个解决方案 - 可以找到一个示例 JMX 文件 on BitBucket,它使用 STOMP over WebSockets 并包括连接、订阅、处理发布消息和从中启动 JMeter 采样器。

【问题讨论】:

试用 ZebraTester。它支持 websockets @Vinit 谢谢 - 我会检查一下 - 如果您知道 ZebraTest 支持异步(回调)样式使用会有所帮助,JMeter 支持 WebSockets(通过插件)。由于我们已经在 J​​Meter 上投入了时间等,我很想看看我是否可以先完成这项工作。 如果您谈论的是基于 Web 套接字的 MQTT,那么即将推出的 ZebraTester 版本中将提供该功能 我们实际上是在 WebSockets 上使用 STOMP 啊,目前不支持或不在路线图上 【参考方案1】:

https://bitbucket.org/pjtr/jmeter-websocket-samplers/overview插件只支持请求-响应模型对话是一种误解。

从 0.7 版开始,该插件提供“单读”和“单写”采样器。当然,这取决于您的确切协议,但想法是您可以使用“单写”采样器发送模拟创建订阅的 WebSocket 消息,然后将(标准 JMeter)While 循环与“单read" 采样器,以读取正在发布的任意数量的消息。

如果这不能满足您的需求,请告诉我,我会看看能为您做些什么(我是这个插件的作者)。

【讨论】:

我错过了 - 我会仔细看看。 根据对问题的编辑 - 我已经使用 WebSocketSamplers 取得了进展,其中包括在收到消息时启动 JMeter 采样器,因此接受这个作为我问题的答案。【参考方案2】:

基本上,JMeter 不太适合与被测系统进行异步类型的交互。

尽管(实际上)使用脚本组件(后处理器、计时器、断言,也许采样器,在您的情况下看起来最有用)和 JMeter 逻辑控制器,一切皆有可能。

比如,你可以排列你的“进一步的采样器”,覆盖在 If 块中,分析“收到 WebSocket 发布的消息”并为 If 块设置标志变量/其他参数。

您甚至可以同步线程,如果需要,请查看this answer。

但是告诉你什么 - 这看起来就像很多手写的东西要完成。

因此,考虑整个自定义手写测试工具也是有意义的。

【讨论】:

谢谢——我也是这么想的(没有深入了解细节)——只是希望我错过了一些东西。我会看看你链接的“线程间”选项。【参考方案3】:

我的系统带有 STOMP。因此,客户端执行 HTTP 消息,并使用此订阅模型通过异步 WebSockets 获得实际状态。为了模拟这种行为,我编写了一个类,它通过 JMeterContext 变量可以与 Jmeter 线程交换数据(导入部分你可以自己找到 import org.springframework.*):

public class StompWebSocketLoadTestClient 

public static JMeterContext ctx;
public static StompSession session;

public static void start(JMeterContext ctx, String wsURL, String SESSION) throws InterruptedException 
    WebSocketClient transport = new StandardWebSocketClient();

    WebSocketStompClient stompClient = new WebSocketStompClient(transport);
    ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
    threadPoolTaskScheduler.initialize();
    stompClient.setTaskScheduler(threadPoolTaskScheduler);
    stompClient.setDefaultHeartbeat(new long[]10000, 10000);
    stompClient.setMessageConverter(new ByteArrayMessageConverter());
    StompSessionHandler handler = new MySessionHandler(ctx);
    WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders();
    handshakeHeaders.add("Cookie", "SESSION=" + SESSION);
    stompClient.connect(wsURL, handshakeHeaders, handler);
    sleep(1000);

消息在这个类中处理:

private static class MySessionHandler extends StompSessionHandlerAdapter implements TestStateListener 

    private String Login = "";
    private final JMeterContext ctx_;

    private MySessionHandler(JMeterContext ctx) 
        this.ctx_ = ctx;
    

    @Override
    public void afterConnected(StompSession session, StompHeaders connectedHeaders) 
        session.setAutoReceipt(true);
        this.Login = ctx_.getVariables().get("LOGIN");
        //System.out.println("CONNECTED:" + connectedHeaders.getSession() + ":" + session.getSessionId() + ":" + Login);
        //System.out.println(session.isConnected());
        **//HERE SUBSCRIBTION:**
        session.subscribe("/user/notification", new StompFrameHandler() 

            @Override
            public Type getPayloadType(StompHeaders headers) 
                //System.out.println("getPayloadType:");
                Iterator it = headers.keySet().iterator();
                while (it.hasNext()) 
                    String header = it.next().toString();

                    //System.out.println(header + ":" + headers.get(header));
                
                //System.out.println("=================");
                return byte[].class;
            

            @Override
            public void handleFrame(StompHeaders headers, Object payload) 
                //System.out.println("recievedMessage");
                NotificationList nlist = null;
                try 
                    nlist = NotificationList.parseFrom((byte[]) payload);

                    JMeterVariables vars = ctx_.getVariables();
                    Iterator it = nlist.getNotificationList().iterator();
                    while (it.hasNext()) 
                        Notification n = (Notification) it.next();
                        String className = n.getType();
                        //System.out.println("CLASS NAME:" + className);

                        if (className.contains("response.Resource")) 
                            ///After getting some message you can work with jmeter variables:
                            vars.putObject("var1", var1);
                            vars.put("var2",String.valueOf(var2));
                        
                        //Here is "sending" variables back to Jmeter thread context so you can use the data during the test 
                        ctx_.setVariables(vars);
                        n = null;

                    
                 catch (InvalidProtocolBufferException ex) 
                    Logger.getLogger(StompWebSocketLoadTestClient.class.getName()).log(Level.SEVERE, null, ex);
                 
            

        );
    

在 Jmeter 测试计划中,在登录阶段之后,我刚刚添加了一个 Beanshell 采样器,其中包含登录名/密码和会话字符串以及 Jmeter 线程上下文

import jmeterstopm.StompWebSocketLoadTestClient;
StompWebSocketLoadTestClient ssltc = new StompWebSocketLoadTestClient();
String SERVER_NAME = vars.get("SERVER_NAME");
String SESSION = vars.get("SESSION");
String ws_pref = vars.get("ws_pref");
ssltc.start(ctx,ws_pref+"://"+SERVER_NAME+"/endpoint/notification-    ws/websocket",SESSION);

还可以通过简单的 vars 变量使用所有通过 Websockets 传入的数据:

Object var1= (Object) vars.getObject("var1");

【讨论】:

这看起来很有趣 - 我们也在使用 STOMP,因此可能非常适合。我通过“处理程序”看到回调 - 在那里,当我看到设置 JMeter 变量时,我正在努力解决的问题是它如何触发进一步的活动 - 即如何在测试中注入更多样本 - 对我们来说,这主要是 refreshData从 API 通过 HTTP。这是否需要 LoopControl 与(比如说)在第一轮连接并发送初始页面请求,并且如果数据变量集(即接收到的消息)发出刷新? 没有完全得到您的问题,但是在您与此示例建立连接后,将进入此 sunscribed 通道的任何数据都可以通过 vars 在任何 jmeter 采样器中使用。 好的,谢谢,我明白了要点 - 我的问题实际上是关于 JMeter 控制结构来处理多个发布响应,但我想我可以解决。

以上是关于JMeter WebSockets 发布/订阅 - 编写异步响应脚本的主要内容,如果未能解决你的问题,请参考以下文章

通过 GAE 标准上的 Websockets 订阅 GraphQL 没有响应

如何通过 websockets 在本地 RSK 节点上订阅“newBlockHeaders”?

EventMachine WebSockets - 订阅 WS 到 EM 频道与保持套接字收集

如何创建基本客户端以通过 websockets 使用 GraphQL 订阅

JMeter MQTT 在订阅与发布测试场景中的使用

使用 k6 测试 graphql 订阅