亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

網絡協(xié)議 22 - RPC 協(xié)議(下)- 二進制類 RPC 協(xié)議

付倫 / 1656人閱讀

摘要:但是只不過都是以二進制的形式編碼的。這其實相當于綜合了和二進制共同優(yōu)勢的一個協(xié)議。在上面的架構中,如果使用二進制的方式進行序列化,雖然不用協(xié)議文件來生成,但是對于接口的定義,以及傳的對象,還是需要共享。

????前面我們認識了兩個常用文本類的 RPC 協(xié)議,對于陌生人之間的溝通,用 NBA、CBA 這樣的縮略語,會使得協(xié)議約定非常不方便。

????在講 CDN 和 DNS 的時候,我們講過接入層的設計,對于靜態(tài)資源或者動態(tài)資源靜態(tài)化的部分都可以做緩存。但是對于下單、支付等交易場景,還是需要調用 API。

????對于微服務的架構,API 需要一個 API 網關統(tǒng)一的管理。API 網關有多種實現方式,用 Nginx 或者 OpenResty 結合 Lua 腳本是常用的方式。在上一節(jié)講過的 Spring Cloud 體系中,有個組件 Zuul 也是干這個的。

數據中心內部是如何相互調用的?

????API 網關用來管理 API,但是 API 的實現一般在一個叫作Controller 層的地方。這一層對外提供 API。由于是讓陌生人訪問的,我們能看到目前業(yè)界主流的,基本都是 RESTful 的 API,是面向大規(guī)?;ヂ?lián)網應用的。

????在 Controller 之內,就是咱們互聯(lián)網應用的業(yè)務邏輯實現。上節(jié)講 RESTful 的時候,說過業(yè)務邏輯的實現最好是無狀態(tài)的,從而可以橫向擴展,但是資源的狀態(tài)還需要服務端去維護。資源的狀態(tài)不應該維護在業(yè)務邏輯層,而是在最底層的持久化層,一般會使用分布式數據庫和 ElasticSearch。

????這些服務端的狀態(tài),例如訂單、庫存、商品等,都是重中之重,都需要持久化到硬盤上,數據不能丟,但是由于硬盤讀寫性能差,因而持久化層往往吞吐量不能達到互聯(lián)網應用要求的吞吐量,因而前面要有一層緩存層,使用 Redis 或者 memcached 將請求攔截一道,不能讓所有的請求都進入數據庫“中軍大營”。

????緩存和持久化層之上一般是基礎服務層,這里面提供一些原子化的接口。例如,對于用戶、商品、訂單、庫存的增刪查改,將緩存和數據庫對再上層的業(yè)務邏輯屏蔽一道。有了這一層,上層業(yè)務邏輯看到的都是接口,而不會調用數據庫和緩存。因而對于緩存層的擴容,數據庫的分庫分表,所有的改變,都截止到這一層,這樣有利于將來對于緩存和數據庫的運維。

????再往上就是組合層。因為基礎服務層只是提供簡單的接口,實現簡單的業(yè)務邏輯,而復雜的業(yè)務邏輯,比如下單,要扣優(yōu)惠券,扣減庫存等,就要在組合服務層實現。

????這樣,Controller 層、組合服務層、基礎服務層就會相互調用,這個調用是在數據中心內部的,量也會比較大,還是使用 RPC 的機制實現的。

????由于服務比較多,需要一個多帶帶的注冊中心來做服務發(fā)現。服務提供方會將自己提供哪些服務注冊到注冊中心中去,同時服務消費方訂閱這個服務,從而可以對這個服務進行調用。

????調用的時候有一個問題,這里的 RPC 調用,應該用二進制還是文本類?其實文本的最大問題是,占用字節(jié)數目比較多。比如數字 123,其實本來二進制 8 位就夠了,但是如果變成文本,就成了字符串 123。如果是 UTF-8 編碼的話,就是三個字節(jié);如果是 UTF-16,就是六個字節(jié)。同樣的信息,要多費好多的空間,傳輸起來也更加占帶寬,時延也高。

????因而對于數據中心內部的相互調用,很多公司選型的時候,還是希望采用更加省空間和帶寬的二進制的方案。

????這里一個著名的例子就是 Dubbo 服務化框架二進制的 RPC 方式。

????Dubbo 會在客戶端的本地啟動一個 Proxy,其實就是客戶端的 Stub,對于遠程的調用都通過這個 Stub 進行封裝。

????接下來,Dubbo 會從注冊中心獲取服務端的列表,根據路由規(guī)則和負載均衡規(guī)則,在多個服務端中選擇一個最合適的服務端進行調用。

????調用服務端的時候,首先要進行編碼和序列化,形成 Dubbo 頭和序列化的方法和參數。將編碼好的數據,交給網絡客戶端進行發(fā)送,網絡服務端收到消息后,進行解碼。然后將任務分發(fā)給某個線程進行處理,在線程中會調用服務端的代碼邏輯,然后返回結果。

????這個過程和經典的 RPC 模式何其相似??!

如何解決協(xié)議約定問題?

????接下來我們還是來看 RPC 的三大問題,其中注冊發(fā)現問題已經通過注冊中心解決了。我們下面就來看協(xié)議約定問題。

????Dubbo 中默認的 RPC 協(xié)議是 Hessian2。為了保證傳輸的效率,Hessian2 將遠程調用序列化為二進制進行傳輸,并且可以進行一定的壓縮。這個時候你可能會疑惑,同為二進制的序列化協(xié)議,Hessian2 和前面的二進制的 RPC 有什么區(qū)別呢?這不繞了一圈又回來了嗎?

????Hessian2 是解決了一些問題的。例如,原來要定義一個協(xié)議文件,然后通過這個文件生成客戶端和服務端的 Stub,才能進行相互調用,這樣使得修改就會不方便。Hessian2 不需要定義這個協(xié)議文件,而是自描述的。什么是自描述呢?

????所謂自描述就是,關于調用哪個函數,參數是什么,另一方不需要拿到某個協(xié)議文件、拿到二進制,靠它本身根據 Hessian2 的規(guī)則,就能解析出來。

????原來有協(xié)議文件的場景,有點兒像兩個人事先約定好,0 表示方法 add,然后后面會傳兩個數。服務端把兩個數加起來,這樣一方發(fā)送 012,另一方知道是將 1 和 2 加起來,但是不知道協(xié)議文件的,當它收到 012 的時候,完全不知道代表什么意思。

????而自描述的場景,就像兩個人說的每句話都帶前因后果。例如,傳遞的是“函數:add,第一個參數 1,第二個參數 2”。這樣無論誰拿到這個表述,都知道是什么意思。但是只不過都是以二進制的形式編碼的。這其實相當于綜合了 XML 和二進制共同優(yōu)勢的一個協(xié)議。

????Hessian2 是如何做到這一點的呢?這就需要去看 Hessian2 的序列化的語法描述文件。

????看起來很復雜,編譯原理里面是有這樣的語法規(guī)則的。

????我們從 Top 看起,下一層是 value,直到形成一棵樹。這里面的有個思想,為了防止歧義,每一個類型的起始數字都設置成為獨一無二的。這樣,解析的時候,看到這個數字,就知道后面跟的是什么了。

????這里還是以加法為例子,“add(2,3)”被序列化之后是什么樣的呢?

H x02 x00     # Hessian 2.0
C          # RPC call
 x03 add     # method "add"
 x92        # two arguments
 x92        # 2 - argument 1
 x93        # 3 - argument 2

H 開頭,表示使用的協(xié)議是 Hession,H 的二進制是 0x48

C 開頭,表示這是一個 RPC 調用

0x03,表示方法名是三個字符

0x92,表示有兩個參數。其實這里存的應該是 2,之所以加上 0x90,就是為了防止歧義,表示這里一定是一個 int

第一個參數是 2,編碼為 0x92,第二個參數是 3,編碼為 0x93

????這個就叫作自描述

????另外,Hessian2 是面向對象的,可以傳輸一個對象。

class Car {
 String color;
 String model;
}
out.writeObject(new Car("red", "corvette"));
out.writeObject(new Car("green", "civic"));
---
C            # object definition (#0)
 x0b example.Car    # type is example.Car
 x92          # two fields
 x05 color       # color field name
 x05 model       # model field name

O            # object def (long form)
 x90          # object definition #0
 x03 red        # color field value
 x08 corvette      # model field value

x60           # object def #0 (short form)
 x05 green       # color field value
 x05 civic       # model field value

????首先,定義這個類。對于類型的定義也傳過去,因而也是自描述的。類名為 example.Car,字符長 11 位,因而前面長度為 0x0b。有兩個成員變量,一個是 color,一個是 model,字符長 5 位,因而前面長度 0x05,。

????然后,傳輸的對象引用這個類。由于類定義在位置 0,因而對象會指向這個位置 0,編碼為 0x90。后面 red 和 corvette 是兩個成員變量的值,字符長分別為 3 和 8。

????接著又傳輸一個屬于相同類的對象。這時候就不保存對于類的引用了,只保存一個 0x60,表示同上就可以了。

????可以看出,Hessian2 真的是能壓縮盡量壓縮,多一個 Byte 都不傳。

如何解決 RPC 傳輸問題?

????接下來,我們再來看 Dubbo 的 RPC 傳輸問題。前面我們也說了,基于 Socket 實現一個高性能的服務端,是很復雜的一件事情,在 Dubbo 里面,使用了 Netty 的網絡傳輸框架。

????Netty 是一個非阻塞的基于事件的網絡傳輸框架,在服務端啟動的時候,會監(jiān)聽一個端口,并注冊以下的事件。

連接事件:當收到客戶端的連接事件時,會調用 void connected(Channel channel) 方法

可寫事件觸發(fā)時,會調用 void sent(Channel channel, Object message),服務端向客戶端返回響應數據

可讀事件觸發(fā)時,會調用 void received(Channel channel, Object message) ,服務端在收到客戶端的請求數據

發(fā)生異常時,會調用 void caught(Channel channel, Throwable exception)

????當事件觸發(fā)之后,服務端在這些函數中的邏輯,可以選擇直接在這個函數里面進行操作,還是將請求分發(fā)到線程池去處理。一般異步的數據讀寫都需要另外的線程池參與,在線程池中會調用真正的服務端業(yè)務代碼邏輯,返回結果。

????Hessian2 是 Dubbo 默認的 RPC 序列化方式,當然還有其他選擇。例如,Dubbox 從 Spark 那里借鑒 Kryo,實現高性能的序列化。

????到這里,我們說了數據中心里面的相互調用。為了高性能,大家都愿意用二進制,但是為什么后期 Spring Cloud 又興起了呢?這是因為,并發(fā)量越來越大,已經到了微服務的階段。同原來的 SOA 不同,微服務粒度更細,模塊之間的關系更加復雜。

????在上面的架構中,如果使用二進制的方式進行序列化,雖然不用協(xié)議文件來生成 Stub,但是對于接口的定義,以及傳的對象 DTO,還是需要共享 JAR。因為只有客戶端和服務端都有這個 JAR,才能成功地序列化和反序列化。

????但當關系復雜的時候,JAR 的依賴也變得異常復雜,難以維護,而且如果在 DTO 里加一個字段,雙方的 JAR 沒有匹配好,也會導致序列化不成功,而且還有可能循環(huán)依賴。這個時候,一般有兩種選擇。

第一種,建立嚴格的項目管理流程。

不允許循環(huán)調用,不允許跨層調用,只準上層調用下層,不允許下層調用上層

接口要保持兼容性,不兼容的接口新添加而非改原來的,當接口通過監(jiān)控,發(fā)現不用的時候,再下掉

升級的時候,先升級服務提供端,再升級服務消費端。

第二種,改用 RESTful 的方式。

使用 Spring Cloud,消費端和提供端不用共享 JAR,各聲明各的,只要能變成 JSON 就行,而且 JSON 也是比較靈活的

使用 RESTful 的方式,性能會降低,所以需要通過橫向擴展來抵消單機的性能損耗

小結

RESTful API 對于接入層和 Controller 層之外的調用,已基本形成事實標準,但是隨著內部服務之間的調用越來越多,性能也越來越重要,于是 Dubbo 的 RPC 框架有了用武之地

Dubbo 通過注冊中心解決服務發(fā)現問題,通過 Hessian2 序列化解決協(xié)議約定的問題,通過 Netty 解決網絡傳輸的問題

在更加復雜的微服務場景下,Spring Cloud 的 RESTful 方式在內部調用也會被考慮,主要是 JAR 包的依賴和管理問題

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://www.ezyhdfw.cn/yun/29968.html

相關文章

  • 網絡協(xié)議 22 - RPC 協(xié)議)- 進制 RPC 協(xié)議

    摘要:但是只不過都是以二進制的形式編碼的。這其實相當于綜合了和二進制共同優(yōu)勢的一個協(xié)議。在上面的架構中,如果使用二進制的方式進行序列化,雖然不用協(xié)議文件來生成,但是對于接口的定義,以及傳的對象,還是需要共享。 ????前面我們認識了兩個常用文本類的 RPC 協(xié)議,對于陌生人之間的溝通,用 NBA、CBA 這樣的縮略語,會使得協(xié)議約定非常不方便。 ????在講 CDN 和 DNS 的時候,我們...

    wing324 評論0 收藏0
  • 分布式服務框架之遠程通訊技術及原理分析

    摘要:微軟的雖然引入了事件機制,可以在隊列收到消息時觸發(fā)事件,通知訂閱者。由微軟作為主要貢獻者的,則對以及做了進一層包裝,并能夠很好地實現這一模式。 在分布式服務框架中,一個最基礎的問題就是遠程服務是怎么通訊的,在Java領域中有很多可實現遠程通訊的技術,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關系呢,它們背后到底是基...

    sorra 評論0 收藏0
  • 分布式服務框架之遠程通訊技術及原理分析

    摘要:微軟的雖然引入了事件機制,可以在隊列收到消息時觸發(fā)事件,通知訂閱者。由微軟作為主要貢獻者的,則對以及做了進一層包裝,并能夠很好地實現這一模式。 在分布式服務框架中,一個最基礎的問題就是遠程服務是怎么通訊的,在Java領域中有很多可實現遠程通訊的技術,例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關系呢,它們背后到底是基...

    0xE7A38A 評論0 收藏0
  • Java 遠程通訊技術及原理分析

    摘要:對于與而言,則可以看做是消息傳遞技術的一種衍生或封裝。在生產者通知消費者時,傳遞的往往是消息或事件,而非生產者自身。通過消息路由,我們可以配置路由規(guī)則指定消息傳遞的路徑,以及指定具體的消費者消費對應的生產者。采用和來進行遠程對象的通訊。 消息模式 歸根結底,企業(yè)應用系統(tǒng)就是對數據的處理,而對于一個擁有多個子系統(tǒng)的企業(yè)應用系統(tǒng)而言,它的基礎支撐無疑就是對消息的處理。與對象不同,消息本質上...

    rozbo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<