云原生實踐之 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 從入門到落地:Servlet vs RSocket

RSocket Demo
這里我們將RSocket的Demo介紹一下。由于沒有client -> server這種通訊模型,所以我們用requester和responder來說明,但是角色也是互換的,requester可以為responder,在實際的編碼過程中,其實就將requester默認調整為responder。

Responder代碼:

RSocketFactory.receive()
.acceptor(new SocketAcceptor() {br/>@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>() {br/>@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已經開發快完成了,所以不用擔心代碼的復雜性。

轉載于:https://blog.51cto.com/14031893/2348223

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252426.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252426.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252426.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

制作.sens數據集跑通bundlefusion

1. 主要參考這篇博客實現 https://blog.csdn.net/Wuzebiao2016/article/details/94426905 2. 首先就是將自己采集的RGBD圖像的保存格式向Bundlefusion需要的格式對齊&#xff0c;如彩色圖的命名格式是frame-000000.color.png&#xff0c;深度圖的命名規則是frame-000000.depth…

用ul li實現邊框重合并附帶鼠標經過效果

邊框重合這個效果并不難&#xff0c;只是我們沒有真正的動手做過而已&#xff0c;下面讓我們來談談用ul li如何實現邊框重合&#xff0c;并附帶鼠標經過效果 1 <!DOCTYPE html>2 <html lang"zh-CN">3 4 <head>5 <title></title>6 …

hive 中窗口函數row_number,rank,dense_ran,ntile分析函數的用法

https://www.cnblogs.com/wujin/p/6051768.html轉載于:https://www.cnblogs.com/0xcafedaddy/p/8385476.html

python之moviepy庫的安裝與使用

目的&#xff1a;因為需要保存一個大大的.mp4視頻&#xff0c;以防過程中設備出現異常導致整個長長的視頻無法正常保存&#xff0c;所以采用分段保存視頻的方式&#xff0c;每500幀保存一段&#xff0c;然后再將視頻合到一起&#xff0e;最近剛開始學習python,發現python真的很…

oracle 之 安裝后pl/sql登錄報ora-12154

這個問題一開始困擾了很久。 查的資料是復制一小段代碼到tnsnames.ora中 SID名 (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST localhost)(PORT 1522)) (CONNECT_DATA (SERVER DEDICATED) (SERVICE_NAME SID名) ) 注意SID名前面不能有任何其他字符&…

如何避免表單重復提交

客戶端方案 禁掉提交按鈕。 表單提交后使用Javascript使提交按鈕disable。這種方法防止心急的用戶多次點擊按鈕。但有個問題&#xff0c;如果客戶端把Javascript給禁止掉&#xff0c;這種方法就無效了。 使用Post/Redirect/Get模式 在提交后執行頁面重定向&#xff0c;這就是所…

十六進制轉八進制

【問題描述】 問題描述 給定n個十六進制正整數&#xff0c;輸出它們對應的八進制數。 輸入格式 輸入的第一行為一個正整數n &#xff08;1<n<10&#xff09;。 接下來n行&#xff0c;每行一個由0~9、大寫字母A~F組成的字符串&#xff0c;表示要轉換的十六進制正整數&…

使用iai_kinect2標定kinectV2相機

實驗背景&#xff1a;因為需要制作bundlefusion需要的數據集&#xff0c;所以需要使用kinectV2相機獲取rgbd圖像&#xff0c;年前的時候在我的筆記本上安裝了libfreenect2庫和iai_kinect2&#xff0c;標定過一次kinecv2相機&#xff0c;然后使用kinectv2相機實時獲取的圖像實現…

tar只解壓tar包中某個文件

如果tar包很大&#xff0c;而只想解壓出其中某個文件。方法如下&#xff1a; 只想解壓出Redis-1.972.tar 中的Changes文件&#xff0c;來查看有哪些更改。 [rootuplooking]# tar -tf Redis-1.972.tar Redis-1.972…

扎克伯格的中文夜:想要成功就不能放棄

10月23日消息。雖然并不太流暢。昨天馬克?扎克伯格依舊用中文與清華經管學院主持人完畢了一場對話&#xff1b;在對話中&#xff0c;這位Facebook創始人兼首席運行官闡述了自己學習中文的原因&#xff1a;想要和太太&#xff08;普里西拉?陳&#xff09;的家人交流&#xff1…

python將ros下bag文件的所有topic解析為csv格式

背景&#xff1a;最近在制作kimera的數據集&#xff0c;尤其是運行semantic模塊所需要的bag文件中有很多topic&#xff0c;但是很多不知道topic中裝的是什么數據&#xff0c;及其格式&#xff0c;所以我就想著怎么可以將bag中的topic都解析數來&#xff0c;這樣就能知道bag中都…

十九. Python基礎(19)--異常

十九. Python基礎(19)--異常 1 ● 捕獲異常 if VS異常處理: if是預防異常出現, 異常處理是處理異常出現 異常處理一般格式: try: <...............> #可能得到異常的語句 except <.......>: #捕獲是哪種異常 <...............> #出現異常的處理方…

洛谷1052——過河(DP+狀態壓縮)

題目描述 在河上有一座獨木橋&#xff0c;一只青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子&#xff0c;青蛙很討厭踩在這些石子上。由于橋的長度和青蛙一次跳過的距離都是正整數&#xff0c;我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點&#xff1a;0…

Tensorflow學習教程------tfrecords數據格式生成與讀取

首先是生成tfrecords格式的數據&#xff0c;具體代碼如下&#xff1a; #coding:utf-8import os import tensorflow as tf from PIL import Imagecwd os.getcwd() 此處我加載的數據目錄如下&#xff1a; bt -- 14018.jpg14019.jpg14020.jpgnbt -- 1_ddd.jpg1_dsdfs.jpg1_dfd.…

ROS獲取KinectV2相機的彩色圖和深度圖并制作bundlefusion需要的數據集

背景&#xff1a; 最近在研究BundleFusion&#xff0c;跑通官方數據集后&#xff0c;就想著制作自己的數據集來運行bundlefusion&#xff0e;KinectV2相機可直接獲取的圖像的分辨率分為三個HD 1920x1080, QHD: 960X540&#xff0c;SD: 512x424.我選擇是中間的分辨率qhd. 錄制…

Linux下配置tomcat+apr+native應對高并發

摘要&#xff1a;在慢速網絡上Tomcat線程數開到300以上的水平&#xff0c;不配APR&#xff0c;基本上300個線程狠快就會用滿&#xff0c;以后的請求就只好等待。但是配上APR之后&#xff0c;Tomcat將以JNI的形式調用Apache HTTP服務器的核心動態鏈接庫來處理文件讀取或網絡傳輸…

Firefox 66 將阻止自動播放音頻和視頻

百度智能云 云生態狂歡季 熱門云產品1折起>>> 當我們點擊一個鏈接&#xff0c;或者打開新的瀏覽器選項卡時&#xff0c;瀏覽器就開始自動播放視頻和聲音&#xff0c;這是一件十分煩人的事。Chrome 瀏覽器早已對這些行為下手了&#xff0c;現在 Firefox 也明確表示要…

Windows 10 關閉Hyper-V

以管理員身份運行命令提示符 關閉 bcdedit /set hypervisorlaunchtype off 啟用 bcdedit / set hypervisorlaunchtype auto 禁用DG 轉載于:https://www.cnblogs.com/Robbery/p/8397767.html

ROS下獲取kinectv2相機的仿照TUM數據集格式的彩色圖和深度圖

準備工作&#xff1a; &#xff11;&#xff0e; ubuntu16.04上安裝iai-kinect2, 2. 運行roslaunch kinect2_bridge kinect2_bridge.launch, 3. 運行 rosrun save_rgbd_from_kinect2 save_rgbd_from_kinect2,開始保存圖像&#xff0e; 這個保存kinectV2相機的代碼如下&…

Java Web 九大內置對象(一)

在Jsp 中一共定義了九個內置對象&#xff0c;分別為&#xff1a; *request HttpServletRequest; *response HttpServletResponse; *session HttpSession; page This(本jsp頁面)&#xff1b; *application ServletCon…