国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
體系化認(rèn)識(shí)RPC
作者|張旭
編輯|雨多田光
標(biāo)簽 | RPC

RPC(Remote Procedure Call),即遠(yuǎn)程過(guò)程調(diào)用,是一個(gè)分布式系統(tǒng)間通信的必備技術(shù),本文體系性地介紹了 RPC 包含的核心概念和技術(shù),希望讀者讀完文章,一提到 RPC,腦中不是零碎的知識(shí),而是具體的一個(gè)腦圖般的體系。本文并不會(huì)深入到每一個(gè)主題剖析,只做提綱挈領(lǐng)的介紹。

RPC 最核心要解決的問(wèn)題就是在分布式系統(tǒng)間,如何執(zhí)行另外一個(gè)地址空間上的函數(shù)、方法,就仿佛在本地調(diào)用一樣,個(gè)人總結(jié)的 RPC 最核心的概念和技術(shù)包括如下,如圖所示:

下面依次展開(kāi)每個(gè)部分。

傳輸(Transport)

TCP 協(xié)議是 RPC 的 基石,一般來(lái)說(shuō)通信是建立在 TCP 協(xié)議之上的,而且 RPC 往往需要可靠的通信,因此不采用 UDP。

這里重申下 TCP 的關(guān)鍵詞:面向連接的,全雙工,可靠傳輸(按序、不重、不丟、容錯(cuò)),流量控制(滑動(dòng)窗口)。

另外,要理解 RPC 中的嵌套 header+body,協(xié)議棧每一層都包含了下一層協(xié)議的全部數(shù)據(jù),只不過(guò)包了一個(gè)頭而已,如下圖所示的 TCP segment 包含了應(yīng)用層的數(shù)據(jù),套了一個(gè)頭而已。

那么 RPC 傳輸?shù)?message 也就是 TCP body 中的數(shù)據(jù),這個(gè) message 也同樣可以包含 header+body。body 也經(jīng)常叫做 payload。

TCP 就是可靠地把數(shù)據(jù)在不同的地址空間上搬運(yùn),例如在傳統(tǒng)的阻塞 I/O 模型中,當(dāng)有數(shù)據(jù)過(guò)來(lái)的時(shí)候,操作系統(tǒng)內(nèi)核把數(shù)據(jù)從 I/O 中讀出來(lái)存放在 kernal space,然后內(nèi)核就通知 user space 可以拷貝走數(shù)據(jù),用以騰出空間,讓 TCP 滑動(dòng)窗口向前移動(dòng),接收更多的數(shù)據(jù)。

TCP 協(xié)議棧存在端口的概念,端口是進(jìn)程獲取數(shù)據(jù)的渠道。

I/O 模型(I/O Model)

做一個(gè)高性能 /scalable 的 RPC,需要能夠滿足:

  • 第一,服務(wù)端盡可能多的處理并發(fā)請(qǐng)求

  • 第二,同時(shí)盡可能短的處理完畢。

CPU 和 I/O 之間天然存在著差異,網(wǎng)絡(luò)傳輸?shù)难訒r(shí)不可控,最簡(jiǎn)單的模型下,如果有線程或者進(jìn)程在調(diào)用 I/O,I/O 沒(méi)響應(yīng)時(shí),CPU 只能選擇掛起,線程或者進(jìn)程也被 I/O 阻塞住。

而 CPU 資源寶貴,要讓 CPU 在該忙碌的時(shí)候盡量忙碌起來(lái),而不需要頻繁地掛起、喚醒做切換,同時(shí)很多寶貴的線程和進(jìn)程占用系統(tǒng)資源也在做無(wú)用功。

Socket I/O 可以看做是二者之間的橋梁,如何更好地協(xié)調(diào)二者,去滿足前面說(shuō)的兩點(diǎn)要求,有一些模式(pattern)是可以應(yīng)用的。

RPC 框架可選擇的 I/O 模型嚴(yán)格意義上有 5 種,這里不討論基于 信號(hào)驅(qū)動(dòng) 的 I/O(Signal Driven I/O)。這幾種模型在《UNIX 網(wǎng)絡(luò)編程》中就有提到了,它們分別是:

  1. 傳統(tǒng)的阻塞 I/O(Blocking I/O)

  2. 非阻塞 I/O(Non-blocking I/O)

  3. I/O 多路復(fù)用(I/O multiplexing)

  4. 異步 I/O(Asynchronous I/O)

這里不細(xì)說(shuō)每種 I/O 模型。這里舉一個(gè)形象的例子,讀者就可以領(lǐng)會(huì)這四種 I/O 的區(qū)別,就用 銀行辦業(yè)務(wù) 這個(gè)生活的場(chǎng)景描述。

下圖是使用 傳統(tǒng)的阻塞 I/O 模型。一個(gè)柜員服務(wù)所有客戶,可見(jiàn)當(dāng)客戶填寫(xiě)單據(jù)的時(shí)候也就是發(fā)生網(wǎng)絡(luò) I/O 的時(shí)候,柜員,也就是寶貴的線程或者進(jìn)程就會(huì)被阻塞,白白浪費(fèi)了 CPU 資源,無(wú)法服務(wù)后面的請(qǐng)求。

下圖是上一個(gè)的進(jìn)化版,如果一個(gè)柜員不夠,那么就 并發(fā)處理,對(duì)應(yīng)采用線程池或者多進(jìn)程方案,一個(gè)客戶對(duì)應(yīng)一個(gè)柜員,這明顯加大了并發(fā)度,在并發(fā)不高的情況下性能夠用,但是仍然存在柜員被 I/O 阻塞的可能。

下圖是 I/O 多路復(fù)用,存在一個(gè)大堂經(jīng)理,相當(dāng)于代理,它來(lái)負(fù)責(zé)所有的客戶,只有當(dāng)客戶寫(xiě)好單據(jù)后,才把客戶分配一個(gè)柜員處理,可以想象柜員不用阻塞在 I/O 讀寫(xiě)上,這樣柜員效率會(huì)非常高,這也就是 I/O 多路復(fù)用的精髓。

下圖是 異步 I/O,完全不存在大堂經(jīng)理,銀行有一個(gè)天然的“高級(jí)的分配機(jī)器”,柜員注冊(cè)自己負(fù)責(zé)的業(yè)務(wù)類型,例如 I/O 可讀,那么由這個(gè)“高級(jí)的機(jī)器”負(fù)責(zé) I/O 讀,當(dāng)可讀時(shí)候,通過(guò) 回調(diào)機(jī)制,把客戶已經(jīng)填寫(xiě)完畢的單據(jù)主動(dòng)交給柜員,回調(diào)其函數(shù)完成操作。

重點(diǎn)說(shuō)下高性能,并且工業(yè)界普遍使用的方案,也就是后兩種。

I/O 多路復(fù)用

基于內(nèi)核,建立在 epoll 或者 kqueue 上實(shí)現(xiàn),I/O 多路復(fù)用最大的優(yōu)勢(shì)是用戶可以在一個(gè)線程內(nèi)同時(shí)處理多個(gè) Socket 的 I/O 請(qǐng)求。用戶可以訂閱事件,包括文件描述符或者 I/O 可讀、可寫(xiě)、可連接事件等。

通過(guò)一個(gè)線程監(jiān)聽(tīng)全部的 TCP 連接,有任何事件發(fā)生就通知用戶態(tài)處理即可,這么做的目的就是 假設(shè) I/O 是慢的,CPU 是快的,那么要讓用戶態(tài)盡可能的忙碌起來(lái)去,也就是最大化 CPU 利用率,避免傳統(tǒng)的 I/O 阻塞。

異步 I/O

這里重點(diǎn)說(shuō)下同步 I/O 和異步 I/O,理論上前三種模型都叫做同步 I/O,同步是指用戶線程發(fā)起 I/O 請(qǐng)求后需要等待或者輪詢內(nèi)核 I/O 完成后再繼續(xù),而異步是指用戶線程發(fā)起 I/O 請(qǐng)求直接退出,當(dāng)內(nèi)核 I/O 操作完成后會(huì)通知用戶線程來(lái)調(diào)用其回調(diào)函數(shù)。

進(jìn)程 / 線程模型(Thread/Process Model)

進(jìn)程 / 線程模型往往和 I/O 模型有聯(lián)系,當(dāng) Socket I/O 可以很高效的工作時(shí)候,真正的業(yè)務(wù)邏輯如何利用 CPU 更快地處理請(qǐng)求,也是有 pattern 可尋的。這里主要說(shuō) Scalable I/O 一般是如何做的,它的 I/O 需要經(jīng)歷 5 個(gè)環(huán)節(jié):

Read -> Decode -> Compute -> Encode -> Send

使用傳統(tǒng)的阻塞 I/O + 線程池的方案(Multitasks)會(huì)遇 C10k問(wèn)題。

https://en.wikipedia.org/wiki/C10k_problem

但是業(yè)界有很多實(shí)現(xiàn)都是這個(gè)方式,比如 Java web 容器 Tomcat/Jetty 的默認(rèn)配置就采用這個(gè)方案,可以工作得很好。

但是從 I/O 模型可以看出 I/O Blocking is killer to performance,它會(huì)讓工作線程卡在 I/O 上,而一個(gè)系統(tǒng)內(nèi)部可使用的線程數(shù)量是有限的(本文暫時(shí)不談協(xié)程、纖程的概念),所以才有了 I/O 多路復(fù)用和異步 I/O。

I/O 多路復(fù)用往往對(duì)應(yīng) Reactor 模式,異步 I/O 往往對(duì)應(yīng) Proactor。

Reactor 一般使用 epoll+ 事件驅(qū)動(dòng) 的經(jīng)典模式,通過(guò) 分治 的手段,把耗時(shí)的網(wǎng)絡(luò)連接、安全認(rèn)證、編碼等工作交給專門的線程池或者進(jìn)程去完成,然后再去調(diào)用真正的核心業(yè)務(wù)邏輯層,這在 *nix 系統(tǒng)中被廣泛使用。

著名的 Redis、Nginx、Node.js 的 Socket I/O 都用的這個(gè),而 Java 的 NIO 框架 Netty 也是,Spark 2.0 RPC 所依賴的同樣采用了 Reactor 模式。

Proactor 在 *nix 中沒(méi)有很好的實(shí)現(xiàn),但是在 Windows 上大放異彩(例如 IOCP 模型)。

關(guān)于 Reactor 可以參考 Doug Lea 的 PPT

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

以及 這篇 paper

http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf

關(guān)于 Proactor 可以參考 這篇 paper

http://www.cs.wustl.edu/~schmidt/PDF/proactor.pdf

說(shuō)個(gè)具體的例子,Thrift 作為一個(gè)融合了 序列化 +RPC 的框架,提供了很多種 Server 的構(gòu)建選項(xiàng),從名稱中就可以看出他們使用哪種 I/O 和線程模型。

Schema 和序列化(Schema & Data Serialization)

當(dāng) I/O 完成后,數(shù)據(jù)可以由程序處理,那么如何識(shí)別這些二進(jìn)制的數(shù)據(jù),是下一步要做的。序列化和反序列化,是做對(duì)象到二進(jìn)制數(shù)據(jù)的轉(zhuǎn)換,程序是可以理解對(duì)象的,對(duì)象一般含有 schema 或者結(jié)構(gòu),基于這些語(yǔ)義來(lái)做特定的業(yè)務(wù)邏輯處理。

考察一個(gè)序列化框架一般會(huì)關(guān)注以下幾點(diǎn):

  • Encoding format。是 human readable 還是 binary。

  • Schema declaration。也叫作契約聲明,基于 IDL,比如 Protocol Buffers/Thrift,還是自描述的,比如 JSON、XML。另外還需要看是否是強(qiáng)類型的。

  • 語(yǔ)言平臺(tái)的中立性。比如 Java 的 Native Serialization 就只能自己玩,而 Protocol Buffers 可以跨各種語(yǔ)言和平臺(tái)。

  • 新老契約的兼容性。比如 IDL 加了一個(gè)字段,老數(shù)據(jù)是否還可以反序列化成功。

  • 和壓縮算法的契合度。跑 benchmark 和實(shí)際應(yīng)用都會(huì)結(jié)合各種壓縮算法,例如 gzip、snappy。

  • 性能。這是最重要的,序列化、反序列化的時(shí)間,序列化后數(shù)據(jù)的字節(jié)大小是考察重點(diǎn)。

序列化方式非常多,常見(jiàn)的有 Protocol Buffers, Avro,Thrift,XML,JSON,MessagePack,Kyro,Hessian,Protostuff,Java Native Serialize,F(xiàn)ST。

下面詳細(xì)展開(kāi) Protocol Buffers(簡(jiǎn)稱 PB),看看為什么作為工業(yè)界用得最多的高性能序列化類庫(kù),好在哪里。

首先去官網(wǎng)查看它的 Encoding format

https://developers.google.com/protocol-buffers/docs/encoding

緊湊高效 是 PB 的特點(diǎn),使用字段的序號(hào)作為標(biāo)識(shí),而不是包名類名(Java 的 Native Serialization 序列化后數(shù)據(jù)大就在于什么都一股腦放進(jìn)去),使用 varint 和 zigzag 對(duì)整型做特殊處理。

PB 可以跨各種語(yǔ)言,但是前提是使用 IDL 編寫(xiě)描述文件,然后 codegen 工具生成各種語(yǔ)言的代碼。

舉個(gè)例子,有個(gè) Person 對(duì)象,包含內(nèi)容如下圖所示,經(jīng)過(guò) PB 序列化后只有 33 個(gè)字節(jié),可以對(duì)比 XML、JSON 或者 Java 的 Native Serialization 都會(huì)大非常多,而且序列化、反序列化的速度也不會(huì)很好。記住這個(gè)數(shù)據(jù),后面 demo 的時(shí)候會(huì)有用。

圖片來(lái)源

https://www.slideshare.net/SergeyPodolsky/google-protocol-buffers-56085699

再舉個(gè)例子,使用 Thrift 做同樣的序列化,采用 Binary Protocol 和 Compact Protocol 的大小是不一樣的,但是 Compact Protocol 和 PB 雖然序列化的編碼不一樣,但是同樣是非常高效的。

圖片來(lái)源

https://www.slideshare.net/SergeyPodolsky/google-protocol-buffers-56085699

這里給一個(gè) Uber 做的序列化框架比較

https://eng.uber.com/trip-data-squeeze/

可以看出 Protocol Buffers 和 Thrift 都是名列前茅的,但是這些 benchmark 看看就好,知道個(gè)大概,沒(méi)必要細(xì)究,因?yàn)闃颖緮?shù)據(jù)、測(cè)試環(huán)境、版本等都可能會(huì)影響結(jié)果。

協(xié)議結(jié)構(gòu)(Wire Protocol)

Socket 范疇里討論的包叫做 Frame、Packet、Segment 都沒(méi)錯(cuò),但是一般把這些分別映射為數(shù)據(jù)鏈路層、IP 層和 TCP 層的數(shù)據(jù)包,應(yīng)用層的暫時(shí)沒(méi)有,所以下文不必計(jì)較包怎么翻譯。

協(xié)議結(jié)構(gòu),英文叫做 wire protocol 或者 wire format。TCP 只是 binary stream 通道,是 binary 數(shù)據(jù)的可靠搬用工,它不懂 RPC 里面包裝的是什么。而在一個(gè)通道上傳輸 message,勢(shì)必涉及 message 的識(shí)別。

舉個(gè)例子,正如下圖中的例子,ABC+DEF+GHI 分 3 個(gè) message,也就是分 3 個(gè) Frame 發(fā)送出去,而接收端分四次收到 4 個(gè) Frame。

Socket I/O 的工作完成得很好,可靠地傳輸過(guò)去,這是 TCP 協(xié)議保證的,但是接收到的是 4 個(gè) Frame,不是原本發(fā)送的 3 個(gè) message 對(duì)應(yīng)的 3 個(gè) Frame。

這種情況叫做發(fā)生了 TCP 粘包和半包 現(xiàn)象,AB、H、I 的情況叫做半包,CDEFG 的情況叫做粘包。雖然順序是對(duì)的,但是分組完全和之前對(duì)應(yīng)不上。

這時(shí)候應(yīng)用層如何做語(yǔ)義級(jí)別的 message 識(shí)別是個(gè)問(wèn)題,只有做好了協(xié)議的結(jié)構(gòu),才能把一整個(gè)數(shù)據(jù)片段做序列化或者反序列化處理。

一般采用的方式有三種:

方式 1:分隔符

方式 2:換行符。比如 memcache 由客戶端發(fā)送的命令使用的是文本行\(zhòng)r\n 做為 mesage 的分隔符,組織成一個(gè)有意義的 message。

圖片來(lái)源

https://www.kancloud.cn/kancloud/essential-netty-in-action/52643

圖中的說(shuō)明:

  1. 字節(jié)流

  2. 第一幀

  3. 第二幀

方式 3:固定長(zhǎng)度。RPC 經(jīng)常采用這種方式,使用 header+payload 的方式。

比如 HTTP 協(xié)議,建立在 TCP 之上最廣泛使用的 RPC,HTTP 頭中肯定有一個(gè) body length 告知應(yīng)用層如何去讀懂一個(gè) message,做 HTTP 包的識(shí)別。

在 HTTP/2 協(xié)議中,詳細(xì)見(jiàn) Hypertext Transfer Protocol Version 2 (HTTP/2)

https://tools.ietf.org/html/rfc7540

雖然精簡(jiǎn)了很多,加入了流的概念,但是 header+payload 的方式是絕對(duì)不能變的。

圖片來(lái)源

https://tools.ietf.org/html/rfc7540

下面展示的是作者自研的一個(gè) RPC 框架,可以在 github 上找到這個(gè)工程 

neoremind/navi-pbrpc

https://github.com/neoremind/navi-pbrpc

可以看出它的協(xié)議棧 header+payload 方式的,header 固定 36 個(gè)字節(jié)長(zhǎng)度,最后 4 個(gè)字節(jié)是 body length,也就是 payload length,可以使用大尾端或者小尾端編碼。

可靠性(Reliability)

RPC 框架不光要處理 Network I/O、序列化、協(xié)議棧。還有很多不確定性問(wèn)題要處理,這里的不確定性就是由 網(wǎng)絡(luò)的不可靠 帶來(lái)的麻煩。

例如如何保持長(zhǎng)連接心跳?網(wǎng)絡(luò)閃斷怎么辦?重連、重傳?連接超時(shí)?這些都非常的細(xì)碎和麻煩,所以說(shuō)開(kāi)發(fā)好一個(gè)穩(wěn)定的 RPC 類庫(kù)是一個(gè)非常系統(tǒng)和細(xì)心的工程。

但是好在工業(yè)界有一群人就致力于提供平臺(tái)似的解決方案,例如 Java 中的 Netty,它是一個(gè)強(qiáng)大的異步、事件驅(qū)動(dòng)的網(wǎng)絡(luò) I/O 庫(kù),使用 I/O 多路復(fù)用的模型,做好了上述的麻煩處理。

它是面向?qū)ο笤O(shè)計(jì)模式的集大成者,使用方只需要會(huì)使用 Netty 的各種類,進(jìn)行擴(kuò)展、組合、插拔,就可以完成一個(gè)高性能、可靠的 RPC 框架。

著名的 gRPC Java 版本、Twitter 的 Finagle 框架、阿里巴巴的 Dubbo、新浪微博的 Motan、Spark 2.0 RPC 的網(wǎng)絡(luò)層(可以參考 kraps-rpchttps://github.com/neoremind/kraps-rpc)都采用了這個(gè)類庫(kù)。

易用性(Ease of use)

RPC 是需要讓上層寫(xiě)業(yè)務(wù)邏輯來(lái)實(shí)現(xiàn)功能的,如何優(yōu)雅地啟停一個(gè) server,注入 endpoint,客戶端怎么連,重試調(diào)用,超時(shí)控制,同步異步調(diào)用,SDK 是否需要交換等等,都決定了基于 RPC 構(gòu)建服務(wù),甚至 SOA 的工程效率與生產(chǎn)力高低。這里不做展開(kāi),看各種 RPC 的文檔就知道他們的易用性如何了。

工業(yè)界的 RPC 框架一覽
國(guó)內(nèi)
  • Dubbo。來(lái)自阿里巴巴 http://dubbo.I/O/

  • Motan。新浪微博自用 https://github.com/weibocom/motan

  • Dubbox。當(dāng)當(dāng)基于 dubbo 的 https://github.com/dangdangdotcom/dubbox

  • rpcx。基于 Golang 的 https://github.com/smallnest/rpcx

  • Navi & Navi-pbrpc。作者開(kāi)源的 https://github.com/neoremind/navi https://github.com/neoremind/navi-pbrpc

國(guó)外
  • Thrift from facebook https://thrift.apache.org

  • Avro from hadoop https://avro.apache.org

  • Finagle by twitter https://twitter.github.I/O/finagle

  • gRPC by Google http://www.grpc.I/O (Google inside use Stuppy)

  • Hessian from cuacho http://hessian.caucho.com

  • Coral Service inside amazon (not open sourced)

上述列出來(lái)的都是現(xiàn)在互聯(lián)網(wǎng)企業(yè)常用的解決方案,暫時(shí)不考慮傳統(tǒng)的 SOAP,XML-RPC 等。這些是有網(wǎng)絡(luò)資料的,實(shí)際上很多公司內(nèi)部都會(huì)針對(duì)自己的業(yè)務(wù)場(chǎng)景,以及和公司內(nèi)的平臺(tái)相融合(比如監(jiān)控平臺(tái)等),自研一套框架,但是殊途同歸,都逃不掉剛剛上面所列舉的 RPC 的要考慮的各個(gè)部分。

Demo 展示

為了使讀者更好地理解上面所述的各個(gè)章節(jié),下面做一個(gè)簡(jiǎn)單例子分析。使用 neoremind/navi-pbrpchttps://github.com/neoremind/navi-pbrpc 來(lái)做 demo,使用 Java 語(yǔ)言來(lái)開(kāi)發(fā)。

假設(shè)要開(kāi)發(fā)一個(gè)服務(wù)端和客戶端,服務(wù)端提供一個(gè)請(qǐng)求響應(yīng)接口,請(qǐng)求是 user_id,響應(yīng)是一個(gè) user 的數(shù)據(jù)結(jié)構(gòu)對(duì)象。

首先定義一個(gè) IDL,使用 PB 來(lái)做 Schema 聲明,IDL 描述如下,第一個(gè) Request 是請(qǐng)求,第二個(gè) Person 是響應(yīng)的對(duì)象結(jié)構(gòu)。

然后使用 codegen 生成對(duì)應(yīng)的代碼,例如生成了 PersonPB.Request 和 PersonPB.Person 兩個(gè) class。

server 端需要開(kāi)發(fā)請(qǐng)求響應(yīng)接口,API 是 PersonPB.Person doSmth(PersonPB.Request req),實(shí)現(xiàn)如下,包含一個(gè) Interface 和一個(gè)實(shí)現(xiàn) class。

server 返回的是一個(gè) Person 對(duì)象,里面的內(nèi)容主要就是上面講到的 PB 例子里面的。

啟動(dòng) server。在 8098 端口開(kāi)啟服務(wù),客戶端需要靠 id=100 這個(gè)標(biāo)識(shí)來(lái)路由到這個(gè)服務(wù)。

至此,服務(wù)端開(kāi)發(fā)完畢,可以看出使用一個(gè)完善的 RPC 框架,只需要定義好 Schema 和業(yè)務(wù)邏輯就可以發(fā)布一個(gè) RPC,而 I/O model、線程模型、序列化 / 反序列化、協(xié)議結(jié)構(gòu)均由框架服務(wù)。

navi-pbrpc 底層使用 Netty,在 Linux 下會(huì)使用 epoll 做 I/O 多路復(fù)用,線程模型默認(rèn)采用 Reactor 模式,序列化和反序列化使用 PB,協(xié)議結(jié)構(gòu)見(jiàn)上文部分介紹的,是一個(gè)標(biāo)準(zhǔn)的 header+payload 結(jié)構(gòu)。

下面開(kāi)發(fā)一個(gè) client,調(diào)用剛剛開(kāi)發(fā)的 RPC。

client 端代碼實(shí)現(xiàn)如下。首先構(gòu)造 PbrpcClient,然后構(gòu)造 PersonPB.Request,也就是請(qǐng)求,設(shè)置好 user_id,構(gòu)造 PbrpcMsg 作為 TCP 層傳輸?shù)臄?shù)據(jù) payload,這就是協(xié)議結(jié)構(gòu)中的 body 部分。

通過(guò) asyncTransport 進(jìn)行通信,返回一個(gè) Future 句柄,通過(guò) Future.get 阻塞獲取結(jié)果并且打印。

至此,可以看出作為一個(gè) RPC client 易用性是很簡(jiǎn)單的,同時(shí)可靠性,例如重試等會(huì)由 navi-pbrpc 框架負(fù)責(zé)完成,用戶只需要聚焦到真正的業(yè)務(wù)邏輯即可。

下面繼續(xù)深入到 binary stream 級(jí)別觀察,使用嗅探工具來(lái)看看 TCP 包。一般使用 wireshark 或者 tcpdump。

客戶端的一次請(qǐng)求調(diào)用如下圖所示,第一個(gè)包就是 TCP 三次握手的 SYN 包。

根據(jù) TCP 頭協(xié)議,可看出來(lái)。

  • ff 15 = 65301 是客戶端的端口

  • 1f a2 = 8098 是服務(wù)端的端口

  • header 的長(zhǎng)度 44 字節(jié)是 20 字節(jié)頭 +20 字節(jié) option+padding 構(gòu)成的。

三次握手成功后,下面客戶端發(fā)起了 RPC 請(qǐng)求,如下圖所示。

可以看出 TCP 包含了一個(gè) message,由 navi-pbrpc 的協(xié)議棧規(guī)定的 header+payload 構(gòu)成,

繼續(xù)深入分析 message 中的內(nèi)容,如下圖所示:

其中

  • 61 70 = ap 是頭中的的 provider 標(biāo)識(shí)

  • body length 是 2,注意 navi-pbrpc 采用了小尾端。

  • payload 是 08 7f,08 在 PB 中理解為第一個(gè)屬性,是 varint 整型,7f 表示傳輸?shù)氖?127 這個(gè)整型。

服務(wù)端響應(yīng) RPC 請(qǐng)求,還是由 navi-pbrpc 的協(xié)議棧規(guī)定的 header+payload 構(gòu)成,可以看出 body 就是 PB 例子里面的二進(jìn)制數(shù)據(jù)。

最后,客戶端退出,四次分手結(jié)束。

總結(jié)

本文系統(tǒng)性地介紹了 RPC 包含的核心概念和技術(shù),帶著讀者從一個(gè)實(shí)際的例子去映射理解。很多東西都是蜻蜓點(diǎn)水,每一個(gè)關(guān)鍵字都能成為一個(gè)很大的話題,希望這個(gè)提綱挈領(lǐng)的介紹可以讓讀者在大腦里面有一個(gè)系統(tǒng)的體系去看待 RPC。

歡迎訪問(wèn)作者的博客 http://neoremind.com。

作者介紹

張旭,目前工作在 Hulu,從事 Big data 領(lǐng)域的研發(fā)工作,曾經(jīng)在百度 ECOM 和程序化廣告部從事系統(tǒng)架構(gòu)工作,熱愛(ài)開(kāi)源,在 github 貢獻(xiàn)多個(gè)開(kāi)源軟件,id:neoremind,關(guān)注大數(shù)據(jù)、Web 后端技術(shù)、廣告系統(tǒng)技術(shù)以及致力于編寫(xiě)高質(zhì)量的代碼。

今日薦文

點(diǎn)擊下方圖片即可閱讀

如何保障微服務(wù)架構(gòu)下的數(shù)據(jù)一致性


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
如何實(shí)現(xiàn)一個(gè)分布式RPC框架
SOFARPC 性能優(yōu)化實(shí)踐(上)| SOFAChannel#2 直播整理
gRPC:Google開(kāi)源的基于HTTP/2和ProtoBuf的通用RPC框架
JAVA RPC:從上手到愛(ài)不釋手
字節(jié)跳動(dòng)微服務(wù)架構(gòu)下的高性能優(yōu)化實(shí)踐
百度正式開(kāi)源其RPC框架brpc
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服