我開始抄程式碼來學編程
- 2019 年 10 月 21 日
- 筆記
之前研究 Hadoop 源碼,把 hadoop-common 模組下的 RPC 模組源碼通讀一遍,又花了 3 個月抄了一遍 Hadoop RPC 程式碼,學到很多東西。我覺得學習編程最有效的方式就是抄程式碼,我覺得這個過程對正在學編程的朋友很有幫助,所以想做成教程,以下是周末寫的一個開頭,後續教程的形式以及進展會發布在公眾號,有興趣的朋友歡迎文末關注。
1. 起源
故事得從19年上半年說起,那時候我正打算研究一下Hadoop源碼。 現在大家都聽說過Hadoop,它是一個分散式存儲和計算的框架。作為分散式系統,節點之間的通訊、互動式必不可少的。Hadoop自己實現了RPC(Remote Procedure Call,遠程過程調用)模組來滿足這樣的需求。帶著好奇,我便閱讀了整個Hadoop RPC模組的源程式碼,讀完後發現這個模組設計的非常好,與其他模組無耦合,完全可以獨立出來當成一個獨立的框架。為了能夠學習相關的編程知識,同時還可以看到Apache 頂級開源項目的程式碼如何編寫的,因此我便把Hadoop RPC模組做成教程。
雖然這個項目是實現RPC功能,但我覺得我們重點不應該過多關注RPC本身,而應該重點學習RPC所涉及的客戶端開發、服務端開發、網路編程、多執行緒、並發編程、設計模式等核心知識,尤其是對於剛學習Java沒有接觸線上實戰項目的朋友,掌握好了這些知識,寫其他項目也會更有思路。
2. 起名
為了能讓不熟悉Hadoop的朋友也能學習本教程,因此我們將Hadoop RPC賦予了新的業務含義。
假設我們有這樣一個場景,公司開發一個新的資料庫,這個資料庫的底層可能是Mysql,也可能是MongoDB,甚至可能是公司自研的資料庫技術,無論是什麼,資料庫都可以作為服務端。作為用戶來說,資料庫底層用了什麼技術並不關係,而是關心怎麼使用。資料庫需要提供了API方便用戶調用,因此就需要有客戶端。
實現連接客戶端請求和服務端響應的技術就是RPC。我給這個項目起了一個名字叫Manis,那麼,資料庫的名字便是ManisDb。工作中我們也比較鼓勵大家給自己的項目起個名字,有了名字,它就像自己的孩子一樣,我們會更有責任心把它做好。
3. 優勢
優勢都是相對的。Hadoop RPC 相比於一般的實戰項目來說,它是經過線上檢驗的,Hadoop集群規模最大達到上萬台,單一個RPC模組完全可以獨立出來用於實戰。同時,我們還可以積累頂級開源項目的開發經驗,大到架構設計,小到設計模式,程式碼規範。RPC在客戶端開發、服務端開發、網路編程三方面都有涉及,且都是重點內容。
Hadoop RPC相比於源碼分析類的教程來說,優勢在於實戰意義比較強。我們會按照Hadoop RPC源碼把我們的野生項目Manis從0到1完整的敲一遍,還原度為95%。解釋下為什麼不是100%,一方面為了突出重點,我會把不太重要、不是很核心的技術捨棄掉。另一方面為了符合新的業務定義,我會做一些改進,而不是照搬Hadoop RPC。比如:Hadoop RPC到了2.6版本只支援Protobuf序列化協議,但為了體現高擴展以及模組間的低耦合,Manis支援了多種序列化協議。
在寫教程之前,我花了大概3個月時間先對照Hadoop RPC源碼把Manis敲出來了。學會了Manis後,你完全有能力閱讀Hadoop RPC的源碼,這也算是面試的加分項吧。可能有些讀者覺得這種方式比較LOW,但我還是相信馬化騰說的“抄程式碼培養感覺”,寫程式碼好比學字畫,不臨摹好的作品怎麼學習別人的優點。真正要把看到的東西變成自己的,最終紮實的方式就是自己走一遍。至於Manis中被捨棄的部分我會在教程中說明,必要的時候會截取Hadoop源碼一起分析。
4. Manis架構圖
圖1-1是Manis的架構圖,基本上是一般的RPC架構圖。
圖1-1 Manis架構圖
5. Manis核心組件時序圖
圖1-2 Manis 核心組件時序圖
6. Manis核心組件概念
結合圖1-2對Manis中涉及的核心的組件概念進行說明。
ManisDb:圖中沒有表示,它代表資料庫,負責啟動服務端(即ipc.Server類),這裡需要說明一下我們的重點在於RPC開發,這裡的資料庫只是舉一個例子,不會涉及真正的資料庫開發。
ManisClient:提供給普通用戶的客戶端類,用於對ManisDb進行增刪改查,它使用Protobuf協議與ManisDb進行通訊。
Manager:提供給管理員的客戶端類,用於對ManisDb進行管理,它使用Serializable協議(Java原生的序列化方式)與ManisDb進行通訊
ProtoBufRpcEngine:支援Protobuf協議的RPC引擎,它定義了兩個內部類——Invoker類和ProtoBufRpcInvoker類。Invoker類用於封裝客戶端的調用請求,並使用Protobuf協議序列化。ProtoBufRpcInvoker類用於完成客戶端請求的方法調用(服務端調)。
SerializableRpcEngine:支援Serializable協議的RPC引擎,它定義兩個內部類——Invoker類和SerializableRpcInvoker類。Invoker類用於封裝客戶端的調用請求,並使用Serializable協議序列化。SerializableRpcInvoker類用於完成客戶端請求的方法調用(服務端調)。
Client:建立與服務端的socket連接,接收客戶端調用,並發送調用請求給服務端,等待服務端返回並將結果返回。
ipc.Server:該類定義在ipc包下面,通過Reactor模式接收並處理客戶端請求,最終調用ProtoBufRpcInvoker或SerializableRpcInvoker的方法獲得結果,並返回給客戶端。
公眾號「渡碼」,分享更多高品質內容