热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

云原生实践之RSocket从入门到落地:ServletvsRSocket

技术实践的作用在于:除了用于构建业务,也是为了验证某项技术或框架是否值得大规模推广。本期开始,我们推出《RSocket从入门到落地》系列文章,通过实例和对比来介绍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 requestResponse(Payload payload);

  Mono fireAndForget(Payload payload);

  Flux requestStream(Payload payload);

  Flux requestChannel(Publisher payloads);

  Mono 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也没有关系。

当然还有一项细小差别,这些就不做介绍了。鉴于个人能力,可能我理解的不够彻底,漏掉了重大的区别,大家理解和使用后,欢迎反馈一下。我们再通过图例来对比下两者的不同:
ce359da7368a27faa67bd531492c6bc4

RSocket Demo

这里我们将RSocket的Demo介绍一下。由于没有client -> server这种通讯模型,所以我们用requester和responder来说明,但是角色也是互换的,requester可以为responder,在实际的编码过程中,其实就将requester默认调整为responder。

Responder代码:

RSocketFactory.receive()
            .acceptor(new SocketAcceptor() {
                @Override
                public Mono 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已经开发快完成了,所以不用担心代码的复杂性。

 


原文链接
本文为云栖社区原创内容,未经允许不得转载。


推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
author-avatar
mobiledu2502882721
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有