浅谈RSocket与响应式编程

简介: RSocket是高效一个二进制的网络通讯协议,能够满足很多场景下使用。另外,RSocket也是一个激进的响应式捍卫者,激进到连API都跟响应式无缝集成。本文我们将和大家分享RSocket与响应式编程。

image.png

作者 | 素渡
来源 | 阿里技术公众号

一 RSocket的主要特性

首先,RSocket是高效一个二进制的网络通讯协议,能够满足很多场景下使用。其次,RSocket是一个激进的响应式捍卫者,激进到连API都跟响应式无缝集成。

1 四种通讯模式

即发即忘FireAndForget

立即发送一个请求,无需为这个请求发送响应报文。适用于监控埋点,日志上报等,这种场景下无需回执,丢失几个请求无伤大雅。

image.png

请求响应RequestResponse

请求方发送一条请求消息,响应方收到请求后并返回一条响应消息。传统的HTTP是典型的RequestResponse。

image.png

流RequestStream

请求方发送一个请求报文,响应方发回N个响应报文。传统的MQ是典型的RequestStream。

image.png

通道RequestChannel

创建一个通道上下文,双方可以互相发送消息。IM是个典型的RequestChannel通讯场景。

image.png

2 双向通讯Bi-Directional

RSocket的Client连接到Server,这个过程称为Setup,在连接成功后,会约定收发消息的方向逻辑:

  • 当Client请求Server时,发送的请求ID永远为奇数
  • 当Server请求Client时,发送的请求ID永远为偶数

image.png

正是因为这个奇偶性确定方向的特性,不同于传统的如HTTP请求,RSocket可以做到双向请求。

3 其他

  • 二进制协议,紧凑高效
  • 多路复用
  • 基于帧(Frame)的背压,与ReactiveStreams语义契合
  • 灵活的传输层切换: TCP/UDP/WebSocket等
  • 支持Cancel、断点续传、租约等高级特性

综上与HTTP做一些比较,RSocket的效率更高,支持的通讯场景更丰富,也没有队头阻塞的问题。与SocketIO这种基于纯事件的框架相比,RSocket的请求具有很清晰的上下文,API精炼易用。

image.png

二 RSocket的内部实现

1 帧的设计

帧(Frame)是RSocket协议报文的最小单位。

  • 一个帧由6 bytes的Header和剩余的Body构成,其中Header的4 bytes表示 StreamID,6 bits表示Frame Type, 10 bits作为Flags。Body根据不同的帧类型,结构也不同,常用的带Payload的帧一般会包括Metadata和Data两个部分。
  • 传输层如果本身不支持分帧特性的(如TCP),那么RSocket会用3 bytes的uint24表示帧长度,所以最大的帧大小是16MB。
  • 如果帧超出16MB,RSocket支持帧分裂重组,也就是拆成更小的帧,接收端再自动重组。

image.png

2 数据载体——Payload

基于帧之上,一般开发者接触到的是Payload, 它类似一个HTTP报文,可以是一个Request,也可以是一个Response。由两个二进制部分组成:

  • Metadata——元数据,类似HTTP的header
  • Data——数据,类似HTTP的body

image.png

3 架构

这里基于笔者在实现Golang版SDK的基础上整理的架构图,Java版基本也类似。

image.png

  • Transport层将网络二进制流编解码为Frames。
  • RSocket支持自定义最大Frame Size,默认16MB,当某个Frame超出时,会被拆解为N个小Frame,收到时再重组,在介绍帧的时候也提到了,这个特性称为Fragmentation。
  • DuplexConnection转换Frames为Payload,抽象为一个个Request/Response上下文,并负责读写。
  • RSocket组装Connection为RSocket Interface,其中Resumable支持断点续传,连接断开重连也能自愈,个人觉得这个特性有点鸡肋,在弱网环境有些优势,但是因为期间会缓存住未处理完毕的帧,所以会耗费大量的系统资源。
  • RSocket使用Reactor核心库暴露为4种通讯模式,抽象为高级API。

4 玩法

RSocket有很多玩法,传统的RPC自然不在话下,用来做IM也未尝不可,某些特性也可以用来做代理或者网络穿透。

IoT的场景,比如小明的家里有个智能空调,小明想在外面通过手机APP来控制空调开关,如何优雅地描述这个控制问题?最精炼的解决方案就是"小明调用空调上开关的API"。

image.png

另外最经典的玩法就是Broker了,Broker类似一种“软路由”的方案,可以让服务的发布访问变得简单。发布服务只要连接到Broker,调用方通过反向请求的方式来让Broker透明转发即可,摒弃了传统的注册中心,端口管理等常见的服务治理手段。

image.png

5 关于RSocket Broker

Broker有很多优势,发布服务不需要监听端口,无需Sidecar,服务注册变得简单,无需zk、etcd之类,LoadBalance变得简单,也更安全,没监听端口后很难攻击。也有很多劣势,网络上多了一跳,性能是有一定损耗的,Broker是中心化设计,类似我们平时全局的Nginx一样,但是Broker的优雅启停显然更加复杂,受限于整个Broker集群的瓶颈等等。上帝为你关闭了一扇门,就一定会为你打开一扇窗。

目前高德落地的FaaS中大量使用了基于RSocket架构的集团Broker,支撑了今年的五一长假,峰值QPS超20万,平稳零故障。

image.png

这里笔者也准备了一个教学用的Mini Broker,演示了两个浏览器之间相互上下文调用彼此服务的场景,有兴趣的同学可以查看。

image.png

三 响应式编程

响应式编程是个老话题了,它早已无处不在,甚至你在Excel里SUM求和,本质上也是种响应式的思维。响应式本质上就是响应变化的数据流。RSocket这个协议本身就是以响应式之名,将其扩展到网络层面。

1 响应式编程大概长这样

image.png

而在我们平时工作中,必然会引入各种操作和变换:

image.png

2 Reactive Streams

JDK推出了响应式标准API,撇开Processor之外,其核心接口就Publisher/Subscriber/Subscription,非常精炼。

  • Publisher:发布者,负责生产数据。唯一的方法subscribe,接收一个Subscriber开始一次新的订阅。
  • Subscriber:订阅者,负责订阅消费数据。
  • Subscription:订阅,某次订阅的上下文控制,如取消、通知获取下N条数据。

Spring的Reactor是一个标准的实现,其一次完整的执行过程如下图:

image.png

  • 创建subscriber,开始订阅Publisher。
  • 生成上下文subscription。
  • Publisher就绪,调用onSubscribe。
  • Publisher开始生产数据。
  • 每条成功生产的数据回调onNext。
  • 当生产失败时,回调onError并结束当前订阅。
  • 当所有数据生产完毕时,回调onComplete并结束当前订阅。
  • 中途可以调用subscription随时cancel取消订阅,或者通过request(n)通知生产下N个元素,这个过程即背压。

由于Java天生的语言优势,很适合使用RxJava或Reactor之类的框架,代码逻辑清晰可读性会非常高。笔者在实现Go版的Reactor时,深深地体会到了没有泛型支持的API表现力是多么匮乏,也期待Go2的泛型能够有所改善。

四 总结

RSocket是个很有趣的网络协议,它可能不会普及流行,但贵在它解决问题的思路和设计很令人耳目一新。如果大家有兴趣,可以去它的官网了解下。

本文总结了笔者在实现Go和Rust版RSocket SDK过程中的一些心得感悟,有兴趣的同学可查看相关链接。

相关链接
https://github.com/jjeffcaii/rsocket-minibroker
https://github.com/rsocket/rsocket-go
https://github.com/rsocket/rsocket-rust

技术公开课

《HaaS物联网云端一体低代码开发课程》

由阿里云IoT一线技术专家精心打磨,直击当前物联网领域学习痛点,由浅入深全方位介绍物联网基础知识和网络层基础知识,帮助开发者建立物联网感知层、传输层、平台层及应用层各层的功能概念,并深入学习如何使用HaaS进行端云一体开发以及低代码开发新模式。

点击这里,开始学习吧~

相关实践学习
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
相关文章
langchain 入门指南 - 使用 Agent
langchain 入门指南 - 使用 Agent
404 0
|
Web App开发 算法 Java
JSON Web Token (JWT)生成Token及解密实战。
昨天讲解了JWT的介绍、应用场景、优点及注意事项等,今天来个JWT具体的使用实践吧。 从JWT官网支持的类库来看,jjwt是Java支持的算法中最全的,推荐使用,网址如下。
3779 0
|
12月前
|
前端开发 Java C++
RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器
本文介绍了在 Spring Boot 3.3 中使用 RSocket 和 WebSocket 实现实时通信的方法。RSocket 是一种高效的网络通信协议,支持多种通信模式,适用于微服务和流式数据传输。WebSocket 则是一种标准协议,支持全双工通信,适合实时数据更新场景。文章通过一个完整的示例,展示了如何配置项目、实现前后端交互和消息传递,并提供了详细的代码示例。通过这些技术,可以大幅提升系统的响应速度和处理效率。
|
5月前
|
SQL 数据库 开发者
Python中使用Flask-SQLAlchemy对数据库的增删改查简明示例
这样我们就对Flask-SQLAlchemy进行了一次简明扼要的旅程,阐述了如何定义模型,如何创建表,以及如何进行基本的数据库操作。希望你在阅读后能对Flask-SQLAlchemy有更深入的理解,这将为你在Python世界中从事数据库相关工作提供极大的便利。
509 77
|
安全 API 数据库
langchain 入门指南 - 函数调用
langchain 入门指南 - 函数调用
437 1
|
9月前
|
网络协议 C# 开发工具
C#中简单Socket编程
1. 先运行服务器代码。服务器将开始监听指定的IP和端口,等待客户端连接。 1. 然后运行客户端代码。客户端将连接到服务器并发送消息。 1. 服务器接收到消息后,将回应客户端,并在控制台上显示接收到的消息。 1. 客户端接收到服务器的回应消息,并在控制台上显示。
375 15
|
运维 数据可视化 数据安全/隐私保护
Portainer.io:让容器管理变得更加直观
在现代软件开发和部署中,容器化技术已经变得越来越流行。Docker 是其中一种领先的容器化平台,而 Portainer.io 则是一个优秀的管理工具,使得 Docker 的使用变得更加简单和可视化。本文将介绍 Portainer.io 的基本功能和如何在 Docker 上安装和配置。
529 1
 Portainer.io:让容器管理变得更加直观
|
机器学习/深度学习 存储 计算机视觉
基于YOLOv8深度学习的西红柿成熟度检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战
基于YOLOv8深度学习的西红柿成熟度检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战
|
安全 关系型数据库 MySQL
【PHP开发专栏】PHP PDO与MySQLi操作数据库
【4月更文挑战第30天】PHP数据库交互的核心是PDO和MySQLi。PDO提供数据访问抽象层,支持多种数据库,强调安全和灵活性;MySQLi则专为MySQL设计,有面向对象和过程化接口。两者都支持预处理语句,防止SQL注入。选择取决于项目需求,如可移植性、特定功能和API偏好。了解其使用有助于编写安全高效的代码。
234 2
|
安全 网络协议 Java
技术好文:SpringBoot学习(五)RSocket和Security
技术好文:SpringBoot学习(五)RSocket和Security