RPC 設計可擴充套件且向後相容的協議

2022-09-19 21:36:27 字數 2874 閱讀 3133

協議:怎麼設計可擴充套件且向後相容的協議?

瀏覽器收到命令後會封裝乙個請求,並把請求傳送到 dns 解析出來的 ip 上,通過抓包工具我們可以抓到請求的資料報,如下圖所示:

協議的作用

rpc 請求在傳送到網路中之前,他需要把方法呼叫的請求引數轉成二進位制;轉成二進位制後,寫入本地 socket 中,然後被網絡卡傳送到網路裝置中。

但在傳輸過程中,rpc 並不會把請求引數的所有二進位制資料整體一下子傳送到對端機器上,中間可能會拆分成好幾個資料報,也可能會合併其他請求的資料報(合併的前提是同乙個 tcp 連線上的資料),至於怎麼拆分合併,這其中的細節會涉及到系統引數配置和 tcp 視窗大小。對於服務提供方應用來說,他會從 tcp 通道裡面收到很多的二進位制資料,那這時候怎麼識別出哪些二進位制是第乙個請求的呢?

為了避免語義不一致的事情發生,我們就需要在傳送請求的時候設定乙個邊界,然後在收到請求的時候按照這個設定的邊界進行資料分割。這個邊界語義的表達,就是我們所說的協議。

如何設計協議

從 rpc 的作用說起,相對於 http 的用處,rpc 更多的是負責應用間的通訊,所以效能要求相對更高。但** http 協議的資料報大小相對請求資料本身要大很多,又需要加入很多無用的內容,比如換行符號、回車符等;還有乙個更重要的原因是,http 協議屬於無狀態協議**,客戶端無法對請求和響應進行關聯,每次請求都需要重新建立連線,響應完成後再關閉連線。因此,對於要求高效能的 rpc 來說,http 協議基本很難滿足需求,所以 rpc 會選擇設計更緊湊的私有協議。

那怎麼設計乙個私有 rpc 協議呢?

rpc 每次發請求發的大小都是不固定的,所以我們的協議必須能讓接收方正確地讀出不定長的內容。

先設計乙個固定長度的:先固定乙個長度(比如 4 個位元組)用來儲存整個請求資料大小,讀取固定長度的位置裡面的值,值的大小就代表協議體的長度,接著再根據值的大小來讀取協議體的資料,整個協議可以設計成這樣:

不定長協議:

但這種協議只是實現了正確的斷句效果,在rpc中是行不通的,因為服務提供方並不知道它的序列化方式是什麼,也就不能將二進位制資料還原成物件。因此,需要將序列化方式單獨拿出來,類似協議長度一樣用固定的長度存放,這些需要固定長度存放的引數統稱為「協議頭」,整個協議就被拆分為:協議頭協議體兩部分。

在協議頭裡面,我們除了會放協議長度、序列化方式,還會放一些像協議標示、訊息 id、訊息型別這樣的引數,而協議體一般只放請求介面方法、請求的業務引數值和一些擴充套件屬性。協議頭是由一堆固定的長度引數組成,而協議體是根據請求介面和引數構造的,長度屬於可變的,具體協議如下圖所示:

定長協議:

1:bit offset——標識協議的其實位置

2:魔術位——標識是什麼協議

3:整體長度——標識整個協議有多長,減去協議頭長度就是協議體長度

4:頭長度——標識協議頭的長度,因為頭是可擴充套件的,所以具體長度不固定,需要標識一下

5:協議版本——標識當前協議的版本,用於協議相容性控制

6:訊息型別——標識訊息的型別,對於文字的需要,這裡也需要嘛?協議型別可能是物件?可能是xml檔案?可能是json碼?正常來講應該都是物件才對,讓用於反序列化,猜測是為了擴充套件預留的

7:序列化方式——用於訊息的序列化和反序列化

8:訊息id——用於表示請求和響應的關係

9:協議頭擴充套件字段——用於擴充套件協議頭,是協議具有擴充套件性,更加的靈活可控

10協議體——協議的內容,一堆堆的二進位制資料,雙方溝通的東西

協議頭——規定資訊轉換的規則

協議體——資訊真正的內容,由於在傳輸層對人不友好對應用程式也不友好需要轉換一下

可擴充套件的協議

上面的協議為定長協議,那如果如果想在協議體重放一些擴充套件屬性怎麼辦?

協議體裡面是可以加新的引數,但這裡有乙個關鍵點,就是協議體裡面的內容都是經過序列化出來的,也就是說你要獲取到你引數的值,就必須把整個協議體裡面的資料經過反序列化出來。但在某些場景下,這樣做的代價有點高啊!

所以為了保證能平滑地公升級改造前後的協議,我們有必要設計一種支援可擴充套件的協議。其關鍵在於讓協議頭支援可擴充套件,擴充套件後協議頭的長度就不能定長了。

那要實現讀取不定長的協議頭裡面的內容,在這之前肯定需要乙個固定的地方讀取長度,所以需要乙個固定的寫入協議頭的長度。整體協議就變成了三部分內容:固定部分、協議頭內容、協議體內容,前兩部分我們還是可以統稱為「協議頭」,具體協議如下:

可擴充套件協議:

設計乙個簡單的 rpc 協議並不難,難的就是怎麼去設計乙個可「公升級」的協議。不僅要讓我們在擴充套件新特性的時候能做到向下相容,而且要盡可能地減少資源損耗,所以我們協議的結構不僅要支援協議體的擴充套件,還要做到協議頭也能擴充套件。

ps:rpc 不直接用 http 協議的乙個原因是無法實現請求跟響應關聯,每次請求都需要重新建立連線,響應完成後再關閉連線,所以我們要設計私有協議。那麼在 rpc 裡面,我們是怎麼實現請求跟響應關聯的呢?

一般rpc為了效能,會採用非同步通訊的方式,請求響應對應關聯,就需要乙個類似身份證號的id,訊息id

如何設計可擴充套件的RPC協議

只有二進位制才能在網路中進行傳輸,在rpc請求傳送到網路之前,需要轉化成二進位制,然後寫入本地socket,然後通過網絡卡傳送到網路裝置中。類似於乙個沒有標點符號的文章,我們要想識別,就必須有標點,所以協議就是給我們斷句提供依據。為了能合適的斷句,我們可以設計乙個固定乙個長度記錄整個請求的資料大小,...

可擴充套件的檔案同步設計

在老的cms系統中通過新配置的同步系統,對cms生成的檔案進行同步。方便對機器新增的擴充套件,新新增的機器首先執行同步初始化的功能模組,此圖暫時沒有加上。在同步模組中進行配置源與目標伺服器的服務模組url。cms的新聞新增,修改及刪除需增加同步函式,以使得新聞新增修改和刪除的動作記錄到同步表中。同步...

可擴充套件系統設計的要點

根據以往經驗和的總結 縱向擴充套件 硬體方面可以更換更強勁的伺服器,增加 cpu 記憶體,使用高速磁碟。軟體方面可以對現有 的優化,重構。使用 non blocking 非阻塞 io 模式,或者非同步 io 模式,使用執行緒模式或者改用 事件驅動形模式。目標是提高單機 qps 連線數,來支援更多的連...