LoadRunner WebSocket 脚本开发和实时通信压测指南。
1. 协议选择和脚本基础
选择正确的协议
创建 Vuser 脚本时,直接选择WebSocket单协议,或多协议组合(如 WebSocket + Web - HTTP/HTML,用于同时处理HTTP登录和WebSocket通信)。不要仅选Web - HTTP/HTML,无法直接生成长连接消息函数。
主要函数概览
web_websocket_connect – 建立 WebSocket 连接(含 HTTP 升级)
web_websocket_send – 发送文本/二进制消息
web_websocket_receive – 同步接收一条消息
web_reg_websocket_receive – 异步注册期望消息(类似 web_reg_find)
web_websocket_close – 主动关闭连接
2. 脚本开发流程
连接建立(放在 vuser_init 或 Action 开头)
c
web_set_sockets_option("SSL_VERSION", "TLSv1.2");
web_set_sockets_option("WS_KEEP_ALIVE_INTERVAL", "30");
web_websocket_connect(
"WSConnect",
"URL=wss://your.server.com/chat",
"Origin=https://your.server.com",
"Headers=Authorization: Bearer {token}\r\n",
"SocketID=0",
"Timeout=10",
LAST);
如果需先通过 HTTP 登录获取 token,在脚本前部用 web_submit_data 等 HTTP 函数,再用参数 {token} 传递。SocketID 用于区分同一 Vuser 内的多个 WebSocket 连接(一般设为 0)。
消息收发和关联
同步发送加接收响应:
c
lr_start_transaction("WS_SendAndReceive");
web_websocket_send(
"WSConnect",
"Payload={\"type\":\"ping\",\"seq\":{seq}}",
"PayloadType=Text",
LAST);
web_websocket_receive(
"WSConnect",
"Text=pong",
"SaveStringParam=pongResp",
"Timeout=5",
LAST);
lr_end_transaction("WS_SendAndReceive", LR_AUTO);
异步推送处理(服务器主动推送):
c
// 在发送前或 vuser_init 末尾注册
web_reg_websocket_receive(
"WSConnect",
"Text=*notification*",
"SaveStringParam=notifyMsg",
"MaxMatch=10",
"Timeout=0",
LAST);
// 后续循环中检查
if (strlen(lr_eval_string("{notifyMsg}")) > 0) {
lr_log_message("Received push: %s", lr_eval_string("{notifyMsg}"));
}
web_reg_websocket_receive 注册后,所有一致的后台消息会被自动捕获到参数中,实现非阻塞异步处理。
心跳保活
实时通信必须维持长连接。常见做法是在 Action 循环中加入应用层心跳:
c
if (mod(current_sec, 30) == 0) {
web_websocket_send("WSConnect", "Payload=ping", LAST);
}
TCP Keep-Alive 也可辅助使用(已在连接设置中配置)。
连接关闭(vuser_end)
c
web_websocket_close("WSConnect", "Code=1000", "Reason=Normal Closure", LAST);
3. 参数化和动态数据关联
参数化负载内容
将发送内容、频率、目的用户等放入参数文件,使用 {username}、{message}、{roomId} 等。序列号或时间戳可用 {timestamp} 或 lr_param_increment。
动态 Token 关联
如果 WebSocket 握手阶段返回 SessionId(在 HTTP 101 响应或首条消息中),用 HTTP 级别的关联捕获:
c
web_reg_save_param("WS_TOKEN", "LB=token\":\"", "RB=\"", "Search=Body", LAST);
web_websocket_connect(...);
// 后续发送时使用 {WS_TOKEN}
响应内容提取
同步接收时直接用 web_websocket_receive 的 SaveStringParam,或用 Text 做边界捕获:
c
web_websocket_receive("WSConnect",
"Text={\"seq\":", "SaveStringParam=fullMsg",
"Binary=0", // 文本方式
LAST);
4. 实时通信压测设计重点
长连接 Vuser 结构
vuser_init:建立 WebSocket 连接,完成登录鉴权。
Action:循环执行发送消息 - 接收确定,同时处理异步通知。通过 think_time 模拟用户延迟(压测峰值时可移除)。
vuser_end:主动关闭连接。
并发方式和负载模型
连接数:每个 Vuser 默认占用一个 WebSocket 连接,Vuser 数即在线用户数。
突发流量:使用集合点(lr_rendezvous)让所有 Vuser 同时发送,测试瞬时处理能力。
阶梯加压:在 Controller 中逐步增加 Vuser,观察短板。
长时间稳定性:设置 Duration 为 2–8 小时,监控连接掉线率。
监控标准
客户端事务响应时间(发送到收到回复的往返时间)
服务端 WebSocket 连接数、内存、CPU、线程池使用率
消息吞吐量(条/秒)、错误率(连接超时、4xx/5xx 升级失败、消息丢失)
LoadRunner 内置监控可添加系统资源,应用标准需通过自定义计数器或日志补充。
5. 常见问题和调试
问题:无法建立 WSS 连接
排查和解决:检查 SSL 版本,安装服务器证书到 LoadRunner 证书库,或临时设置 web_set_sockets_option("SSL_VERIFY_PEER", "0") 跳过检查(仅限测试环境)。
问题:连接被服务端主动断开
排查和解决:查看是不是缺少心跳,增加 TCP Keep-Alive 或应用层 Ping;检查服务端最大空闲时间配置。
问题:异步消息丢失或乱序
排查和解决:使用 web_reg_websocket_receive 并设置合适的缓冲区大小和一致规则;及时从参数中取出消息,避免包括。
问题:录制不生成 WebSocket 函数
排查和解决:在 Recording Options → Network → Port Mapping 中设置 Socket level data,并启用 WebSocket 支持;也可通过 Wireshark 抓包后手动编码。
问题:高并发下绑定端口耗尽
排查和解决:多 Vuser 运行时本地端口可能不足,调大动态端口范围(如 Linux 下修改 net.ipv4.ip_local_port_range)并缩短 TIME_WAIT 时间。
6. 完整脚本示例
c
vuser_init() {
web_set_sockets_option("SSL_VERSION", "TLSv1.2");
// HTTP 登录获取 token 部分略
web_websocket_connect("WS0", "URL=wss://...", "SocketID=0", LAST);
web_reg_websocket_receive("WS0", "Text=*chat*", "SaveStringParam=pushMsg", "MaxMatch=5", "Timeout=0", LAST);
return 0;
}
Action() {
lr_start_transaction("SendMessage");
web_websocket_send("WS0", "Payload={\"msg\":\"{userMsg}\"}", "PayloadType=Text", LAST);
web_websocket_receive("WS0", "Text=ack", "Timeout=3", LAST);
lr_end_transaction("SendMessage", LR_AUTO);
if (strlen(lr_eval_string("{pushMsg}")) > 0) {
// 处理异步推送
}
return 0;
}
vuser_end() {
web_websocket_close("WS0", "Code=1000", LAST);
return 0;
}
包括了连接、同步收发、异步注册和正常关闭,可以直接在此基础上根据实际业务协议调整Payload和关联思路。