什么是RSocket?它有哪些优势?

在传统Web应用开发过程中,我们都是基于HTTP协议实现请求-响应式的交互方式。这种交互方案很简单,但不够灵活,也无法应对所有的响应式应用场景。那么,有没有在网络协议层上提供更加丰富的交互方式呢?答案是肯定的,这就是我们本文要讨论的RSocket协议。

RSocket协议

在引入RSocket协议之前,我们先来讨论为什么需要这样一个协议的背景,让我们从传统的请求-响应模式的问题开始说起。

请求-响应模式的问题

我们知道常用的HTTP 协议的优势在于其广泛的适用性,有非常多的服务器和客户端实现的支持,但 HTTP 协议本身比较简单,只支持请求-响应模式。而这种模式对于很多应用场景来说是不合适的。典型的例子是消息推送,以 HTTP 协议为例,如果客户端需要获取最新的推送消息,就必须使用轮询。客户端不停的发送请求到服务器来检查更新,这无疑造成了大量的资源浪费。请求-响应模式的另外一个问题是,如果某个请求的响应时间过长,会阻塞之后的其他请求的处理。

虽然服务器发送事件(Server-Sent Events,SSE)可以用来推送消息,不过 SSE 是一个简单的文本协议,仅提供有限的功能。此外,WebSocket 可以进行双向数据传输,但由于连接造成的服务之间的紧密耦合,WebSocket的使用不符合响应式系统要求,因为协议不提供控制背压的可能性,而背压是回弹性系统的重要组成部分。

事实上,响应式编程的实施目前主要有两个障碍,一个是关系型的数据访问,另一个就是网络协议,幸运的是,响应式流规范背后的团队理解了跨网络、异步、低延迟通信的必要性。在2015年中,RSocket协议就在这样的背景下诞生了。

RSocket协议与交互模式

Socket是一种新的第7层语言无关的应用网络协议,用来解决单一的请求-响应模式以及现有网络传输协议所存在的问题,提供Java,JavaScript,C++和Kotlin等多种语言的实现版本。

RSocket RSocket是一个二进制的协议,以异步消息的方式提供4种交互模式,除了请求-响应(request/response)模式之外,还包括请求-响应流(request/stream)、发后不管(fire-and-forget)和通道(channel)这三种新的交互模式。

  1. 请求-响应模式:这是最典型也最常见的模式。发送方在发送消息给接收方之后,等待与之对应的响应消息。
  2. 请求-响应流模式:发送方的每个请求消息,都对应于接收方的一个消息流作为响应。
  3. 即发即忘模式:发送方的请求消息没有与之对应的响应。
  4. 通道模式:在发送方和接收方之间建立一个双向传输的通道。

RSocket专门设计用于与响应式风格应用配合使用,在使用RSocket协议时,背压和流量控制仍然有效。

为了更好的理解RSocket协议,让我们将它与HTTP协议做一个对比。我们知道Servlet基于HTTP协议之上的是一套Java API规范,将HTTP请求转化为一个ServletRequest对象,并将处理结果封装成一个ServletResponse对象进行返回。HTTP协议为了兼容各种应用方式,本身有一定的复杂性,性能一般。而RSocket采用的是自定义二进制协议,本身的定位就是高性能通讯协议,性能上比HTTP高出一个数量级。

在交互模式上,与HTTP的请求-响应这种单向的交互模式不同,RSocket倡导的是对等通讯,不再使用传统的理解是客户端-服务器端改进,而是在两端之间可以自由的相互发送和处理请求。RSocket协议在交互方式上可以参考下图:


使用RSocket实现远程交互

想要在应用程序中使用RSocket协议,我们需要引入如下依赖:

<dependency>

    <groupId>io.rsocket</groupId>

    <artifactId>rsocket-core</artifactId>

</dependency>

<dependency>

    <groupId>io.rsocket</groupId>

    <artifactId>rsocket-transport-netty</artifactId>

</dependency>

可以看到这里使用了rsocket-transport-netty包,该包的底层实现就是Reactor Netty组件,支持TCP 和 WebSocket协议。如果你想使用UDP协议,那么可以引入rsocket-transport-aeron包。

RSocket接口

我们先来看一下RSocket协议中最核心的接口,即RSocket接口的定义,如下所示:

import org.reactivestreams.Publisher;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

public interface RSocket extends Availability, Closeable {

    

//推送元信息,数据可以自定义

Mono<Void> metadataPush(Payload payload);

    //请求-响应模式,发送一个请求并接收一个响应。该协议也比 HTTP 更具优势,因为它是异步且多路复用的

Mono<Payload> requestResponse(Payload payload);

    //即发-即忘模式,请求-响应的优化,在不需要响应时非常有用

    Mono<Void> fireAndForget(Payload payload);

   

    //请求-响应流模式,类似于返回集合的请求/响应,集合将以流的方式返回,而不是等到查询完成

    Flux<Payload> requestStream(Payload payload);

    //通道模式,允许任意交互模型的双向消息流

    Flux<Payload> requestChannel(Publisher<Payload> payloads);    

}

显然,RSocket接口通过四个方法分别实现了它所提供的四种交互模式,其中requestResponse方法返回的是一个Mono<Payload>对象,这里的Payload代表的就是一种消息对象,由两部分组成,元信息metadata和数据data,类似于常见的消息通信中的消息头和消息体的概念。

然后,我们发现fireAndForget方法返回的是一个Mono<Void>流,符合即发-即忘模式的语义。而requestStream作为请求-响应流模式的实现,与requestResponse的区别在于它的返回值是一个Flux流,而不是一个Mono对象。最后,我们注意到这几个方法的输入都是一个Payload消息对象,而不是一个响应式流对象。但requestChannel方法就不一样了,它的输入同样是一个代表响应式流的Publisher对象,意味着这种模式下的输入输出都是响应式流,也就是说可以进行客户端和服务器端之间的双向交互。

在rsocket-core包中,针对RSocket接口提供了一个抽象的实现类AbstractRSocket,对上述方法做了简单的实现封装,在具体使用过程中,我们可以基于这个AbstractRSocket类来具体提供某一个交互模式的实现逻辑,而不需要完成实现RSocket接口中的所有方法。

使用RSocket的交互模式

这里以最常见的请求-响应交互模式为例,给出使用RSocket协议的使用方法。与使用HTTP协议一样,这个过程需要构建服务器端和客户端,并通过客户端来发起请求。

我们先来看如何构建RSocket服务器端,示例代码如下所示:

    RSocketFactory.receive()

        .acceptor(((setup, sendingSocket) -> Mono.just(

            new AbstractRSocket() {

              @Override

              public Mono<Payload> requestResponse(Payload payload) {

                return Mono.just(DefaultPayload.create("Hello: " + payload.getDataUtf8()));

              }

            }

        )))

        .transport(TcpServerTransport.create("localhost", 7000))

        .start()

        .subscribe();

这里的RSocketFactory.receive()方法返回用来创建服务器的 ServerRSocketFactory 类的对象。ServerRSocketFactory 的acceptor()方法的参数是 SocketAcceptor 接口。上述代码中,我们用到了前面介绍的RSocket抽象实现类AbstractRSocket,重写了其中的requestResponse()方法,对输入的参数前面添加一个"Hello: "前缀并返回。接下来的transport()方法指定ServerTransport接口的实现类TcpServerTransport作为 RSocket 底层的传输层实现,显然,我们监听本地服务器上的7000端口。最后,通过 start().subscribe()来触发整个启动过程。

构建完服务器端,我们来构建客户端组件,如下所示:

    RSocket socket = RSocketFactory.connect()

        .transport(TcpClientTransport.create("localhost", 7000))

        .start()

        .block();

RSocketFactory.connect() 方法用来创建 RSocket 客户端,返回 ClientRSocketFactory 类的对象。接下来的 transport() 方法指定传输层 ClientTransport 实现 。和服务器端组件TcpServerTransport对应,这里使用的是TcpClientTransport来连接本地服务器上的7000端口。最后调用start().block()方法等待客户端启动并返回RSocket对象。

现在,我们就可以使用RSocket的requestResponse()方法来发送请求并获取响应了,如下所示:

    socket.requestResponse(DefaultPayload.create("World"))

        .map(Payload::getDataUtf8)

        .doOnNext(System.out::println)

        .doFinally(signalType -> socket.dispose())

        .then()

        .block();

我们可以使用DefaultPayload.create()方法来简单地创建 Payload 对象,然后通过RSocket 类的 dispose() 方法用来销毁该对象。这样,整个调用过程就结束了。执行这次请求,我们会在控制台上获取“Hello: World”。

RSocket与框架集成

通常,我们不会直接使用RSocket开发库进行应用程序的开发,而是借助于特定的开发框架。在Java领域中,Spring Boot、Spring Cloud以及Dubbo等主流开发框架都集成了RSocket协议。

集成RSocket与Spring框架

想要在Spring Boot中使用RSocket协议,我们需要引入如下依赖:

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-rsocket</artifactId>

</dependency>

然后,我们同样先来构建一个请求-响应式交互方式。我们可以构建如下所示一个简单Controller:

@Controller

public class HelloController {

  @MessageMapping("hello")

  public Mono<String> hello(String input) {

    return Mono.just("Hello: " + input);

  }

}

注意到这里引入了一个新的注解@MessageMapping,跟@RequestMapping注解类似,@MessageMapping是Spring中提供用来指定WebSocket、RSocket等协议中消息处理的目的地。然后,我们输入了一个String类型的参数并返回一个Mono对象,符合请求-响应相互模式的定义。

为了访问这个RSocket端点,我们需要构建一个RSocketRequester对象,构建方式如下所示:

@Autowired

RSocketRequester.Builder builder;

RSocketRequester requester = builder.dataMimeType(MimeTypeUtils.TEXT_PLAIN)

        .connect(TcpClientTransport.create(7000)).block();

基于这个RSocketRequester对象,我们就可以通过它的route方法路由到前面通过@MessageMapping注解构建的"hello"端点,如下所示:

Mono<String> response = requester.route("hello")

        .data("World")

        .retrieveMono(String.class);

我们再来看一个请求-响应流的示例,如下所示:

@MessageMapping("stream")

Flux<Message> stream(Message request) {

        return Flux

                .interval(Duration.ofSeconds(1))

                .map(index -> new Message(request.getParam, index));

}

这里我们根据输入的Message对象,返回一个Flux流,每一秒发送一个添加了Index的新Message对象。

集成RSocket与其他框架

针对其他开发框架,Dubbo 在 3.0.0-SNAPSHOT 版本里基于 RSocket 对响应式编程提供了支持,开发人员可以非常方便的使用RSocket的API。而随着Spring框架的持续升级,5.2版本中也把RSocket作为缺省的通讯协议。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/12088.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Alibaba SpringCloud集成Nacos、Sentinel实现服务治理-17

关于服务治理 总体而言&#xff0c;限流和降级作为微服务架构中的重要机制&#xff0c;尽管在实现上可能有多种方式&#xff0c;但它们都着眼于保护服务提供者和消费者&#xff0c;在面对异常情况时确保系统稳定运行。限流关注于保护服务提供者&#xff0c;控制请求流量&#…

【linux系统学习教程 Day02】网络安全之Linux系统学习教程,管道,文件内容统计,过滤排序,去重,目录介绍

1-4 管道 管道符号&#xff1a; | &#xff0c;可以将前面指令的执行结果&#xff0c;作为后面指令的操作内容。 ## 比如过滤ip地址 ip addr | tail -4 | head -1 解释一下就是先执行 ip addr ,得到的结果当做 tail -4 的输入&#xff0c;意思就是查看ip addr 结果的后四行内容…

基于NIOS-II软核流水灯实现

文章目录 一、创建工程二、系统设计1. 在 “component library” 标签栏中找到 “Nios II Processor” 后点击 Add2. 在 ”Component Library” 标签栏中的查找窗口输入 jtag 找到 ”JTAG UART ”&#xff0c;然后点击 Add3. 添加片上存储器 On-Chip Memory(RAM)核4. 查找窗口输…

如何创建和运营新版Facebook粉丝专页

在众多平台中&#xff0c;Facebook粉丝专页无疑是连接全球消费者、扩展品牌影响力的重要工具。如果你是初次接触Facebook粉丝专页&#xff0c;可能会感到有些迷茫——毕竟&#xff0c;只是听说过它的好处&#xff0c;却不知道如何开始。 Facebook粉丝专页不仅是一个分享产品信…

使用Docker创建verdaccio私服

verdaccio官网 1.Docker安装 这边以Ubuntu安装为例Ubuntu 安装Docker​&#xff0c;具体安装方式请根据自己电脑自行搜索。 2.下载verdaccio docker pull verdaccio/verdaccio3.运行verdaccio 运行容器&#xff1a; docker run -it -d --name verdaccio -p 4873:4873 ver…

unordered_map、unordered_set底层封装

文章目录 一、先实现哈希桶1.1哈希桶的实现方法1.2日常普遍的哈希桶存放的数据有两种&#xff1a;字符串和整形1.3哈希桶的实现代码详解1.3.1哈希桶的两种仿函数&#xff08;int和string&#xff09;1.3.2哈希桶的节点&#xff08;如果桶非常深&#xff0c;这里考虑挂红黑树&am…

苹果M4芯片:大模型本地运算的转折点

在人工智能和机器学习领域&#xff0c;大模型的兴起对硬件提出了前所未有的挑战。苹果公司最近推出的M4芯片&#xff0c;被视为其在这场竞赛中的“第一式”。本文将探讨M4芯片的特点&#xff0c;并与其他芯片进行比较。 M4芯片的亮点 Neural Engine算力&#xff1a;M4芯片的…

Samtec技术分享 | 电源/信号高密度阵列的新视角

【摘要/前言】 “角度”&#xff0c;这个词每天都出现在我们的生活中&#xff0c;有物理学的角度&#xff0c;如街边的拐角&#xff0c;还有视觉上的角度和观点中的角度~ Samtec新型 AcceleRate mP 高密度电源/信号互连系统正是从电源完整性 90度旋转的不同角度中诞生的。 …

深度学习之激活函数——Tanh

Tanh 双曲正切1函数(tanh)&#xff0c;其图像与sigmoid函数十分相近&#xff0c;相当于sigmoid函数的放大版。在实际的使用中&#xff0c;tanh函数要优先于sigmoid函数。 函数表达式 t a n h e x − e − x e x e − x tanh\frac{e^x-e^{-x}}{e^xe^{-x}} tanhexe−xex−e−…

Git大文件无法直接push用git lfs track 上传大文件具体操作

Git 因为大文件push失败 回退到git add前用git lfs track单独添加大文件 以下work flow仅代表个人解决问题的办法&#xff0c;有优化流程的欢迎交流 回退到git add前 以下指令回退一个commit git reset --soft HEAD~1以下指令撤销所有git add操作&#xff0c;但不删除本地修…

数字绘画教学实训解决方案

一、建设背景 1.1政策背景 教育信息化政策推动&#xff1a;近年来&#xff0c;随着教育信息化政策的不断推动&#xff0c;各级教育部门纷纷出台相关政策&#xff0c;鼓励和支持教育信息化的发展。数字绘画作为现代艺术教育的重要组成部分&#xff0c;其教学实训解决方案的建设…

Netgear无线路由器漏洞复现(CVE-2019-20760)

漏洞概述 漏洞服务&#xff1a; uhttpd 漏洞类型&#xff1a; 远程命令执行 影响范围&#xff1a; 1.0.4.26之前的NETGEAR R9000设备会受到身份验证绕过的影响 解决建议&#xff1a; 更新版本 漏洞复现 操作环境&#xff1a; ubuntu:22.04 qemu-version&#xff1a; 8.1…

【JVM】从三种认知角度重识JVM

目录 JVM概述 JVM主要功能 虚拟机是Java平台无关的保障 JVM概述 JVM&#xff1a;Java Virtual Machine,也就是Java虚拟机。 虚拟机&#xff1a;通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的计算机系统&#xff08;物理上不存在&#xff09;。 JVM通…

聊聊ChatGPT:智能语言模型背后的原理

目录 1. ChatGPT的基础&#xff1a;GPT模型 2. 预训练与微调&#xff1a;让模型更加智能 2.1 预训练 2.2 微调 3. 多样化的应用场景 4. 未来的展望 5. 结语 在当今的人工智能领域&#xff0c;OpenAI的ChatGPT无疑是一个炙手可热的话题。它不仅能流畅地进行对话&#xff…

一键批量合并视频:掌握视频剪辑技巧解析,轻松创作完美影片

在数字时代的浪潮下&#xff0c;视频已成为人们记录和分享生活的重要工具。然而&#xff0c;对于许多非专业视频编辑者来说&#xff0c;将多个视频片段合并成一个完整的影片却是一项复杂且耗时的任务。幸运的是&#xff0c;云炫AI智剪一键批量合并视频功能的出现&#xff0c;让…

ICode国际青少年编程竞赛- Python-5级训练场-综合练习5

ICode国际青少年编程竞赛- Python-5级训练场-综合练习5 1、 a 16 for i in range(6):Dev.step(1)Dev.turnLeft()Dev.step(a)Dev.step(-a)Dev.turnRight()while Dev.energy < 100:wait()Dev.step(1)a a - 5 i2、 for i in range(5):Dev.step(11 - i * 2)Dev.turnRight()wh…

人工智能中的概率魔法:解锁不确定性的智慧之钥

在人工智能&#xff08;AI&#xff09;的广阔天地中&#xff0c;概率论以其独特的魅力&#xff0c;成为了连接现实世界与智能决策的桥梁。从语音识别到图像识别&#xff0c;从自然语言处理到机器翻译&#xff0c;从智能推荐到自动驾驶&#xff0c;概率论知识在这些领域中发挥着…

高低温试验箱型号怎么选择?多禾试验带你一起探索

高低温试验箱在工业和科学研究当中扮演着至关重要的角色。无论是在电子、汽车、医疗器械还是航空航天领域&#xff0c;都需要对产品在不同温度条件下的性能进行测试。然而&#xff0c;在进行选择适合自己需求的高低温试验箱型号时&#xff0c;面对市场上琳琅满目的设备&#xf…

给定两点所能得到的数学关系

给定两点所能得到的数学关系 正文 正文 这里介绍一个基础问题&#xff0c;如果给定平面上的两个点的坐标&#xff0c;那么它们之间能够得到什么数学关系呢&#xff1f; ω arctan ⁡ y 1 − y 0 x 1 − x 0 x 1 − x 0 d cos ⁡ ω y 1 − y 0 d cos ⁡ ω d ( x 1 − x…

GIT基础01 基础命令与分支

前言 我们知道git是开发中比较常见的版本控制工具 我们可以先提出一个场景: 老板让你去修改方案 第一次修改 打回 第二次修改 打回 第n次修改 老板让你使用第一次的版本 阁下如何应对??? 我对每个版本进行编号?? 是一种方案 但是这里也是有缺陷的 比如说在很多版本中找…