1. 程式人生 > >從零寫分散式RPC框架 系列 1.0 (1)架構設計

從零寫分散式RPC框架 系列 1.0 (1)架構設計

本系列文章的目的是搭建出一個基於Netty,Zookeeper和SpringBoot的簡易分散式RPC框架,並且釋出到Maven中央倉庫以 spring-boot-starter 的形式對外提供開箱即用的服務。1.0 版本使用 protobuf 來做序列化,最終的使用形式比較接近於 Dubbo 。最終效果可見:https://github.com/linshenkx/rpc-netty-spring-boot-starter

系列文章:

一 RPC設計

本RPC框架主要有RPC-Server 和 RPC-Client 兩個核心模組。
對於使用這個框架的使用者來說,則有三個角色:Registry、rpc-provider、rpc-consumer。
本系列文章以搭建框架為主,在最後的 examples 會給出結合 Registry、rpc-provider、rpc-consumer 的使用範例。

1 框架模組

  • RPC-Server
    RPC伺服器,通過自定義的協議而非http介面對外提供服務實現
    需要向註冊中心註冊服務資訊和自身資訊
  • RPC-Client
    RPC客戶端,通過向註冊中心訂閱服務,獲取提供對應服務實現的RPC Server資訊,從而通過自定義協議從RPC Server獲取服務實現。

2 角色分工

  • Registry
    註冊中心,底層實現是Zookeeper,可藉助ZK叢集達到服務的高可用
  • rpc-provider
    服務提供者(服務生產者),依賴於RPC-Server模組對外提供RPC服務
  • rpc-consumer
    服務消費者,依賴於RPC-Client模組呼叫RPC服務

注意:本框架1.0版本未完善 RPC Client 和 Registry 的釋出訂閱模型,所以每次都需要 RPC Client去 Registry 獲取資訊再 向 RPC Server 發起服務呼叫,也由此帶來極大的效能損耗和浪費。1.0版本只是實現了一個框架原型,後續版本將對效能等做優化。

設計

二 模組結構

結構圖如下,其中 examples 模組不依賴於父工程,可獨立執行,不屬於框架的一部分。
結構圖
rpc-netty-spring-boot-starter 下有5個模組,其中外部使用的是兩個 starter ,而真正工作的事另外三個模組。

  • rpc-netty-common
    封裝統一規則,如使RPC Server和RPC Client 可以基於同一協議通訊。
    內含 自定義RPC通訊物件及序列化方法,還有對應的Netty編碼器、解碼器等。
  • rpc-netty-server-spring-boot-autoconfigure
    • 核心類是RpcServer,負責提供RPC服務
    • 內含 ZKServiceRegistry 負責向zk叢集註冊服務,@RpcService 註解對外提供使用
    • 另外還有 RpcServerHandler 提供Netty 通訊處理,ZKProperties 和 RpcServerProperties 提供屬性注入。
  • rpc-netty-server-spring-boot-starter
    對 rpc-netty-server-spring-boot-autoconfigure 進行包裝,本身無功能實現
  • rpc-netty-client-spring-boot-autoconfigure
    • 核心類是RpcClient,負責獲取服務實現生成代理類
    • 內含 ZKServiceDiscovery 負責發現指定服務的RPC Server資訊
    • 另外還有 RpcClientHandler 提供Netty 通訊處理,ZKProperties 提供屬性注入。
  • rpc-netty-client-spring-boot-starter
    對rpc-netty-client-spring-boot-autoconfigure 進行包裝,本身無功能實現

三 工作流程

RPC Server

服務啟動掃描 RpcService 註解類收集能實現的服務在RpcServerProperties指定埠上 啟動Netty伺服器向zk叢集註冊服務和自身資訊

需要注意,RPC Server需一直維持與zk叢集的連線,如果關閉RPC Server,zk上註冊的資訊會隨之清除。

RPC Client

服務端利用反射執行方法生成結果使用者觸發獲取服務實現傳遞介面資訊服務端返回結果

需要注意,這裡沒有使用釋出訂閱模型,沒有維持連線,所以每次使用都需要去獲取服務實現,沒有使用池化技術和快取。需要在後續版本改良。

四 功能依賴

  • rpc-netty-common 模組
    • protostuff-core :Rptostuff 核心模組,提供物件序列化和反序列化功能
    • protostuff-runtime:Protostuff 執行時模組,用於生成所需的 Protostuff Schema 物件
    • objenesis:提供比 JDK 更高效的反射功能,用於物件反序列化
  • rpc-netty-server-spring-boot-autoconfigure 和 rpc-netty-server-spring-boot-autoconfigure 模組
    • spring-boot-starter:提供spring-boot 基礎服務,如 spring-context 資訊等,該依賴scope 應為 provided ,由使用方提供依賴,避免版本衝突
    • spring-boot-configuration-processor:提供屬性注入,scope同上
    • rpc-netty-common:提供統一服務
    • zkclient :提供對zk叢集的操作,注意應使用 exclusion 將其 slf4j-log4j12 模組排除在classpath,否則會與spring-boot日誌框架重複或與Lombok的@log4j2衝突

除了上述依賴,還有以上3個模組都依賴的

  • netty-all :Netty模組,提供NIO通訊所需的API,是整個RPC框架的基礎
  • lombok:其 optional 應為true ,避免傳遞依賴

另外,兩個spring-boot-starter分別只依賴各自的spring-boot-autoconfigure模組

注意,為了避免依賴衝突問題,這裡使用到了 scope設為provided,exclusion排除模組, optional設為true 三種方法。詳情請見:provided,optional 和 exclusion 最全區分指南

  1. scope設為provided:對依賴整體有效,依賴將提供編譯而不參與打包,由使用方提供
    在本專案中,則是在釋出後,由使用 spring-boot-starter 的spring-boot工程提供。
  2. exclusion排除特定元件:避免傳遞依賴
    本專案中,用於移去 zkclient 的 slf4j-log4j12 模組,避免依賴匯入
  3. optional設為true:避免傳遞依賴
    本專案中,rpc-netty-server-spring-boot-autoconfigure依賴optional為true的 Lombok ,但 rpc-netty-server-spring-boot-starter則不含 Lombok 模組,避免依賴傳出

五 父工程pom

這裡我把部署到maven 中央倉庫的內容刪去,不影響正常使用,感興趣的可以到GitHub找完整專案檢視,部署的中央倉庫的方法見:使用gpg外掛釋出jar包到Maven中央倉庫 完整實踐

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.github.linshenkx</groupId>
    <artifactId>rpc-netty-spring-boot-starter</artifactId>
    <version>1.0.5.RELEASE</version>
    <packaging>pom</packaging>

    <name>rpc-netty-spring-boot-starter</name>
    <description>基於Netty的簡易RPC框架</description>
    <url>https://github.com/linshenkx/rpc-netty-spring-boot-starter</url>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-boot.version>2.1.0.RELEASE</spring-boot.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
        <netty.version>4.1.31.Final</netty.version>
        <protostuff.version>1.5.9</protostuff.version>
        <objenesis.version>3.0.1</objenesis.version>
        <zkclient.version>0.11</zkclient.version>
    </properties>

    <modules>
        <module>rpc-netty-common</module>
        <module>rpc-netty-server-spring-boot-autoconfigure</module>
        <module>rpc-netty-server-spring-boot-starter</module>
        <module>rpc-netty-client-spring-boot-autoconfigure</module>
        <module>rpc-netty-client-spring-boot-starter</module>
    </modules>
   
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
                <version>${spring-boot.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <version>${spring-boot.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.github.linshenkx</groupId>
                <artifactId>rpc-netty-common</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.linshenkx</groupId>
                <artifactId>rpc-netty-server-spring-boot-autoconfigure</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.linshenkx</groupId>
                <artifactId>rpc-netty-client-spring-boot-autoconfigure</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-all</artifactId>
                <version>${netty.version}</version>
            </dependency>
            <dependency>
                <groupId>io.protostuff</groupId>
                <artifactId>protostuff-core</artifactId>
                <version>${protostuff.version}</version>
            </dependency>
            <dependency>
                <groupId>io.protostuff</groupId>
                <artifactId>protostuff-runtime</artifactId>
                <version>${protostuff.version}</version>
            </dependency>
            <dependency>
                <groupId>org.objenesis</groupId>
                <artifactId>objenesis</artifactId>
                <version>${objenesis.version}</version>
            </dependency>
            <dependency>
                <groupId>com.101tec</groupId>
                <artifactId>zkclient</artifactId>
                <version>${zkclient.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
</project>

其他

相關推薦

分散式RPC框架 系列 2.0 1架構升級

針對1.0版本的效能問題,本版本做了從服務地址列表快取等方面做了優化處理,並加入負載均衡引擎、序列化引擎、服務端限流等新功能,並對通訊模型進行改造,使其支援新特性、避免粘包半包問題並對後續升級改造留下支援空間。具體可見 專案GitHub地址 。本文將介紹 2.0 版本的邏輯架構和模型設計

分散式RPC框架 系列 2.0 4使用BeanPostProcessor實現自定義@RpcReference註解注入

之前服務提供方 RpcServer 我們是使用 ApplicationContextAware 來掃描 @RpcService 註解,新增一個註解即可實現服務暴露。現在,我們用 BeanPostProcessor 來實現服務注入,自動將服務實現類注入到被@RpcReference註解標記

分散式RPC框架 系列 2.0 3RPC-Server和RPC-Client模組改造

2.0版本RPC-Server改動不大,主要變化在於RPC-Client使用了服務地址快取,並引入監控機制,第一時間獲取zk叢集中服務地址資訊變化並重新整理本地快取。另外,RPC-Client還使用了RpcClientProperties開放對負載均衡策略和序列化策略的選擇。 系列文

分散式RPC框架 系列 2.0 2RPC-Common模組設計實現

RPC-Common模組相對於1.0版本複雜了很多,最主要的變化在於將 Rpc的Netty處理器從RPC-Server和RPC-Client收回。1.0 版本的設計思路是儘可能減少冗餘依賴,所以RPC-Common一般只放通用的功能。現在則是儘可能都放在RPC-Common模組,以方便工

分散式RPC框架 系列 第一版 1架構設計

本系列文章的目的是搭建出一個基於Netty,Zookeeper和SpringBoot的簡易分散式RPC框架,並且釋出到Maven中央倉庫以 spring-boot-starter 的形式對外提供開箱即用的服務。1.0 版本使用 protobuf 來做序列化,最終的使用形式比較接近於 Du

分散式RPC框架 系列 1.0 2RPC-Common模組設計實現

RPC-Common模組提供RPC-Server和RPC-Client的通用物件,封裝統一規則,使RPC Server和RPC Client 可以基於同一協議通訊。主要包含底層通訊的Netty所需的編碼解碼器(RpcEncoder,RpcDecoder),實現自定義協議的傳輸物件(Rpc

分散式RPC框架 系列 1.0 5整合測試

本篇將對前面幾篇模組作整合處理,使用spring-boot-starter的形式進行釋出。然後新建 examples 工程模組對其測試使用。 系列文章: 從零寫分散式RPC框架 系列 1.0 (1)架構設計 從零寫分散式RPC框架 系列 1.0 (2)RPC-Common模組設計

分散式RPC框架 系列 1.0 4RPC-Client模組設計實現

RPC-Client模組負責建立 動態代理物件 供 服務消費者 使用,而動態代理物件的方法執行則是通過RPC呼叫RPC-Server的服務實現。即RPC-Client遮蔽了底層的通訊過程,使得服務消費者可以基於介面透明使用服務提供者的服務。 系列文章: 從零寫分散式RPC框架 系

分散式RPC框架 系列 1.0 3RPC-Server模組設計實現

RPC-Server模組負責(1)將@RpcService註解標記的服務和自身資訊註冊到ZK叢集,(2)對外提供RPC服務實現,處理來自RPC-Client的請求。該模組整體的核心類為 RpcServer ,而真正處理請求的核心類是 RpcServerHandler 。另外還有一個 ZK

分散式RPC框架 系列 1.0 1架構設計

本系列文章的目的是搭建出一個基於Netty,Zookeeper和SpringBoot的簡易分散式RPC框架,並且釋出到Maven中央倉庫以 spring-boot-starter 的形式對外提供開箱即用的服務。1.0 版本使用 protobuf 來做序列化,最終

Spring註解版框架系列 IoC篇 1 框架設計

本文的註解版IoC框架跟其他手寫IoC框架的不同之處在與:在實現了 @Component 和 @Autowired 的同時還實現了@Qualifier,並解決單例模式下迴圈依賴的問題,以上3個註解的使用效果參照 Spring 。 專案 Github 地址為:https://githu

Spring註解版框架系列 IoC篇 2實現 @Component、@Autowired、@Qualifier註解

本文承接了上一篇文章的思路進行程式碼實現,並搭建起一個基本可用的基於@Component、@Autowired、@Qualifier 註解的 IoC 框架。 專案 Github 地址為:https://github.com/linshenkx/winter-core 相關文章地址:從

開始搭建android框架系列

bsp andro hup 開始 blank class and lan com 網址:從零開始搭建android框架系列 githup:https://github.com/CameloeAnthony/Ant從零開始搭建android框架系列(轉)

開始實現RPC框架

RPC概述 RPC(Remote Procedure Call)即遠端過程呼叫,允許一臺計算機呼叫另一臺計算機上的程式得到結果,而程式碼中不需要做額外的程式設計,就像在本地呼叫一樣。 現在網際網路應用的量級越來越大,單臺計算機的能力有限,需要藉助可擴充套件的計算機叢集來

網路圖片載入的封裝-開始搭建android框架系列4

本篇文章專案github地址:MVPCommon 本文章原地址:簡書部落格 1 有哪些常用的圖片載入庫? 當下使用的主要有Piccaso、Fresco、Android-Universal-Image-Loader、Glide、Volley這五個

不容錯過,最全的安卓架構合集【開始搭建android框架系列2

安卓架構文章合集(a collection of android Architecture) 部落格原地址: 簡書部落格 github地址: 這是從各大平臺上參考的android架構文章,文章資料,主要參考自Info,推薦關注: infoQ 1 Android

談談WebView的使用-開始搭建android框架系列5

本篇文章專案github地址:MVPCommon 本文章原地址:簡書部落格 1 前言 這篇文章將從webview的基礎,介紹到專案中的真實使用。以及怎麼樣通過注入js指令碼的方式來改變網頁內容,從而在本地展示新聞體育列表。製作出一個像模像樣的app

Go遊戲服務端框架搭建架構設計

         五邑隱俠,本名關健昌,10年遊戲生涯,現隱居海邊。   本教程以Go語言分割槽遊戲服務端框架搭建為例。   Go語言是Google開發的一種靜態強型別、編譯型、併發型、具有垃圾回收功能的程式語言。語法上近似C語言,支援介面、可通過struct

SQL到迅速精通【實用函數2

表的操作 deny 獲取 拒絕 分享 子字符串 evo sci ever 1.對查詢結果進行排序 查詢stu_info表中所有學生信息,並按照成績由高到底進行排序,輸入語句如下。 SELECT * FROM stu_info ORDER BY s_score DESC;

開始學Kotlin-類和對象5

int 文件中 cls 間接 main dcl this 調用 定義類 從零開始學Kotlin基礎篇系列文章 定義一個類 定義一個類,使用關鍵字class聲明,後面跟類名(不使用new) class demo5 {//定義一個類,使用關鍵字class聲明,後面跟類名