「Web应用架构」轮询,SSE 和WebSocket,如何选择合适的?
构建实时Web应用程序有点挑战,我们需要考虑如何将数据从服务器发送到客户端。能够“主动”实现这一功能的技术已经存在了很长时间,并且仅限于两种通用方法:客户端请求或服务器请求。
实现这些的几种方法:
长/短轮询(客户端拉动)
WebSockets(服务器推送)
服务器发送的事件(服务器推送)
客户端拉取-客户端以一定的定期间隔向服务器请求更新
服务器推送-服务器正在主动将更新推送到客户端(客户端拉取的反向操作)
让我们以一个简单的用例来比较以上技术,然后选择合适的技术。
范例:
我们的示例用例非常简单。我们需要开发一个仪表板Web应用程序,该应用程序可以流转来自(GitHub / Twitter / .. etc)等网站的活动列表。这个应用程序的目的是从上面列出的各种方法中选择合适的一种。
1.使用轮询:
轮询是一种技术,客户端通过该技术定期向服务器请求新数据。我们可以通过两种方式进行轮询:短轮询和长轮询。简单来说,短轮询是基于AJAX的计时器,它以固定的延迟进行调用,而长轮询则基于Comet(即,当服务器事件发生时,服务器将无延迟地将数据发送到客户端)。两者都有优点和缺点,并根据用例进行调整。有关深入的详细信息,请阅读StackOverflow社区给出的答案。
让我们看看一个简单的客户端长轮询代码段的外观:
/* Client - subscribing to the github events */
subscribe: (callback) => {
const pollUserEvents = () => {
$.ajax({
method: 'GET',
url: 'http://localhost:8080/githubEvents',
success: (data) => {
callback(data) // process the data
},
complete: () => {
pollUserEvents();
},
timeout: 30000
})
}
pollUserEvents()
}
这基本上是一个长轮询功能,它像往常一样第一次运行,但是它设置了三十(30)秒的超时,并且在每次对服务器进行Async Ajax调用之后,回调都会再次调用Ajax。
AJAX调用可在HTTP协议上运行,这意味着默认情况下,对同一域的请求应进行多路复用。我们发现这种方法存在一些陷阱。
多路复用(轮询响应实际上无法同步)
轮询需要3次往返(TCP SIN,SSL和数据)
超时(如果连接保持空闲时间太长,代理服务器将关闭连接)
您可以在这里关于现实世界的挑战。
2.使用WebSockets:
WebSocket只是客户端和服务器之间的持久连接。这是一种通过单个TCP连接提供全双工通信通道的通信协议。
RFC 6455声明WebSocket“旨在在HTTP端口80和443上工作,并支持HTTP代理和中介”,从而使其与HTTP协议兼容。为了实现兼容性,WebSocket握手使用HTTP升级标头将HTTP协议更改为WebSocket协议。HTTP和WebSocket都位于OSI模型的应用程序层,因此依赖于第4层的TCP。
有一个MDN文档详细解释了WebSocket,我也建议您阅读它。
让我们看看一个非常简单的WebSocket客户端实现的样子:
$(function () {
// if user is running mozilla then use it's built-in WebSocket
window.WebSocket = window.WebSocket || window.MozWebSocket;
const connection = new WebSocket('ws://localhost:8080/githubEvents');
connection.onopen = function () {
// connection is opened and ready to use
};
connection.onerror = function (error) {
// an error occurred when sending/receiving data
};
connection.onmessage = function (message) {
// try to decode json (I assume that each message
// from server is json)
try {
const githubEvent = JSON.parse(message.data); // display to the user appropriately
} catch (e) {
console.log('This doesn\'t look like a valid JSON: '+ message.data);
return;
}
// handle incoming message
};
});
如果服务器支持WebSocket协议,它将同意升级,并将通过响应中的Upgrade标头传达此信息。
让我们看看如何在Node.JS(服务器)中实现:
const express = require('express');
const events = require('./events');
const path = require('path');
const app = express();
const port = process.env.PORT || 5001;
const expressWs = require('express-ws')(app);
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/static/index.html'));
});
app.ws('/', function(ws, req) {
const githubEvent = {}; // sample github Event from Github event API https://api.github.com/events
ws.send('message', githubEvent);
});
app.listen(port, function() {
console.log('Listening on', port);
});
一旦我们从GitHub事件API获得数据,就可以在建立连接后将其流式传输到客户端。对于我们的场景,这种方法也有一些陷阱。
使用WebSockets,我们需要自己处理许多由HTTP处理的问题。
WebSocket是用于传输数据的另一种协议,它不会通过HTTP / 2连接自动多路复用。在服务器和客户端上实现自定义多路复用有点复杂。
WebSocket是基于帧的,而不是基于流的。当我们打开网络标签。您可以看到WebSocket消息在frame中列出。
有关WebSocket的详细信息,请查看这篇很棒的文章,在这里您可以阅读有关碎片以及如何在后台进行处理的更多信息。
3.使用SSE:
SSE是一种机制,一旦建立了客户端-服务器连接,服务器就可以将数据异步推送到客户端。然后,只要有新的“大块”数据可用,服务器就可以决定发送数据。可以将其视为单向发布-订阅模型。
它还提供了一个标准的JavaScript客户端API,称为EventSource,已在大多数现代浏览器中实现,作为W3C的HTML5标准的一部分。 Polyfills可用于不支持EventSource API的浏览器。
我们可以看到Edge和Opera Mini落后于此实现,对于SSE而言,最重要的案例是针对移动浏览器设备,因为这些浏览器没有可行的市场份额。Yaffle是事件源的众所周知的pollyfill。
由于SSE是基于HTTP的,因此它很自然地与HTTP / 2相适应,并且可以结合使用以实现两者的最佳选择:HTTP / 2处理基于多路复用流的有效传输层,而SSE为应用程序提供API以实现 推。因此,开箱即用地通过HTTP / 2实现多路复用。连接断开时会通知客户端和服务器。通过使用消息维护唯一的ID,服务器可以看到客户端错过了n条消息,并在重新连接时发送了未完成消息的积压。
让我们看看示例客户端实现的外观:
const evtSource = new EventSource('/events');
evtSource.addEventListener('event', function(evt) {
const data = JSON.parse(evt.data);
// Use data here
},false);
此代码段非常简单。它连接到我们的源并等待接收消息。现在,示例NodeJS服务器将如下所示。
// events.js
const EventEmitter = require('eventemitter3');
const emitter = new EventEmitter();
function subscribe(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
// Heartbeat
const nln = function() {
res.write('\n');
};
const hbt = setInterval(nln, 15000);
const onEvent = function(data) {
res.write('retry: 500\n');
res.write(`event: event\n`);
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
emitter.on('event', onEvent);
// Clear heartbeat and listener
req.on('close', function() {
clearInterval(hbt);
emitter.removeListener('event', onEvent);
});
}
function publish(eventData) {
// Emit events here recieved from Github/Twitter APIs
emitter.emit('event', eventData);
}
module.exports = {
subscribe, // Sending event data to the clients
publish // Emiting events from streaming servers
};
// App.js
const express = require('express');
const events = require('./events');
const port = process.env.PORT || 5001;
const app = express();
app.get('/events', cors(), events.subscribe);
app.listen(port, function() {
console.log('Listening on', port);
});
我们从这种方法中获得的主要好处是:
实施更简单,数据效率更高
开箱即用地通过HTTP / 2自动多路复用
将客户端上数据的连接数限制为一个
如何在SSE,WebSocket和Polling中进行选择?
经过漫长而详尽的客户端和服务器实施之后,SSE似乎是我们解决数据交付问题的最终答案。也有一些问题,但是可以解决。
可以利用服务器发送事件的应用程序的一些简单示例:
实时股价流图
重要事件的实时新闻报道(发布链接,推文和图片)
由Twitter的流API提供的实时Github / Twitter仪表板墙
监视服务器统计信息(如正常运行时间,运行状况和正在运行的进程)的监视器。
但是,SSE不仅是其他提供快速更新的方法的可行替代方案。在某些特定情况下,例如在SSE被证明是理想解决方案的情况下,每个人都可以胜过其他人。考虑一个像MMO(大型多人在线)游戏这样的场景,该场景需要来自连接两端的大量消息。在这种情况下,WebSockets将压制SSE。
如果您的用例需要显示实时的市场新闻,市场数据,聊天应用程序等,例如在我们的案例中,依靠HTTP / 2 + SSE将为您提供有效的双向通信渠道,同时又能获得留在其中的好处HTTP世界。
如果您想为我们的用例获取示例客户端-服务器实现,请签出GitHub代码。
资源
“caniuse.com”
“使用服务器发送的事件进行流更新”,HTML5 Rocks的Eric Bidelman
“使用HTML5 SSE的数据推送应用”,O’Reilly Media的Darren Cook
感谢您阅读。如果您认为这篇文章很有用,请在您的圈子中分享。
原文:https://codeburst.io/polling-vs-sse-vs-websocket-how-to-choose-the-right-one-1859e4e13bd9
本文:https://pub.intelligentx.net/polling-vs-sse-vs-websocket-how-choose-right-one
讨论:请加入知识星球或者小红圈【首席架构师圈】或者小号【jiagoushi_pro】或者QQ群【11107777】
微信公众号 |
【首席架构师智库】 适合物业仔细反复阅读。 精彩图文详解架构方法论,架构实践,技术原理,技术趋势。 我们在等你,赶快扫描关注吧。 |
![]() |
微信小号 | 50000人社区,激烈深度讨论:企业架构,云计算,大数据,数据科学,物联网,人工智能,安全,全栈开发,DevOps,数字化. |
![]() |
QQ群 | 深度交流企业架构,业务架构,应用架构,数据架构,技术架构,集成架构,安全架构。以及大数据,云计算,物联网,人工智能等各种新兴技术。 |
|
视频号 |
【首席架构师智库】 1分钟快速了解架构相关的基本概念,模型,方法,经验。 每天1分钟,架构心中熟。 |
|
知识星球 | 向大咖提问,近距离接触,或者获得私密资料分享。 | 知识星球【首席架构师圈】 |
微信圈子 | 志趣相投的同好交流。 | 微信圈子【首席架构师圈】 |
喜马拉雅 | 路上或者车上了解最新黑科技资讯,架构心得。 | 【智能时刻,架构君和你聊黑科技】 |
知识星球 | 认识更多朋友,职场和技术闲聊。 | 知识星球【职场和技术】 |
谢谢大家关注,转发,点赞和在看。
「Web应用架构」轮询,SSE 和WebSocket,如何选择合适的?相关推荐
- 「首席看应用架构」轮询,SSE 和WebSocket,如何选择合适的?
构建实时Web应用程序有点挑战,我们需要考虑如何将数据从服务器发送到客户端.能够"主动"实现这一功能的技术已经存在了很长时间,并且仅限于两种通用方法:客户端请求或服务器请求. 实现 ...
- 触发器如何通知websocket_「Web应用架构」如何扩展WebSockets
当与那些还没有使用过WebSockets的开发人员交谈时,他们通常会有同样的担忧:如何将它扩展到多个服务器上? 发布到一台服务器上的通道是可以的,前提是所有订阅者都连接到那台服务器.一旦您有多个服务器 ...
- apache 配置 wss websocket打开握手超时_「Web应用架构」WebSocket介绍和WebSocket API
WebSocket支持在客户端和服务器之间双向的.面向消息的文本和二进制数据流.它是浏览器中最接近原始网络套接字的API.除了WebSocket连接也不仅仅是一个网络套接字,因为浏览器在一个简单的AP ...
- 「Web应用架构」模式:前端的后端(BFF)
面向用户界面和外部方的单用途边缘服务 介绍 随着web的出现和成功,交付用户界面的实际方式已经从厚客户端应用程序转变为通过web交付的界面,这一趋势也使基于SAAS的解决方案总体上得以发展.通过web ...
- 架构演进之「微服务架构」
"为什么要搞「微服务架构」"?这也是我们当初讨论的聚焦点.现在天天把"微服务"挂在嘴边的人很多,但是有多少人真正深入思考过"为什么",我认为 ...
- 渗透测试 | 几款常用的CMS识别「Web指纹识别」扫描脚本工具(含下载地址)
在对「靶标资产」进行渗透测试的前期,通常需要对「靶标资产」进行相关的信息收集,而对「靶标资产」进行Web指纹信息扫描也是信息收集当中很关键的一部分. 能否有效识别出「靶标资产」的Web指纹信息,主要还 ...
- 同事操作两个数据源保持事务一致_「微服务架构」微服务架构中的数据一致性...
在微服务中,一个逻辑上原子操作可以经常跨越多个微服务.即使是单片系统也可能使用多个数据库或消息传递解决方案.使用多个独立的数据存储解决方案,如果其中一个分布式流程参与者出现故障,我们就会面临数据不一致 ...
- 「RocketMQ技术专题」帮你梳理RocketMQ/Kafka的选择理由及二者PK
前提背景 大家都知道,市面上有许多开源的MQ,例如,RocketMQ.Kafka.RabbitMQ等等,现在Pulsar也开始发光,今天我们谈谈笔者最常用的RocketMQ和Kafka,想必大家早就知 ...
- 一文看懂当红Serverless:为何AWS、阿里云和腾讯云都在发力「无服务器架构」
冠望 发自 凹非寺 量子位 报道 | 公众号 QbitAI 要说目前软件架构中热度十二分的话题,当属Serverless. 通常我们会将其翻译为"无服务器架构". 尽管成天被称为& ...
最新文章
- R语言使用ggplot2包的快速可视化函数qplot绘制分组分组点图(带状图)实战
- php 分布式环境 启动,极简.高性能.分布式框架,可运行于多种环境(apache/php-fpm,swoole)...
- 多项目开发下的dll文件管理
- Linux内核模块开发常用内核接口
- LightSwitch社区资源搜集
- 中国塑料汽车外饰件市场趋势报告、技术动态创新及市场预测
- 百度地图API实现地理围栏
- Docker部署SpringCloud ELK+RabbitMQ日志
- Opencv 中的向量类Vec
- 能耗监测系统是干嘛的?
- 六:抽象队列同步器AQS应用之BlockingQueue详解
- 分省市县地理空间矩阵:地级市空间、地理距离矩阵等多指标数据集
- Facebook个人账号相关问题?
- Gradle系列之Zip打包
- 理想汽车事故,智能短板暴露-1
- Oracle集群管理-集群资源crsd异常启动案例,crsd资源offline
- java sleep唤醒_Java中的等待唤醒机制—至少50%的工程师还没掌握!
- ArcEngine简单教程——要素的属性查询、空间查询
- 如何将swf转换成MP4格式?视频转换器如何使用
- 机械制造计算机,机械制造计算机综合自动化是学什么的专业