负载测试
由于 Socket.IO 有其 自己的协议,包括握手、心跳和自定义数据包编码,因此对 Socket.IO 服务器进行负载测试的最简单方法是使用 Socket.IO 客户端库并创建大量客户端。
¥Since Socket.IO has its own protocol, including handshake, heartbeats and custom packet encoding, the easiest way to load test your Socket.IO server is to use the Socket.IO client library and create a lot of clients.
有两种经典的解决方案可以做到这一点:
¥There are two classic solutions to do this:
Artillery
Artillery 是对应用进行负载测试的绝佳工具。它允许创建连接、发送事件和检查确认。
¥Artillery is a great tool for load testing your application. It allows creating connections, sending events and checking acknowledgments.
该文档可以在 此处 中找到。
¥The documentation can be found here.
重要的提示:默认安装带有 v2 客户端,即带有 v3/v4 服务器的 不兼容。你需要为此安装一个自定义引擎:https://github.com/ptejada/artillery-engine-socketio-v3
¥Important note: the default installation comes with a v2 client, which is not compatible with a v3/v4 server. You need to install a custom engine for this: https://github.com/ptejada/artillery-engine-socketio-v3
安装:
¥Installation:
$ npm install artillery artillery-engine-socketio-v3
示例场景:
¥Sample scenario:
# my-scenario.yml
config:
target: "http://localhost:3000"
phases:
- duration: 60
arrivalRate: 10
engines:
socketio-v3: {}
scenarios:
- name: My sample scenario
engine: socketio-v3
flow:
# wait for the WebSocket upgrade (optional)
- think: 1
# basic emit
- emit:
channel: "hello"
data: "world"
# emit an object
- emit:
channel: "hello"
data:
id: 42
status: "in progress"
tags:
- "tag1"
- "tag2"
# emit in a custom namespace
- namespace: "/my-namespace"
emit:
channel: "hello"
data: "world"
# emit with acknowledgement
- emit:
channel: "ping"
acknowledge:
match:
value: "pong"
# do nothing for 30 seconds then disconnect
- think: 30
要运行此场景:
¥To run this scenario:
$ npx artillery run my-scenario.yml
Artillery 还具有许多令人敬畏的功能,例如 将指标发布到各个端点 或 从 AWS 运行测试 的能力。
¥Artillery also comes with a lot of awesome features, like the ability to publish the metrics to various endpoints or run the tests from AWS.
它唯一的限制是你无法轻松测试服务器到客户端事件,因为 Artillery DSL 更适合经典的客户端到服务器通信。这就把我们带到了 我们的下一部分。
¥Its only limitation is that you cannot easily test server-to-client events, as the Artillery DSL is more suited for classic client-to-server communication. Which brings us to our next section.
手动创建客户端
¥Manual client creation
以下是创建一千个 Socket.IO 客户端并监视每秒接收的数据包数量的基本脚本:
¥Here's a basic script to create a thousand Socket.IO clients and monitor the number of packets received per second:
const { io } = require("socket.io-client");
const URL = process.env.URL || "http://localhost:3000";
const MAX_CLIENTS = 1000;
const POLLING_PERCENTAGE = 0.05;
const CLIENT_CREATION_INTERVAL_IN_MS = 10;
const EMIT_INTERVAL_IN_MS = 1000;
let clientCount = 0;
let lastReport = new Date().getTime();
let packetsSinceLastReport = 0;
const createClient = () => {
// for demonstration purposes, some clients stay stuck in HTTP long-polling
const transports =
Math.random() < POLLING_PERCENTAGE ? ["polling"] : ["polling", "websocket"];
const socket = io(URL, {
transports,
});
setInterval(() => {
socket.emit("client to server event");
}, EMIT_INTERVAL_IN_MS);
socket.on("server to client event", () => {
packetsSinceLastReport++;
});
socket.on("disconnect", (reason) => {
console.log(`disconnect due to ${reason}`);
});
if (++clientCount < MAX_CLIENTS) {
setTimeout(createClient, CLIENT_CREATION_INTERVAL_IN_MS);
}
};
createClient();
const printReport = () => {
const now = new Date().getTime();
const durationSinceLastReport = (now - lastReport) / 1000;
const packetsPerSeconds = (
packetsSinceLastReport / durationSinceLastReport
).toFixed(2);
console.log(
`client count: ${clientCount} ; average packets received per second: ${packetsPerSeconds}`
);
packetsSinceLastReport = 0;
lastReport = now;
};
setInterval(printReport, 5000);
你可以将其用作对你自己的应用进行负载测试的起点。
¥You can use it as a starting point for load testing your own application.