天天看點

HTTP和RPC的關系分析

RPC由來:

RPC 風格對應的是 Restful風格。 出發點: RPC 的含義來看(遠端過程調用) ,認為隻要實作遠端調用即可,實作的方式可以是HTTP基于應用層的協定,也可以是Socket基于傳輸層協定 因為Socket程式設計是比較複雜的,是以Dubbo在Socket程式設計方面是用的Netty來實作。是以RPC隻是一種風格。 舉一個例子: 谷歌的grpc架構,底層就是基于Http2.0 來實作。差別的話,有人認為http不屬于rpc體系,基于socket的tcp方式通信的才算rpc。然而rpc的原理就是。a主機去通路b主機擷取相應資訊。是以http妥妥的屬于rpc的一種,rpc是概念,http是實作方式的一種。

RPC要解決的兩個問題:

  1. 解決分布式系統中,服務之間的調用問題。
  2. 遠端調用時,要能夠像本地調用一樣友善,讓調用者感覺不到遠端調用的邏輯。

HTTP與RPC的關系:

http與rpc: HTTP 調用其實也是一種特殊的 RPC,HTTP協定可以認為是RPC傳輸協定的一個子集。HTTP1.0 協定時,HTTP 調用還隻能是短連結調用,一個請求來回之後連接配接就會關閉。HTTP1.1 在 HTTP1.0 協定的基礎上進行了改進,引入了 KeepAlive 特性可以保持 HTTP 連接配接長時間不斷開,以便在同一個連接配接之上進行多次連續的請求,進一步拉近了 HTTP 和 RPC 之間的距離。當 HTTP 協定進化到 2.0 之後,Google 開源了一個建立在 HTTP2.0 協定之上的通信架構直接取名為 gRPC,也就是 Google RPC,這時 HTTP 和 RPC 之間已經沒有非常明顯的界限了。其實http是最常用的承載RPC的通信協定之一。而且我們可以在http 上傳輸xml和json這樣的文本協定,也可以是protobuf和thrift這樣的二進制協定,這都不是問題。大家常用的REST api就可以很好的封裝成rpc。當然,http這種協定是笨重一些,但它的穿透性比較好,配套的設施也齊全,也比較簡單直覺。

IPC與RPC: 如果兩個子系統沒有在網絡上進行分離,而是運作在同一個作業系統執行個體之上的兩個程序時,它們之間的通信手段還可以更加豐富。除了以上提到的幾種分布式解決方案之外,還有共享記憶體、信号量、檔案系統、核心消息隊列、管道等,本質上都是通過作業系統核心機制來進行資料和消息的互動而無須經過網絡協定棧。但在現代企業服務中,這種單機應用已經非常少見了,因為單機應用意味着單點故障 —— “一人摔跤全家跌倒”。業務子系統往往都需要經實體網絡棧進行隔離,是以分布式解決方案在要求高可用無間斷服務的企業環境裡便大有作為,這也讓 RPC 迎來自己大放異彩的時代。

為什麼有的RPC架構會自定義 tcp 協定而不是http協定的 rpc 做後端程序通信?

RPC是一種技術的概念名詞,RPC=Remote Produce Call 是一種技術的概念名詞,HTTP是一種協定,RPC可以通過 HTTP 來實作,也可以通過Socket自己實作一套協定來實作。為何 RPC 還有除 HTTP 之外的實作法,有何必要,畢竟除了HTTP實作外,私有協定不具備通用性。要解決這個問題就應該搞清楚 http 使用的 tcp 協定,和我們自定義的 tcp 協定在封包上的差別。首先要否認一點 http 協定相較于自定義tcp封包協定,增加的開銷在于連接配接的建立與斷開。http協定是支援連接配接池複用的,也就是建立一定數量的連接配接不斷開,并不會頻繁的建立和銷毀連接配接。二一要說的是http也可以使用protobuf這種二進制編碼協定對内容進行編碼,是以二者最大的差別還是在傳輸協定上。通用定義的http1.1協定的tcp封包包含太多廢資訊,一個POST協定的格式大緻如下

HTTP/1.0 200 OK 
Content-Type: 
Content-Length: 12343
Expires: 
Last-Modified:
Server: 
           

即使編碼協定也就是body是使用二進制編碼協定,封包中繼資料也就是header頭的鍵值對卻用了文本編碼,非常占位元組數。如上圖所使用的封包中有效位元組數僅僅占約 30%,也就是70%的時間用于傳輸中繼資料廢編碼。當然實際情況下封包内容可能會比這個長,但是報頭所占的比例也是非常可觀的。那麼假如我們使用自定義tcp協定, 報頭占用的位元組數也就隻有16個byte,極大地精簡了傳輸内容。這也就是為什麼後端程序間通常會采用自定義tcp協定的rpc來進行通信的原因。

自定義RPC傳輸協定與http差別:

  1. 自定義TCP傳輸協定在第四層,不用到osi的第七層,簡化傳輸協定。
  2. 自定義TCP傳輸協定傳輸資料少了備援資料。傳輸時間短,性能高。
  3. tcp支援長連結。
  4. 支援的資料類型多
  5. rpc傳輸的是二進制,http傳輸的是文本,就拿數字類型來說,http傳輸的是字元串,但是rpc傳輸的内容幾個位元組,資料量就更少了
  6. rpc的缺點:修改協定麻煩,服務端修改協定很可能會導緻用戶端調用失敗。
  7. http普适度高。特别适用于web服務。基于應用級的接口使用友善,要求的開發水準不高,容錯性強。但是傳輸速度慢,資料包大,如實作實時互動,伺服器性能壓力大,資料傳輸安全性差。
  8. 速度來看,RPC要比http更快,雖然底層都是TCP,但是http協定的資訊往往比較臃腫;難度來看,RPC實作較為複雜,http相對比較簡單;靈活性來看,http更勝一籌,因為它不關心實作細節,跨平台、跨語言。

應用場景:

  • 如果對效率要求更高,并且開發過程使用統一的技術棧,那麼用RPC還是不錯的。
  • 如果需要更加靈活,跨語言、跨平台,顯然http更合适
  • 微服務,更加強調的是獨立、自治、靈活。而RPC方式的限制較多,是以微服務架構中,有大部分會采用基于Http的Rest風格服務。

RPC與HTTP收發包

TCP/IP協定中針對TCP預設開啟了Nagle算法。Nagle算法通過減少需要傳輸的資料包,提高網絡的使用率,來優化網絡。rpc協定按照協定幀格式從tcp緩沖區讀取協定幀大小的幀資料,解壓到responpacket結構體。

for !c.isClosed {

		// 檢查上遊是否關閉
		select {
		case <-c.ctx.Done():
			return
		default:
		}
...
		req, err := c.fr.ReadFrame()
...
}
           

RPC(包含http)都是基于tcp發送/接收緩沖區的收發包:

  • 發送端發送資料,資料先通過網卡到服務端tcp的receive buffer中。服務端的上層應用如果需要讀取資料,會申請一段業務buffer,調用JDK的IO接口,IO會将tcpreceive buffer的資料拷貝到業務的buffer裡面。上層業務再通過設定的反序列化協定将業務buffer轉換成對象進行業務處理。
  • 服務端讀取資料時,先申請一段業務buffer(大小一般是1k),通過調用JDK的channel.read(buffer) IO方法,IO會将tcp buffer的資料拷貝到業務buffer裡面。傳回值為讀取位元組的個數:如果傳回值大于0,說明讀取到了對應大小的資料;如果是0,表示沒有讀到資料,資料讀取完成(可能業務buffer是滿的,不能往裡面寫資料);如果是-1,代表tcp連接配接被關閉(一般處理是關閉到該連接配接)