技术实践的做用在于:除了用于构建业务,也是为了验证某项技术或框架是否值得大规模推广。php
本期开始,咱们推出《RSocket 从入门到落地》系列文章,经过实例和对比来介绍RSocket。主要围绕RSocket如何实现Polyglot RPC、Service Registry、 Service Discovery、 IoT联结等维度,为读者们揭开RSocket的面纱,但愿对你们在Java API规范的技术选型过程当中有所借鉴。java
第一篇文章咱们将经过Servlet和RSocket的对比,快速了解RSocket的一些基本知识。要说明的是其实RSocket与Servlet并非同类的产品,可是你们对Servlet都很熟悉,功能对比相对方便一些。node
阅读本系列文章,须要你们对Java有了解,其中可能会涉及到Kotlin,有少部分C++和Python(不作要求),若是了解Spring Boot则最好。程序员
维基百科上的解释是"Servlet,全称Java Servlet,是用Java编写的服务器端程序。 其主要功能在于交互式地浏览和修改数据,生成动态Web内容”。web
对于Java程序员来讲,解释这个概念直接上代码,这样才能方便理解,以下:spring
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.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; }
展开阐述一下:websocket
四个模型:
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是一套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介绍一下。因为没有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已经开发快完成了,因此不用担忧代码的复杂性。
原文连接本文为云栖社区原创内容,未经容许不得转载。