花了快2個月!Guide自己動手寫了一個簡單的RPC框架!

Github地址:https://github.com/Snailclimb/guide-rpc-framework (歡迎star,歡迎一起完善!共勉!)

前言

大概 2 個月前,我說過要利用業餘時間寫一個簡單的 RPC 框架,今天(2020-06-05)總算將其開源出來,希望對小夥伴們有幫助。

雖說 RPC 的原理實際不難,但是,自己在實現的過程中自己也遇到了很多問題。Guide-rpc-framework 目前只實現了 RPC 框架最基本的功能,一些可優化點都在下面提到了,有興趣的小夥伴可以自行完善。

介紹

guide-rpc-framework 是一款基於 Netty+Kyro+Zookeeper 實現的 RPC 框架。代碼註釋詳細,結構清晰,並且集成了 Check Style 規範代碼結構,非常適合閱讀和學習。

由於 Guide 哥自身精力和能力有限,如果大家覺得有需要改進和完善的地方的話,歡迎將本項目 clone 到自己本地,在本地修改後提交 PR 給我,我會在第一時間 Review 你的代碼。

我們先從一個基本的 RPC 框架設計思路說起!

一個基本的 RPC 框架設計思路

一個典型的使用 RPC 的場景如下,一般情況下 RPC 框架不僅要提供服務發現功能,還要提供負載均衡、容錯等功能,這個的 RPC 框架纔算真正合格。

一個完整的RPC框架使用示意圖

簡單說一下設計一個最基本的 RPC 框架的思路:

  1. 註冊中心 :註冊中心首先是要有的,推薦使用 Zookeeper。註冊中心主要用來保存相關的信息比如遠程方法的地址。
  2. 網絡傳輸 :既然要調用遠程的方法就要發請求,請求中至少要包含你調用的類名、方法名以及相關參數吧!推薦基於 NIO 的 Netty 框架。
  3. 序列化 :既然涉及到網絡傳輸就一定涉及到序列化,你不可能直接使用 JDK 自帶的序列化吧!JDK 自帶的序列化效率低並且有安全漏洞。 所以,你還要考慮使用哪種序列化協議,比較常用的有 hession2、kyro、protostuff。
  4. 動態代理 : 另外,動態代理也是需要的。因爲 RPC 的主要目的就是讓我們調用遠程方法像調用本地方法一樣簡單,使用動態代理屏蔽遠程接口調用的細節比如網絡傳輸。
  5. 負載均衡 :負載均衡也是需要的。爲啥?舉個例子我們的系統中的某個服務的訪問量特別大,我們將這個服務部署在了多臺服務器上,當客戶端發起請求的時候,多臺服務器都可以處理這個請求。那麼,如何正確選擇處理該請求的服務器就很關鍵。假如,你就要一臺服務器來處理該服務的請求,那該服務部署在多臺服務器的意義就不復存在了。負載均衡就是爲了避免單個服務器響應同一請求,容易造成服務器宕機、崩潰等問題,我們從負載均衡的這四個字就能明顯感受到它的意義。

項目基本情況和可優化點

爲了循序漸進,最初的是時候,我是基於傳統的 BIO 的方式 Socket 進行網絡傳輸,然後利用 JDK 自帶的序列化機制 以及內存直接存儲相關服務相關信息來實現這個 RPC 框架的。

後面,我對原始版本進行了優化,已完成的優化點和可以完成的優化點我都列在了下面 👇。

爲什麼要把可優化點列出來? 主要是想給哪些希望優化這個 RPC 框架的小夥伴一點思路。歡迎大家 Clone 本倉庫,然後自己進行優化。

項目模塊概覽

運行項目

1.導入項目

克隆項目到自己的本地:git clone [email protected]:Snailclimb/guide-rpc-framework.git

然後使用 IDEA 打開,等待項目初始化完成。

2.初始化 git hooks

這一步主要是爲了在 commit 代碼之前,跑 Check Style,保證代碼格式沒問題,如果有問題的話就不能提交。

以下演示的是 Mac/Linux 對應的操作,Window 用戶需要手動將 config/git-hooks 目錄下的pre-commit 文件拷貝到 項目下的 .git/hooks/ 目錄。

執行下面這些命令:

➜  guide-rpc-framework git:(master)chmod +x ./init.sh
➜  guide-rpc-framework git:(master) ✗ ./init.sh

簡單介紹一下是怎麼做的!

init.sh 這個腳本的主要作用是將 git commit 鉤子拷貝到項目下的 .git/hooks/ 目錄,這樣你每次 commit 的時候就會執行了。

cp config/git-hooks/pre-commit .git/hooks/
chmod +x .git/hooks/pre-commit

抱怨:項目上一直用的 Gradle,很久沒用 Maven 了,感覺 Gradle 很多方面都比 Maven 要更好用!比如 Gradle 的項目依賴文件build.gradle 比 Maven 的pom.xml更加清晰簡潔(Maven 是因爲 xml 的鍋)、Gradel 還可以使用 groovy 語言…

pre-commit 的內容如下,主要作用是在提交代碼前運行 Check Style檢查代碼格式問題。

#!/bin/sh
#set -x

echo "begin to execute hook"
mvn checkstyle:check

RESULT=$?

exit $RESULT

3.CheckStyle 插件下載和配置

IntelliJ IDEA-> Preferences->Plugins->搜索下載 CheckStyle 插件,然後按照如下方式進行配置。

配置完成之後,按照如下方式使用這個插件!

4.下載運行 zookeeper

這裏使用 Docker 來下載安裝。

下載:

docker pull zookeeper:3.4.14

運行:

docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14

使用

服務提供端

實現接口:

public class HelloServiceImpl implements HelloService {
   @Override
    public String hello(Hello hello) {
      ......
    }
}

發佈服務(使用 Netty 進行傳輸):

HelloService helloService = new HelloServiceImpl();
NettyServer nettyServer = new NettyServer("127.0.0.1", 9999);
nettyServer.publishService(helloService, HelloService.class);

服務消費端

ClientTransport rpcClient = new NettyClientTransport();
RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient);
HelloService helloService = rpcClientProxy.getProxy(HelloService.class);
String hello = helloService.hello(new Hello("111", "222"));

相關問題

爲什麼要造這個輪子?Dubbo 不香麼?

寫這個 RPC 框架主要是爲了通過造輪子的方式來學習,檢驗自己對於自己所掌握的知識的運用。

實現一個簡單的 RPC 框架實際是比較容易的,不過,相比於手寫 AOP 和 IoC 還是要難一點點,前提是你搞懂了 RPC 的基本原理。

我之前從理論層面在我的知識星球分享過如何實現一個 RPC。不過理論層面的東西只是支撐,你看懂了理論可能只能糊弄住面試官。咱程序員這一行還是最需要動手能力,即使你是架構師級別的人物。當你動手去實踐某個東西,將理論付諸實踐的時候,你就會發現有很多坑等着你。

大家在實際項目上還是要儘量少造輪子,有優秀的框架之後儘量就去用,Dubbo 在各個方面做的都比較好和完善。

如果我要自己寫的話,需要提前瞭解哪些知識

Java

  1. 動態代理機制;
  2. 序列化機制以及各種序列化框架的對比,比如 hession2、kyro、protostuff。
  3. 線程池的使用;
  4. CompletableFuture 的使用

Netty

  1. 使用 Netty 進行網絡傳輸;
  2. ByteBuf 介紹
  3. Netty 粘包拆包
  4. Netty 長連接和心跳機制

Zookeeper :

  1. 基本概念;
  2. 數據結構;
  3. 如何使用 Netflix 公司開源的 zookeeper 客戶端框架 Curator 進行增刪改查;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章