0

    数据不够实时:试试长连接?

    2023.06.03 | admin | 151次围观

    短 轮询 (polling)

    短轮询可能是我们用的最多的一种实时刷新数据的方式了,我们在讲轮询方案时,大部分指的就是短轮询,其实现方式和普通的接口无异,改造也只要前端增加定时器或useRequest配置轮询参数即可,其原理也非常简单,如下图,如果是http1.1及以上,TCP连接可以复用,当然http1.0及以下也是可以使用,但消耗会更多。短轮询的特点就是接口请求立即会返回谷歌浏览器网页响应时间过长,每次请求都可以理解为是一次新的请求。

    image.png

    短 轮询 的优缺点

    短轮询最大的优点就是简单,前端设置时间间隔,定时去请求数据,而服务端只需同步的查询数据返回即可,但缺点也显而易见:

    无用请求过多:从下图可以看出,每隔固定时间,一定有请求发出,且每次接口可能返回一样的数据或返回空结果,服务端会重复查询数据库、前端会重复重渲染

    实时性不可控,如数据更新了,但轮询请求刚结束一轮,会造成轮询间隔内数据都得不到更新

    长 轮询 (long polling)

    看完了上面关于短轮询的介绍,我们知道了轮询有两个主要的缺陷:一个是无用请求过多,另外一个是数据实时性不可控。为了解决这两个问题,于是有了更进一步的长轮询方案。

    image.png

    在上图中,客户端发起请求后,服务端发现当前没有新的数据,这个时候服务端没有立即返回请求,而是将请求挂起,在等待一段时间后(一般为30s或者是60s,设置一个超时返回主要是为了考虑过长的无数据连接占用会被网关或者某层中间件断开甚至是被运营商断开),如发现还是没有数据更新的话,就返回一个空结果给客户端。客户端在收到服务端的回复后,立即再次向服务端发送新的请求。这次服务端在接收到客户端的请求后,同样等待了一段时间,这次好运的是服务端的数据发生了更新,服务端给客户端返回了最新的数据。客户端在拿到结果后再次发送下一个请求,如此反复。

    长 轮询 的优缺点

    长轮询很完美地解决了短轮询的问题,首先服务端在没有数据更新的情况下没有给客户端返回数据,所以避免了客户端大量的重复请求。再者客户端在收到服务端的返回后,马上发送下一个请求,这就保证了更好的数据实时性。不过长轮询也有缺点:

    从上面的描述来看,长轮询的次数和时延似乎可以更少,那是不是长轮询更好呢?其实不是的,这个两种轮询方式都有优劣势和适合的场景。

    短 轮询 ,长轮询怎么选?

    长 轮询多用于操作频繁,点对点的通讯,而且连接数不能太多情况,每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

    而像WEB网站的http服务一般都用短 轮询谷歌浏览器网页响应时间过长,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。

    长连接WebSocket

    上面说到长轮询不适用于服务端资源频繁更新的场景,而解决这类问题的一个方案就是WebSocket。用最简单的话来介绍WebSocket就是:客户端和服务器之间建立一个持久的长连接,这个连接是双工的,客户端和服务端都可以实时地给对方发送消息。下面是WebSocket的图示:

    image.png

    WebSocket对于前端的同学来说是非常常见了,因为无论是webpack还是vite,用来HMR的reload就是通过WebSocket来进行的,有代码改动,工程重新编译,新变更的模块通知到浏览器加载新的模块,这里的通知浏览器加载新模块就是通过WebSocket的进行的。如上图,通过握手(协议转换)建立连接后,双方就保持持久连接,由于历史的关系,WebSocket建立连接是依赖HTTP的,但是其建连请求有明显的特征,目的是客户端和服务端都能识别并保持连接。

    请求特征

    请求头特征

    响应头特征

    数据不够实时:试试长连接?

    兼容性

    WebSocket 协议在2008年诞生,2011年成为国际标准。现在所有浏览器都已经支持了。

    实现一个简单的 WebSocket

    基于原生WebSocket我们实现一个简单的长连。

    连接

    // 连接只需实例一个WebSocket
    const ws = new WebSocket(`wss://${url}`);

    发送消息

     ws.send("这是一条消息:" + count);

    监听消息

    ws.onmessage = function (event) {
    console.log(event.data);
    }

    关闭连接

    ws.close();

    在工程上使用WebSocket

    在工程上,很少直接基于原生WebSocket实现业务需求,使用WebSocket需要完成下面几个问题:

    服务端推送(SSE)

    SSE全称Server-sent Events,是HTML 5 规范的一个组成部分,该规范十分简单,主要由两个部分组成:第一个部分是服务器端与浏览器端之间的通讯协议,第二部分则是在浏览器端可供 JavaScript 使用的 EventSource 对象。通讯协议是基于纯文本的简单协议。服务器端的响应的内容类型是“text/event-stream”。响应文本的内容可以看成是一个事件流,由不同的事件所组成。每个事件由类型和数据两部分组成,同时每个事件可以有一个可选的标识符。不同事件的内容之间通过仅包含回车符和换行符的空行(“rn”)来分隔。每个事件的数据可能由多行组成。

    image.png和 Websocket对比

    SSEWebSocket

    单向:仅服务端能发送消息

    双向:客户端、服务端双向发送

    仅文本数据

    二进制、文本都可

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论