本着開源精神,本項目README已經同步了英文版本。另外,項目的源代碼的註釋大部分也修改成了英文。java
如訪問速度不佳,可放在 Gitee 地址:https://gitee.com/SnailClimb/... 。若是要提交 issue 或者 pr 的話,請在 Github 提交:https://github.com/Snailclimb... 。git
相關項目:程序員
雖然說 RPC 的原理實際不難,可是,本身在實現的過程當中本身也遇到了不少問題。guide-rpc-framework 目前只實現了 RPC 框架最基本的功能,一些可優化點都在下面提到了,有興趣的小夥伴能夠自行完善。github
經過這個簡易的輪子,你能夠學到 RPC 的底層原理和原理以及各類 Java 編碼實踐的運用。面試
你甚至能夠把 guide-rpc-framework 當作你的畢設/項目經驗的選擇,這是很是不錯!對比其餘求職者的項目經驗都是各類系統,造輪子確定是更加能贏得面試官的青睞。算法
若是你要將 guide-rpc-framework 當作你的畢設/項目經驗的話,我但願你必定要搞懂,而不是直接複製粘貼個人思想。你能夠 fork 個人項目,而後進行優化。若是你以爲的優化是有價值的話,你能夠提交 PR 給我,我會盡快處理。docker
guide-rpc-framework 是一款基於 Netty+Kyro+Zookeeper 實現的 RPC 框架。代碼註釋詳細,結構清晰,而且集成了 Check Style 規範代碼結構,很是適合閱讀和學習。apache
因爲 Guide哥自身精力和能力有限,若是你們以爲有須要改進和完善的地方的話,歡迎 fork 本項目,而後 clone 到本地,在本地修改後提交 PR 給我,我會在第一時間 Review 你的代碼。json
咱們先從一個基本的 RPC 框架設計思路提及!安全
注意 :咱們這裏說的 RPC 框架指的是:可讓客戶端直接調用服務端方法就像調用本地方法同樣簡單的框架,好比我前面介紹的 Dubbo、Motan、gRPC 這些。 若是須要和 HTTP 協議打交道,解析和封裝 HTTP 請求和響應。這類框架並不能算是「RPC 框架」,好比 Feign。
一個最簡單的 RPC 框架使用示意圖以下圖所示,這也是 guide-rpc-framework 目前的架構 :
服務提供端 Server 向註冊中心註冊服務,服務消費者 Client 經過註冊中心拿到服務相關信息,而後再經過網絡請求服務提供端 Server。
做爲 RPC 框架領域的佼佼者Dubbo的架構以下圖所示,和咱們上面畫的大致也是差很少的。
通常狀況下, RPC 框架不只要提供服務發現功能,還要提供負載均衡、容錯等功能,這樣的 RPC 框架纔算真正合格的。
簡單說一下設計一個最基本的 RPC 框架的思路:
爲了按部就班,最初的是時候,我是基於傳統的 BIO 的方式 Socket 進行網絡傳輸,而後利用 JDK 自帶的序列化機制 來實現這個 RPC 框架的。後面,我對原始版本進行了優化,已完成的優化點和能夠完成的優化點我都列在了下面 👇。
爲何要把可優化點列出來? 主要是想給哪些但願優化這個 RPC 框架的小夥伴一點思路。歡迎你們 fork 本倉庫,而後本身進行優化。
CompletableFuture
包裝接受客戶端返回結果(以前的實現是經過 AttributeMap
綁定到 Channel 上實現的) 詳見:使用 CompletableFuture 優化接受服務提供端返回結果客戶端與服務端通訊協議(數據包結構)從新設計
,能夠將原有的
RpcRequest
和
RpcReuqest
對象做爲消息體,而後增長以下字段(能夠參考:《Netty 入門實戰小冊》和 Dubbo 框架對這塊的設計):
fork 項目到本身的倉庫,而後克隆項目到本身的本地:git clone git@github.com:username/guide-rpc-framework.git
,使用 IDEA 打開,等待項目初始化完成。
這一步主要是爲了在 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 的時候就會執行了。
IntelliJ IDEA-> Preferences->Plugins->搜索下載 CheckStyle 插件,而後按照以下方式進行配置。
配置完成以後,按照以下方式使用這個插件!
這裏使用 Docker 來下載安裝。
下載:
docker pull zookeeper:3.5.8
運行:
docker run -d --name zookeeper -p 2181:2181 zookeeper:3.5.8
實現接口:
@Slf4j @RpcService(group = "test1", version = "version1") public class HelloServiceImpl implements HelloService { static { System.out.println("HelloServiceImpl被建立"); } @Override public String hello(Hello hello) { log.info("HelloServiceImpl收到: {}.", hello.getMessage()); String result = "Hello description is " + hello.getDescription(); log.info("HelloServiceImpl返回: {}.", result); return result; } } @Slf4j public class HelloServiceImpl2 implements HelloService { static { System.out.println("HelloServiceImpl2被建立"); } @Override public String hello(Hello hello) { log.info("HelloServiceImpl2收到: {}.", hello.getMessage()); String result = "Hello description is " + hello.getDescription(); log.info("HelloServiceImpl2返回: {}.", result); return result; } }
發佈服務(使用 Netty 進行傳輸):
/** * Server: Automatic registration service via @RpcService annotation * * @author shuang.kou * @createTime 2020年05月10日 07:25:00 */ @RpcScan(basePackage = {"github.javaguide.serviceimpl"}) public class NettyServerMain { public static void main(String[] args) { // Register service via annotation new AnnotationConfigApplicationContext(NettyServerMain.class); NettyServer nettyServer = new NettyServer(); // Register service manually HelloService helloService2 = new HelloServiceImpl2(); RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder() .group("test2").version("version2").build(); nettyServer.registerService(helloService2, rpcServiceProperties); nettyServer.start(); } }
ClientTransport rpcClient = new NettyClientTransport(); RpcServiceProperties rpcServiceProperties = RpcServiceProperties.builder() .group("test1").version("version1").build(); RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceProperties); HelloService helloService = rpcClientProxy.getProxy(HelloService.class); String hello = helloService.hello(new Hello("111", "222"));
寫這個 RPC 框架主要是爲了經過造輪子的方式來學習,檢驗本身對於本身所掌握的知識的運用。
實現一個簡單的 RPC 框架實際是比較容易的,不過,相比於手寫 AOP 和 IoC 仍是要難一點點,前提是你搞懂了 RPC 的基本原理。
我以前從理論層面在個人知識星球分享過如何實現一個 RPC。不過理論層面的東西只是支撐,你看懂了理論可能只能糊弄住面試官。咱程序員這一行仍是最須要動手能力,即便你是架構師級別的人物。當你動手去實踐某個東西,將理論付諸實踐的時候,你就會發現有不少坑等着你。
你們在實際項目上仍是要儘可能少造輪子,有優秀的框架以後儘可能就去用,Dubbo 在各個方面作的都比較好和完善。
Java :
CompletableFuture
的使用Netty :
ByteBuf
介紹Zookeeper :