服务端推送,也称为消息推送或通知推送,是一种允许应用服务器主动将信息发送到客户端的能力,为客户端提供了实时的信息更新和通知,增强了用户体验。

服务端推送的背景与需求主要基于以下几个诉求:

  1. 实时通知:在很多情况下,用户期望实时接收到应用的通知,如新消息提醒、商品活动提醒等。

  2. 节省资源:如果没有服务端推送,客户端需要通过轮询的方式来获取新信息,会造成客户端、服务端的资源损耗。通过服务端推送,客户端只需要在收到通知时做出响应,大大减少了资源的消耗。

  3. 增强用户体验:通过服务端推送,应用可以针对特定用户或用户群发送有针对性的内容,如优惠活动、个性化推荐等。这有助于提高用户对应用的满意度和黏性。

常见推送场景有:微信消息通知栏、新闻推送、外卖状态 等等,我们自身的推送场景有:下载、连线请求、直播提醒 …

一、解决方案:

1、传统实时处理方案:

轮询:这是一种较为传统的方式,客户端会定时地向服务端发送请求,询问是否有新数据。服务端只需要检查数据状态,然后将结果返回给客户端。轮询的优点是实现简单,兼容性好;缺点是可能产生较大的延迟,且对服务端资源消耗较高。

长轮询(Long Polling):轮询的改进版。客户端向服务器发送请求,服务器收到请求后,如果有新的数据,立即返回给客户端;如果没有新数据,服务器会等待一定时间(比如30秒超时时间),在这段时间内,如果有新数据,就返回给客户端,否则返回空数据。客户端处理完服务器返回的响应后,再次发起新的请求,如此反复。长轮询相较于传统的轮询方式减少了请求次数,但仍然存在一定的延迟。

2、HTML5 标准引入的实时处理方案:

WebSocket:一种双向通信协议,同时支持服务端和客户端之间的实时交互。WebSocket 是基于 TCP 的长连接,和HTTP 协议相比,它能实现轻量级的、低延迟的数据传输,非常适合实时通信场景,主要用于交互性强的双向通信。

SSE:SSE(Server-Sent Events)是一种基于 HTTP 协议的推送技术。服务端可以使用 SSE 来向客户端推送数据,但客户端不能通过SSE向服务端发送数据。相较于 WebSocket,SSE 更简单、更轻量级,但只能实现单向通信。

两者的主要区别:

3、第三方推送:

常见的有操作系统提供相应的推送服务,如苹果的APNs(Apple Push Notification service)、谷歌的FCM(Firebase Cloud Messaging)等。同时,也有一些跨平台的推送服务,如个推、极光推送、友盟推送等,帮助开发者在不同平台上实现统一的推送功能。

这种推送方式在生活中十分常见,一般你打开手机就能看到各种信息推送,基本就是利用第三方推送来实现。

二、SSE:

接下来我们重点讲讲 SSE 服务端推送,它基于 HTTP 协议,易于实现和部署,特别适合那些需要服务器主动推送信息、客户端只需接收数据的场景:

1、客户端:

Server-Sent Events(SSE)是 HTML5 的一部分,用于从服务器实时接收更新,目前大部分主流浏览器都提供了支持:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE Client</title>
</head>
    <h1>Receive: <span id="sse"></span></h1>
    <script>
        const numberElement = document.getElementById("sse");
        const source = new EventSource('http://localhost:8080/sse');
        source.onmessage = (event) => {
            numberElement.innerText = event.data;
        source.onerror = (error) => {
            console.error("SSE error:", error);
    </script>
</body>
</html>

自动重连:一旦连接断开,浏览器会自动尝试重新建立连接。当然,每个浏览器都有自己的重连策略和措施。因此,重连时间和尝试次数可能因浏览器而异。

也可以通过 CURL 调用:

➜  ~ curl -X GET -H  "Accept:text/event-stream" -H  "Content-Type:application/x-www-form-urlencoded" "http://localhost:8080/sse"
data:Data: 0
data:Data: 1
data:Data: 2
data:Data: 3

2、服务端:

我们目前服务端主要使用 Spring,其对 SSE 主要提供了两种支持:

  • Spring WebMVC:传统的基于 Servlet 的同步阻塞编程模型,即 同步模型Web框架。
  • Spring WebFlux:异步非阻塞的响应式编程模型,即 异步模型Web框架。

1)Spring WebFlux 中的 SSE 支持(支持版本Spring5.0):

Spring WebFlux 框架提供了一套基于响应式编程的非阻塞异步IO模型,能高效支持 SSE。在 Spring WebFlux 中,我们可以结合 Flux 和 MediaType.TEXT_EVENT_STREAM_VALUE 来实现 SSE。

以下示例展示如何在 Spring WebFlux 中创建 SSE 流:

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.Duration;
@RestController
public class SseController {
    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> getSseStream() {
        // 使用Flux生成每秒一个递增的数据流,用于模拟实时数据推送
        return Flux.interval(Duration.ofSeconds(1))
                .map(sequence -> "Data: " + sequence);

Spring WebFlux 底层依赖于两个非阻塞的异步框架: Reactor 和 Netty。其中,Reactor 库主要是提供响应式式编程的支持,Netty 是一个高性能的非阻塞网络框架,主要负责处理 HTTP 输入输出。

  • Reactor:Reactor 是一个基于 Java 8 的响应式流库,它实现了 Reactive Streams 规范。Reactor 提供了两个核心的响应式类型 - Mono 和 Flux,相当于 findOne 和 findList 的区别。这两个类型提供了丰富的操作符,允许你以声明式和函数式的方式来处理你的业务逻辑。
  • Netty:Netty 是一个高性能、异步的事件驱动的网络框架,虽然 Netty 重点在网络通信层,但仍然提供了 Web 服务器的能力。
    Reactor 对 Netty 进行了集成,提供了子模块 Reactor Netty,在 Spring WebFlux 中,Reactor Netty 主要用作默认的服务器运行时环境,负责处理 HTTP 请求和响应。

这两个框架共同为 Spring WebFlux 提供了底层的支持,使得我们能够使用响应式编程编写高性能、可扩展的Web应用程序。另外,虽然 Spring WebFlux 在底层默认使用 Reactor 和 Netty,但它也有很好的灵活性和可替换性,我们可以根据需要更换其他非阻塞的异步框架。

2)Spring WebMVC 中的 SSE 支持(支持版本Spring4.2):

在 Spring WebMVC 中,可以通过SseEmitter对象来处理 SSE 请求,它允许将数据通过 SSE 连接发送给客户端。

下面是一个使用SseEmitter提供 SSE 的简单示例:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RestController
public class SseController {
    private ExecutorService nonBlockingService = Executors.newCachedThreadPool();
    @GetMapping("/sse")
    public SseEmitter getSseStream() {
        SseEmitter emitter = new SseEmitter();
        nonBlockingService.execute(() -> {
            // 这里模拟数据发送给客户端的逻辑
            try {
                for (int i = 0; i < 10; i++) {
                    emitter.send("Data: " + i);
                    Thread.sleep(1000);
                emitter.complete();
            } catch (Exception ex) {
                emitter.completeWithError(ex);
        });
        return emitter;

如果你的项目使用 SpringMVC 模型,不想再引入 Spring WebFlux,能否利用 Reactor 响应式库呢?

答案也是可以的,虽然 SpringMVC 主要提供的是同步阻塞能力,但也不妨碍它提供一定的异步支持,比如这里,我们可以直接引入 Reactor 库,也同样可以实现 SSE:

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.Duration;
@RestController
public class SseController {
    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> getSseStream() {
        // 使用Flux生成每秒一个递增的数据流,用于模拟实时数据推送
        return Flux.interval(Duration.ofSeconds(1))
                .map(sequence -> "Data: " + sequence);

基于 Spring WebMVC 或 Spring WebFlux,我们可以方便地在 Spring 框架中实现 SSE 的支持。这两种方法根据具体需求和场景,可以灵活选择。

三、业务实践:

我们以「文件下载」功能进行说明,一般情况下,大文件的下载,服务端压力比较大、处理时间也比较长,为了有更好的交互体验,我们可以使用异步处理,服务端处理完了之后主动通知 客户端,效果如下:

这个小弹窗就是服务端处理完了之后,通过 SSE连接主动推送到客户端。

我们来看看处理流程:

1)SSE 连接:

先建立 SSE 连接,确保服务端有主动推送消息的能力。

2)异步下载:

长耗时下载任务我们通过异步的方式处理,避免用户在下载页面长时间等待。

3)广播并推送:

下载完成后,我们需要将完成事件推送给客户端。需要注意的是,由于服务是集群部署、SSE 连接在节点本地 Map 维护,这就有可能导致当前客户端的 SSE连接所在节点 与 事件推送节点 是两个独立的节点。

因此,我们这里借助于 Redis 的发布/订阅能力,将消息广播出去,能匹配连接的节点负责将消息推送至客户端、其他节点直接丢弃即可。效果图如下:

能否做到精准投递?

答案也是可以的,我们可以这样来做:

  • 借助 Redis 做中心存储,存储Map<用户,节点IP> 这样的映射关系。
  • 在推送消息之前,先通过映射关系找到该用户的SSE连接所在节点
  • 然后在通过 RPC调用 直接将消息投递到对应的服务节点,最后由该节点进行事件推送。

一般情况下,我们可以用「广播」这种简单粗暴的方式应对大部分场景,毕竟「精准投递」需要中心化的维护节点关系、应对节点变更等,处理起来稍显麻烦。具体视业务场景来做选择即可。

SSE 技术是一种轻量级的实时推送技术,具有支持跨域、使用简单、支持自动重连等特点,使得其在实时消息推送、股票交易等场景下广泛使用。

另外,SSE 相对于 WebSocket 更加轻量级,如果需求场景不需要交互式动作,那么 SSE 是一个不错的选择。

HTTP/2 协议-服务端主动推送消息 这篇文章介绍一下 HTTP/2 的服务端消息推送功能,它可以很大程度的提升客户的体验,它与之前介绍的 Websocket 消息推送有很大的不同,讨论一下 HTTP/2 协议中的 PUSH_PROMISE 服务端推送帧实现原理。 1.服务器推送的意义 提前将资源推送到浏览器 推送可以基于已发送的请求,例如客户端请求 html,服务端可以主动推送 js、css 文件 2.服务端推送的基本实现原理 推送资源必须对应一个请求 请求由服务端 PUSH_PROMISE 帧发
目录问题场景Server side event (SSE)简介在后端使用SSE功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入  在开发web项目时,有一个需求是:后端服务器要主动地、不断地推送消息给客户端网页。要实现该需
SSE简介 SSEServer-sent Events )是 WebSocket 的一种轻量代替方案,使用 HTTP 协议。 严格地说,HTTP 协议是没有办法做服务器推送的,但是当服务器向客户端声明接下来要发送流信息时,客户端就会保持连接打开,SSE 使用的就是这种原理。 SSEServer-Sent Events 的简称, 是一种服务器端到客户端(浏览器)的单项消息推送。 相比于 WebSocket,SSE 简单不少,服务器端和客户端工做量都要小不少、简单不少,同时实现的功能也有局限。
PHP SSE:服务器发送的事件 一个简单高效的库通过PHP实现了HTML5的服务器发送的事件,用于将事件从服务器实时推送到客户端,并且比Websocket更容易,而不是AJAX请求。 PHP 5.4或更高版本 通过Composer( )安装 composer require " hhxsv5/php-sse:~2.0 " -vvv 运行PHP Web服务器 cd examples php -S 127.0.0.1:9001 -t . 开启网址http://127.0.0.1:9001/index.html Javascript示范 客户端:从服务器接收事件。 // withCredentials=true: pass the cross-domain cookies to server-side const source = new EventSource (
SSE(Server-Sent Events):替代websocket完成服务器推送 提到服务端数据推送,你可以一下子就想到了Websocket,WebSocket是一种全新的协议,随着HTML5草案的不断完善,越来越多的现代浏览器开始全面支持WebSocket技术了,它将TCP的Socket(套接字)应用在了webpage上,从而使通信双方建立起一个保持在活动状态连接通道。 但你可能不知道,HTML5中有一个轻量的替代Websocket的方案:SSEServer-Sent Events)。
### 回答1: nacos-server-2.0.3.zip 是一个Nacos服务端的压缩包,可以用于安装和部署Nacos服务。Nacos是一个开源的分布式服务发现、配置管理和服务管理平台,可以帮助开发者更好地管理和维护微服务架构。如果你需要使用Nacos服务,可以下载并安装这个压缩包。 ### 回答2: nacos-server-2.0.3.zip是一个服务中心的命名空间和配置中心,由阿里巴巴公司开发和维护。它为用户提供了一个集中式的服务管理系统,其中包括服务注册和发现、配置管理、负载均衡等功能。用户可以在一个统一的平台上管理各种服务,包括云上的服务和本地的服务。同时,nacos还提供了强大的failover和容错能力,确保了服务的高可用性和稳定性。 nacos支持多种服务,包括Kubernetes、Mesos、DockerSwarm等云原生服务。它还提供了完整的RESTful API,可以通过API实现自动化操作,降低运维成本。同时,nacos还支持丰富的插件扩展,用户可以根据自身需求灵活增加或删除插件。 nacos-server-2.0.3.zip是nacos的最新版本,它修复了一些已知Bug,同时优化了一些性能问题。用户可以从官方网站上免费下载,并根据指南进行安装和配置。一旦成功安装,用户就可以开始使用nacos进行服务管理和配置管理,并获得以下优势: 1.服务发现:nacos提供了灵活的服务发现机制,可以轻松地找到需要的服务。 2.配置管理:用户可以在nacos上管理和维护所有的配置信息,包括数据库、服务URL等。 3.负载均衡:nacos提供了强大的负载均衡能力,可以平衡不同节点的负载,确保系统的稳定性。 4.自动化操作:nacos提供了RESTful API,可以通过API实现自动化操作,降低运维成本。 总之,nacos-server-2.0.3.zip是一个功能强大的服务中心,可以帮助用户轻松地管理和维护各种服务。它不仅简化了开发和运维工作,还提高了系统的可靠性和稳定性,是现代化应用开发中不可或缺的一部分。 ### 回答3: nacos-server-2.0.3.zip是一款开源的服务发现和配置管理平台。 服务发现是一种在分布式系统中识别可用服务实例的机制,因为当前的应用程序和微服务都趋于分布式,因此服务发现因而变得非常重要。而nacos-server-2.0.3.zip就是一种优秀的能够解决服务发现问题的解决方案,它通过注册中心的形式来管理和协调微服务架构中的各种服务。 除了服务发现,nacos-server-2.0.3.zip还能够管理服务的配置信息。在传统的微服务架构中,多个服务之间的调用需要依赖一些共同的配置,而nacos-server-2.0.3.zip能够提供一种便捷的配置管理方式。开发人员可以在nacos-server-2.0.3.zip的控制台上进行配置管理,而服务将会自动加载最新的配置。 nacos-server-2.0.3.zip还具有负载均衡能力,它可以通过负载均衡来实现微服务架构中的流量控制。同时,nacos-server-2.0.3.zip还支持多数据中心部署,可以在多个数据中心之间快速切换。 总之,nacos-server-2.0.3.zip是一款非常实用、易用、开源的微服务架构解决方案,它通过服务发现、配置管理和负载均衡等能力来协调和管理微服务架构中的各种服务。这款软件具有良好的扩展性和高可用性,适用于各种规模的企业级应用。
好问题。虽然CPU消耗是一个问题,但它不是最主要的问题,比如你是外卖员去店里面取餐,你是选择一直在哪儿等呢还是先去把旁边的几家餐先取了? 对应的就是同步阻塞和同步非阻塞的区别。 乍一看,同步非阻塞好像消耗更多的CPU,但是你想,很多 Redis 这种系统,在处理网络连接这些模块的时候,会有很多线程来跑吗?所以,处理网络模块的时候,最主要的问题是要考虑每个线程(进程)的最高利用率
深入分析redis之listpack,取代ziplist? 好问题。不过需要注意的是,ziplist、quicklist、listpack 主要解决的问题是 “如何高效的利用内存(压缩)”。所以,你会看到,上层类型比如 zset、stream 底层都会选用多种结构组合使用,而使用规则就是根据数据量的大小来判断 Feign 应用之 RequestInterceptor 拦截器,超实用指南 看不懂就多看两遍,最基本的思想都讲了。别人的博客只是参考,辅助你理解,有任何疑问可以说清楚具体问题,而不是在这里喷,有什么意思?