云原生实践之 RSocket 从入门到落地:Servlet vs RSocket
技术实践的作用在于:除了用于构建业务,也是为了验证某项技术或框架是否值得大规模推广。
本期开始,我们推出《RSocket 从入门到落地》系列文章,通过实例和对比来介绍RSocket。主要围绕RSocket如何实现Polyglot RPC、Service Registry、 Service Discovery、 IoT联结等维度,为读者们揭开RSocket的面纱,希望对大家在Java API规范的技术选型过程中有所借鉴。
第一篇文章我们将通过Servlet和RSocket的对比,快速了解RSocket的一些基本知识。要说明的是其实RSocket与Servlet并不是同类的产品,但是大家对Servlet都很熟悉,功能对比相对方便一些。
阅读本系列文章,需要大家对Java有了解,其中可能会涉及到Kotlin,有少部分C++和Python(不做要求),如果了解Spring Boot则最好。
什么是 Servlet ?
维基百科上的解释是"Servlet,全称Java Servlet,是用Java编写的服务器端程序。 其主要功能在于交互式地浏览和修改数据,生成动态Web内容”。
对于Java程序员来说,解释这个概念直接上代码,这样才能方便理解,如下:
public abstract class HttpServlet extends Servlet {
protected abstract void doGet(HttpServletRequest req,HttpServletResponse resp)
throws ServletException, IOException;
protected abstract void doPost(HttpServletRequest req,HttpServletResponse resp)
throws ServletException, IOException;
}
所以,Servlet就是提供HTTP Request,处理后,最终调用HTTP Response完成输出。没错,就是这个,大家可别小瞧这个class,几乎所有符合Servlet规范的web框架的第一个Java类都是从这里开始的,包括Struts、Spring MVC和阿里巴巴内部用到的WebX。很多开发者根据这个class写了Web Framework,来解决不同的问题。
什么是 RSocket
rsocket.io给出的解释是"RSocket是一个二进制的协议,以异步消息的方式提供4种对等的交互模型,以字节流的方式运行在TCP, WebSockets, Aeron等传输层之上”。
通过这个定义,大家可以有一个基本理解:二进制协议、异步消息、七层协议和运行在TCP、WebSocket以及Aeron之上。同样的,我们通过代码来解释这个概念,如下:
public interface RSocket extends Availability, Closeable {
Mono<Payload> requestResponse(Payload payload);
Mono<Void> fireAndForget(Payload payload);
Flux<Payload> requestStream(Payload payload);
Flux<Payload> requestChannel(Publisher<Payload> payloads);
Mono<Void> metadataPush(Payload payload);
default double availability() {
return isDisposed() ? 0.0 : 1.0;
}
展开阐述一下:
四个模型:
requestResponse、fireAndForget、requestStream和requestChannel,它们和doGet、doPost没有区别。
参数:
Payload,前面说到基于消息通讯,那就是拿到消息返回消息,Got!等一下,为何不叫Message?请原谅我们的英文水平,暂时可以理解为同义词吧。对于一个消息来说,由两部分组成,原信息(metadata)和数据(data)。原信息是指路由信息等,例如要调用那个服务,你的数据的mime type是什么,数据则是指调用的参数值和返回的结果。
metadataPush:
这个是什么?推送元信息的,可以告诉对方的一些元信息,至于是什么,可以自己定义。我理解为:如果是一个集群,我可以将集群的信息给你,然后让你和各个work node连接;我要下线啦,大家做好准备等等。
availability:
为何要这个? 这个可以理解问健康度检查,如果为0,则表示不可用,这在load balance的情况下非常实用。Servlet缺少这个,所以我们要自行加入Health URL等,如/ok.jsp :) 那为何不是布尔值,true或者false?仅是个人理解:double值可以作为权重,如1.0表示处理能力非常好,0.8一般,这个就看你如何处理了。
Mono和Flux:
这是Reactive编程要求,通过异步的方式来提升系统的处理能力。RSocket定义中有一个异步关键字,Mono和Flux就是来处理异步的。
Servlet 和 RSocket的区别
其实两者的共同点非常明显:Servlet是一套Java的API规范,基于HTTP协议之上;RSocket也是一套API规范(支持多种语言),基于自定义的二进制协议之上。 可以不用关心协议的细节,直接实现接口写代码就可以,然后功能就会Ready。 这里我们还是想列举一下它们两者之间的重大区别:
协议层:
Servlet是基于HTTP协议的,RSocket则是自定义协议。 标准化方面,HTTP尚不用说。 但是RSocket的自定义二进制协议性能非常好,解析方便。如果觉得HTTP非常简单,那是1.1,2.0版本开始是有点复杂的。这里我们可以理解为:RSocket定位高性能通讯,比HTTP高非常多(号称10倍)。这里要注意的是:RSocket并不是天然的极致高性能,要实现极致高性能需要根据自己业务场景优化才行。
指令和通讯模式:
HTTP的指令不只是get和post,其他还有head、put、delete和options等。Servlet2.0添加了流式的支持,但是这些指令都是为浏览器设计的,并非为服务通讯设计的,而且它们都是request/response模式,所以也叫做 request command。其他例如流式推送、fireAndForget和双向通讯,Servlet2.0都不支持。基本上,我们可以将HTTP定位为request/response这一种通讯模式。这个说法也许有争议,因为HTTP也有polling和websocket等,但是这些设计都是为了hack和高效通讯的改造,而不是内置的通讯模式。
message:
HTTP1.1是基于文本的通讯,2.0是基于message的。 message的好处是什么呢?基于message的好处是异步化。message都必须有一个ID,这个消息发送出去后,就不用等立即返回,可以继续发其他message,收到message后,再根据返回的message ID和之前的发出去的message ID进行匹配。如果不是message,内容发出去后,就要等着返回的结果进行匹配,然后才能发下一个message,这也是为何很多人抱怨www是World Wide Wait。
Reactive编程模型:
RSocket要求基于Reactive编程模型,对Java来说,主要是Reactor和RxJava,由于Spring在RSocket上贡献颇多,外加RSocket Java SDK还要基于Netty-Reactor,所以默认的接口就是Reactor API。异步化对编程确实比较有挑战,如callback、Future和Promise等,对比传统不是那么友好,所以Reactive在传统和异步化上推出了Reactive编程模型,算是兼顾,这个看大家如何理解,如果对Functional Programming也能接受的话,那Reactive就没有问题。
对等通讯:
我们传统的理解是Client -> Server模式,例如写一个Servlet运行在服务端的,然后再用JS写一个Servlet运行在浏览器端,这样服务端可以反向调用浏览器,例如订单状态变更时,需要将详情区域刷新一下。但是RSocket没有这个概念,大家的地位是对等的,都可以在server端,我调用你的服务,你也可以调用我的服务。后续我们会有详细的Demo来介绍这个使用场景,如无监听端口对外提供服务,从互联网反向访问内部服务。RSocket Broker就是基于这种对等通讯来实现的。
Singleton & Prototype scope:
这里我们套用Spring的Singleton scope和Prototype scope来看Servlet和RSocket的不同。 Singleton scope表示JVM唯一,而Prototype scope是每次调用都需要创建。类比而言,Servlet的class基本都是singleton的,但是RSocket确未必,主要原因是前面说到的对等通讯,如果要给连接的另一方发送请求,就需要hold住连接的另一方(peer RSocket),所以这个handler就不能singleton的,如果只是单方通讯,不用在乎setup payload,那么RSocket的handler为Singleton也没有关系。
当然还有一项细小差别,这些就不做介绍了。鉴于个人能力,可能我理解的不够彻底,漏掉了重大的区别,大家理解和使用后,欢迎反馈一下。我们再通过图例来对比下两者的不同:
RSocket Demo
这里我们将RSocket的Demo介绍一下。由于没有client -> server这种通讯模型,所以我们用requester和responder来说明,但是角色也是互换的,requester可以为responder,在实际的编码过程中,其实就将requester默认调整为responder。
Responder代码:
RSocketFactory.receive()
.acceptor(new SocketAcceptor() {
@Override
public Mono<RSocket> accept(ConnectionSetupPayload setup, RSocket sendingSocket) {
return Mono.just(new RSocketHandlerImpl());
}
})
.transport(TcpServerTransport.create("0.0.0.0", 42252))
.start()
.subscribe();
Responder主要是RSocketFactory.receive(),接收外部来的连接。接下来你只需要一个RSocket的接口实现给acceptor就可以了。 这里说明一下SocketAcceptor接口。对于Responder来说,它需要验证requester能否可以连接到自己,这个非常有用,如初始鉴权等,一旦鉴权通过,连接建立好后,后续就不需要验证了。这里的ConnectionSetupPayload是requester发给responder的创建连接的数据。这个是Servlet中没有的,后续我们还会提供更多的实践,第一篇文章里仅验证是否可以连接。
Requester代码:
RSocketFactory.connect()
.acceptor(new Function<RSocket, RSocket>() {
@Override
public RSocket apply(RSocket peerRsocket) {
return Mono.just(new RSocketHandlerImpl()) ;
}
})
.transport(TcpClientTransport.create("localhost", 42252))
.start()
.block();
RSocketFactory.connect() 是表示要连接到目标的responder上,然后也有RSocket实现给acceptor表示接收从对方过来的调用请求。 最好的block()表示采用同步方式等待responder返回,这个是需要的,如目标服务宕机或者不存在等,应用可以快速自我发现。 但是在load balance的情况下,我们未采用block这种方式,而是使用Mono方式,这样可以实现自动重连,新地址推送等。
实际上,如果使用Spring Boot,可能就需要1-2个Bean,SocketAcceptor和RSocket Bean,其他都是通过注入方式完成,不需要写很多重复代码。 目前rsocket-spring-boot-starter已经开发快完成了,所以不用担心代码的复杂性。
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云原生实践之 RSocket 从入门到落地:Servlet vs RSocket的更多相关文章
- 云原生 - 体验Istio的完美入门之旅(一)
作者:justmine 头条号:大数据达摩院 微信公众号:大数据处理系统 创作不易,在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处. 为了方便大家阅读,可以关注头条号或微信公众号,后 ...
- 宙斯盾 DDoS 防护系统“降本增效”的云原生实践
作者 tomdu,腾讯云高级工程师,主要负责宙斯盾安全防护系统管控中心架构设计和后台开发工作. 导语 宙斯盾 DDoS 防护系统作为公司级网络安全产品,为各类业务提供专业可靠的 DDoS/CC 攻击防 ...
- 订单峰值激增 230%,Serverless 如何为世纪联华降本超 40%?|双11 云原生实践
作者 | 朱鹏 导读:2020 年 双11,世纪联华基于阿里云函数计算 (FC) 弹性扩容,应用于大促会场 SSR.线上商品秒杀.优惠券定点发放.行业导购.数据中台计算等多个场景,业务峰值 QPS 较 ...
- “行业客户云原生最佳实践日” 亮相KubeCon上海
2018年11月13日至15日,由CNCF主办的KubeCon + CloudNativeCon将首次登陆中国上海,这是全球范围内规模最大的Kubernetes和云原生技术盛会. 唯一聚焦客户实践的分 ...
- 阿里云 CDN 业务基于边缘容器的云原生转型实践
导读:本文基于边缘容器的阿里云 CDN 云原生实践, 涵盖了边缘容器的背景和趋势,边缘托管集群 ACK Managed Edge K8s(文中简称“Edge@ACK”) 的能力.架构,以及基于边缘容器 ...
- Canonical 开源 MicroK8 | 云原生生态周报 Vol. 25
业界要闻 1.Canonical 开源 MicroK8 面向工作站和边缘/物联网的零运维 Kubernetes!MicroK8 是 Canonical 提供的一款功能强大的企业级 Kubernetes ...
- Falco 进入 CNCF Incubator 项目 | 云原生生态周报 Vol. 35
作者 | 王思宇.陈洁.敖小剑 业界要闻 Falco 进入 CNCF Incubator 项目 原于 2018 年 8 月进入 sandbox,旨在 Kubernetes 运行时环境下支持配置规则来加 ...
- 云原生 - Istio可观察性之分布式跟踪(三)
作者:justmine 头条号:大数据与云原生 微信公众号:大数据与云原生 创作不易,在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处. 为了方便阅读,微信公众号已按分类排版,后续的文 ...
- 云原生 - Istio可观察性之监控(四)
作者:justmine 头条号:大数据与云原生 微信公众号:大数据与云原生 创作不易,在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处. 为了方便阅读,微信公众号已按分类排版,后续的文 ...
随机推荐
- CSS3 常用属性
1------border-radius (盒子圆角 border-radius :border-radius:5px 4px 3px 2px; 左上,右上,右下,左下 2------如果将一个正方形 ...
- Java 跨平台原理
Java的跨平台基于编译器和虚拟机.其中,CPU处理器和操作系统的整体称为平台.编译器把源文件编译成与平台无关的基于Unicode的字节码class文件,虚拟机把该文件解释成与平台有关的机器码指令,可 ...
- PowerApp Document
https://docs.microsoft.com/en-us/powerapps/ PowerApp Document: https://docs.microsoft.com/en-us/powe ...
- 一文教你看懂大数据的技术生态圈:Hadoop,hive,spark
转自:https://www.cnblogs.com/reed/p/7730360.html 大数据本身是个很宽泛的概念,Hadoop生态圈(或者泛生态圈)基本上都是为了处理超过单机尺度的数据处理而诞 ...
- 快排实现仿order by多字段排序
class OrderBy(object): def __init__(self, sequence, *condition, **extra_condition): ""&quo ...
- Java变成遇到的简单乱码问题
1.乱码 --- 编码集 编码集的本质是让数字与字符产生一个映射关系,不同的编码集映射实现也不同 比如UTF-8: "中"----> -28 -72 -83 对应 ...
- Shell 脚本处理用户输入
传递参数 跟踪参数 移动变量 处理选项 将选项标准化 获得用户的输入 bash shell提供了一些不同的方法来从用户处获取数据,包括命令行参数(添加在命令后数据),命令行选项(可以修改命令行为的单个 ...
- Git 简单入门(二)
分支管理 分支的作用 提交不完整的代码到主分支上会导致别人不能正常开发 如果等代码全部写完再提交,存在丢失每天进度的风险 详见:https://segmentfault.com/q/101000001 ...
- mysql里的数据库引擎, 编码格式
针对数据库里即使设置了varchar类型的字段, 值输入中文报错的情况,是因为数据库的默认编码类型不支持汉字输入. utf-8 可以编译全球通用的所有语言符号. 由1-6个可变字节组成,有非常严格的排 ...
- C盘突然爆满
C盘突然爆满!幸好还开的机!~~ 因为是突然就爆满了,想着应该是虚拟内存的原因!于是就开始了探索.... 1.文件夹选项中把所有文件都显示出来. 2.在C盘你就会看到一个“pagefile.sys”的 ...