RPC – 麻雀雖小,五臟俱全

說起 RPC (遠程過程調用),大家應該不陌生。隨着微服務、分佈式越來越流行,RPC 應用越來越普遍。常見的 RPC 框架如:Dubbo、gRPC、Thrift 等。本篇文章不是介紹各種 RPC 的使用和對比。而是深入剖析一個 RPC 包含哪些內容。我最近在 Hadoop 的源碼,正好把 Hadoop RPC 看完了。感覺 Hadoop 的 RPC 框架設計的還是比價優秀的。Hadoop 作為大數據技術的基石,如果沒有一個高性能、高可靠的 RPC 框架,很難支撐上千台服務器規模的集群。因此,本篇文章就以 Hadoop RPC 為例,介紹一個 RPC 框架會涉及的技術。

架構設計

RPC 的架構涉及客戶端、網絡、服務端三大組件。網絡一般使用 socket ,更多的是基於現有的網絡框架進行參數的設置達到最優的目的。但是客戶端和服務端需要我們自己設計,並且對於分佈式框架來說,設計的架構應該有高性能、高可用以及可擴展的特點。

  • 高性能:由於客戶端同時發起多個請求,這就要求系統能夠快速處理,降低響應延遲。也就是高吞吐、低延遲。從客戶端角度來說,由於創建客戶端到服務端的連接成本較高。因此可以緩存連接資源,從而實現多個客戶端復用相同的連接資源,避免每個客戶端都來創建而降低性能;從服務端角度來說,可以啟動多線程來併發處理客戶端請求。除了多線程,可以採用 Reactor 編程模式,提高多線程併發的性能。
  • 高可用:當我們的服務端掛了,能不能有備用節點繼續提供服務。Hadoop 2.x 實現了 NameNode 的高可用。當客戶端需要通過 RPC 調用 NameNode 服務的過程中,如果主 NameNode 宕機,那麼備用 NameNode 會升級成活動節點。同時會將 RPC 的請求發送的當前活躍的 NameNode,從而繼續提供可用的服務,而這個過程對客戶端來說是透明的。
  • 可擴展性:一個框架需要不斷地優化、不斷升級。需要在架構設計時明確不變的需求點,以及可變的需求點,對於可變的需求需要能夠有良好的可擴展性。以 RPC 涉及的序列化為例。由於不同序列化框架適用場景不同,因此這需要被當成可變的需求點,應該將其設計成可擴展的,能夠容易地支持不同的序列化框架。目前,Hadoop RPC 支持自身的序列化框架(Writable)和 Protoc Buffer。

設計模式

設計模式更多地與上面提到的可擴展性相呼應。良好的設計模式可以提高代碼復用性、增強可擴展性,同時能夠降低 BUG 數量。Hadoop RPC 中涉及的設計模式比較多,大概包括:工廠模式、代理模式、適配器模式、裝飾者模式和命令模式等。以代理模式為例,當客戶端調用遠程方法時,實際上是通過代理,將方法名和參數通過網絡發送到服務端。但這個過程對客戶端是透明的,對於客戶端來說就像調用本地方法一樣。

除了設計模式,在工程實踐中還應該注意遵循常見的設計原則。

多線程

在任何一個系統中多線程都比較常見。通過多線程併發處理,提高系統的吞吐量。在 Hadoop RPC 中,客戶端與服務端都用到了多線程技術。客戶端開啟多線程,每個線程處理一類請求,並且緩存連接資源。服務端也是多線程併發處理客戶端的請求,使用 Reactor 編程模式提高併發性能。

談到多線程就不得不提另一個話題 —— 線程安全。Hadoop RPC 中用了不少的技術來保證線程安全,包括:synchronized、concurrent併發包、atomic併發包和 nio 工具包。從優秀框架中學習線程安全,對我們以後併發編程有不少好處。

序列化與反序列化

由於 RPC 涉及數據在網絡上傳輸,因此需要一個優秀的序列化框架,既能夠高效的編碼與解碼,且編碼后的數據大小又盡可能小。不同的序列化框架主要是在編解碼效率和編碼大小兩個主要方面做權衡。Hadoop RPC 目前支持兩種序列化框架,一個是 Hadoop 自己實現的 Writable 框架,另一個是 Protocol Buffer。Hadoop RPC 雖然支持 Writable 序列化框架,但還是以 Protocol Buffer 為主。因為 Protocol Buffer 從編解碼效率和編碼大小方便都是比較優秀的。當然常見的序列化包括 Avro、Kryo 等,有興趣的讀者可以查一下它們之間的性能對比。

其他

一個 RPC 框架,除了包含上面提到比較主要的方面。還有一些其他的方面

  • 語言層面:利用好 Java 語言的繼承、組合、封裝、多態等特性。甚至包括泛型、註解等。
  • 代碼規範:良好的工程實現應該有一個良好的代碼規範。在 Hadoop 中,代碼風格比較統一,且每個重要的類都有詳細的註釋,在關鍵的方法或者屬性上也有明確的註釋。我在自己的工程中會使用阿里的 Java 代碼規約插件,也會為了讓自己的代碼更規範。
  • 異常處理:對於一個優秀的框架異常處理很關鍵,什麼時候需要拋出異常、拋出什麼樣的異常以及什麼時候需要處理異常。在 RPC 中除了需要處理本地異常還要處理遠程服務的異常。因此,在程序中如何優雅的處理異常也是體現一個程序員能力的地方。
  • 網絡編程:RCP 中涉及的網絡編程一般用 socket,Hadoop RPC 使用的 Reactor 模式的網絡編程,並且 Netty 也在使用這種框架。我們有必要會用並且掌握它。

 這一段寫的比較雜,想到哪寫到哪。最近有跟朋友聊過在看 RPC 相關的東西,朋友說:“一個 RPC 能夠涉及多少東西?值得研究?”。其實我一開始也是這樣想的,無非就是客戶端將請求序列化,通過網絡發給服務端,服務端反序列化調用函數后再返回。但是看了 Hadoop RPC 代碼后,我發現這樣框架涉及的知識還是特別多的,並且還比較系統,基本上包含了我們平時編程涉及的方方面面。同時它不再是一個單機程序,而是一個 C/S 架構的程序。如果我們有興趣還可以繼續研究他的高可用,從而對分佈式應用有更深入的了解。

我覺得 RPC 是麻雀雖小五臟俱全。由於它涉及了我們編程的方方面面,所以我想基於 Hadoop RPC 做一個詳細的教程,把它涉及的每個重要部分都進行詳細的分析,上面提到的內容基本都會涵蓋。對於想了解 RPC 的讀者,能夠感受到一個 RPC 框架更清晰的面貌。對於僅有 Java 基礎的讀者來說,能夠學到編寫一個框架所涉及的具體編程技術,同時能夠從世界頂級開源項目學到優秀設計和工程經驗。

小結 

本篇文章主要介紹了 RPC 框架涉及的知識。包括:架構設計、設計模式以及設計原則、多線程併發以及線程安全、序列化框架和一些其他的內容。我覺得學習最好的方式就是從優秀的框架中學習、模仿。好比我們練書法基本都要經過臨摹這一步。當然直接看別人的代碼確實需求花費更多的時間和經歷,並且有時候投入與產出並不成正比。所以,我想把我在 Hadoop RPC 框架中學到的優秀的設計和實現能夠整理成教程,以便有興趣的讀者學習。如果有任何建議歡迎與我交流。公眾號有福利

公眾號「渡碼」

 

【精選推薦文章】

自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"