SSE 和长轮询方式下的性能测试对比
在现代 Web 应用程序开发中,一种实现实时消息传递的最流行方法是使用 SSE (Server-Sent Events,服务器发送事件) 或长轮询(Long Polling)。这两种方法都旨在消除传统的轮询技术的缺点,该技术会在短时间内频繁地向服务器发送请求以检查是否有消息更新。在本文中,我们将探讨 SSE 和长轮询方法的工作原理及其性能,以及它们如何与传统的轮询技术相比,为前端开发提供指导意义。
- SSE 工作原理
SSE 是 HTML5 的一部分,允许 Web 应用程序与服务器建立长期连接,并通过该连接接收实时数据。SSE 使用 HTTP 协议的 GET 请求,并通过服务器端的响应来实现消息传递。客户端使用 EventSource 对象打开连接,服务器推送消息到客户端,每次推送都包括一个事件的名称和数据。
例如,假设我们正在监控一个传感器,该传感器每隔一秒钟会向服务器发送一条数据。为了通过 SSE 获取此数据,我们可以使用以下 JavaScript 代码:
var source = new EventSource('/sensor'); source.addEventListener('sensor_data', function(event) { console.log('Sensor data received: ' + event.data); });
在此代码中,我们创建了一个 EventSource 对象,将其连接到 /sensor 路径。当服务器推送名为 "sensor_data" 的事件时,客户端的 "sensor_data" 事件侦听器被触发,并将数据打印到控制台上。
- 长轮询工作原理
长轮询是实现实时消息传递的另一种方法。它类似于轮询技术,但与轮询技术不同的是,在没有新消息的情况下,服务器不会立即响应客户端的请求。相反,服务器将长时间保持客户端请求处于挂起状态,直到有新消息为止。
例如,我们可以使用以下 JavaScript 代码来实现长轮询:
function longPoll() { $.ajax({ url: '/sensor', type: 'GET', async: true, cache: false, timeout: 30000, success: function(data) { console.log('Sensor data received: ' + data); longPoll(); // 递归调用以等待下一个返回值 }, error: function(XMLHttpRequest, textStatus, errorThrown) { console.log('Error occurred: ' + textStatus); longPoll(); // 递归调用以重试 } }); } longPoll();
在长轮询中,我们使用 jQuery 的 ajax() 函数,设置请求类型为 GET,将异步标志设置为 true,并将超时时间设置为 30 秒。如果成功返回数据,则打印数据并递归调用 longPoll() 函数以等待下一个返回值。如果发生错误,则打印错误消息并递归调用 longPoll() 函数以进行重试。
- SSE 和长轮询的性能测试
我们将使用 Apache Bench(ab)来比较 SSE 和长轮询的性能。我们将测试每种技术并计算其处理请求所需的平均时间。
在以下测试中,我们将使用以下服务器端代码:
const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); setInterval(() => { res.write(`event: sensor_data\n`); res.write(`data: ${Date.now()}\n`); res.write(`\n`); }, 1000); }); server.listen(3000);
该代码创建了一个 HTTP 服务器,为 SSE 和长轮询提供一个可用的端点。每秒钟发送一条数据,以便我们可以模拟真实数据流。
接下来,我们将为 SSE 和长轮询分别运行 ab 命令来测试它们的性能。对于每种测试,我们将向服务器发送 1000 个请求,并使用 100 个并发请求。我们将测试 SSE 和长轮询处理这 1000 个请求所需的时间,以及它们发送的数据量。
SSE 测试结果:
ab -n 1000 -c 100 http://localhost:3000 Requests per second: 31.77 [#/sec] (mean) Average transfer rate: 2671 [Kbytes/sec] received
长轮询测试结果:
ab -n 1000 -c 100 http://localhost:3000 Requests per second: 13.93 [#/sec] (mean) Average transfer rate: 726.16 [Kbytes/sec] received
如我们所见,SSE 显著优于长轮询,平均处理请求速度是长轮询的两倍以上。此外,SSE 也发送了更多的数据,这在实际应用中当然更具有指导性。
- 总结与指导
在性能和数据量方面,SSE 明显优于长轮询,然而使用 SSE 的实现更加复杂。SSE 必须配置服务器发送事件(SSE)端点,而长轮询代码则更加简单。
在实际情况中,我们应该选择 SSE 或长轮询可能要取决于特定应用的性质和需要。尝试使用 SSE 实现实时消息传递时,应该先考虑我们的应用程序是否能够实现 SSE 和与 SSE 相关的服务器端点。如果我们的应用程序需要避免推送过多的数据,则应该考虑使用长轮询。
在编写代码以实现 SSE 或长轮询时,我们应该思考如何设计代码,以便实现不仅高效、可扩展性高,而且易于维护。我们应该避免使用复杂的 JavaScript 特性以及没有必要的 HTTP 请求,保证代码最大的效率和可维护性。
我们的示例代码可以作为代码指南,可供开发者参考实现 SSE 或长轮询实现实时消息传递的功能。同时,我们也呼吁使用者了解具体的业务背景,根据需求灵活应对,使得最终应用可扩展和性能更高效。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a4d3fdadd4f0e0ffd2c83d