從零寫分散式RPC框架 系列 1.0 (5)整合測試
本篇將對前面幾篇模組作整合處理,使用spring-boot-starter的形式進行釋出。然後新建 examples 工程模組對其測試使用。
系列文章:
從零寫分散式RPC框架 系列 1.0 (1)架構設計
從零寫分散式RPC框架 系列 1.0 (2)RPC-Common模組設計實現
從零寫分散式RPC框架 系列 1.0 (3)RPC-Server模組設計實現
從零寫分散式RPC框架 系列 1.0 (4)RPC-Client模組設計實現
從零寫分散式RPC框架 系列 1.0 (5)整合測試
使用gpg外掛釋出jar包到Maven中央倉庫 完整實踐
文章目錄
一 建立spring-boot-starter模組
建立RPC-Server和RPC-Client對應的spring-boot-starter模組如下,只依賴了對應的spring-boot-autoconfigure,可以將其視為spring-boot-autoconfigure的包裝,兩者的區別還在於一些依賴沒有被傳遞到spring-boot-starter來,不過使用起來沒有區別
二 在主工程新增部署到Maven中央倉庫的配置
如果只是想在本地玩玩的話,使用install就好,沒必要deploy,另外如果由於測試過程自動開啟RPC伺服器等待連線導致測試不會結束,可以直接使用-Dmaven.test.skip=true
在主工程pom檔案中新增如下資訊:developers,scm,licenses,distributionManagement還有相關外掛,程式碼較多,這裡就不貼出來了。感興趣的也可以直接到GitHub檢視本專案,具體配置方法見使用gpg外掛釋出jar包到Maven中央倉庫 完整實踐,該文章即以本專案為例。
三 新建examples工程
新建examples工程,包含3個模組:
- rpc-lib
rpc介面模組,定義RPC服務提供者和RPC消費者公用的介面規範 - rpc-provider
rpc服務提供者模組,負責服務實現,並對外提供RPC呼叫服務 - rpc-consumer
rpc服務消費者模組,負責服務消費,通過rpc-lib的契約(介面)向rpc-provider呼叫服務實現。
主工程pom檔案如下:
- spring-cloud-dependencies是spring-cloud的依賴管理模組,也可以去掉
- rpc-lib是rpc-provider和rpc-consumer共同依賴的模組,所以放在這裡維持版本統一
- rpc-netty-server-spring-boot-starter和rpc-netty-client-spring-boot-starter則是我們的專案,也是實現RPC的核心依賴
- 最後面我還加上了repository地址,在專案deploy到中央倉庫之前會先加入這個倉庫,所以這個倉庫可以更快拉取的最新發現jar包,對於除錯來說就不用再等了,日常使用中可以去掉。
<?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.test</groupId>
<artifactId>rpc-netty-spring-boot-starter-examples</artifactId>
<version>1.0.5.RELEASE</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</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-cloud.version>Finchley.SR2</spring-cloud.version>
<spring-boot.version>${project.parent.version}</spring-boot.version>
<rpc-netty-linshen.version>1.0.5.RELEASE</rpc-netty-linshen.version>
</properties>
<modules>
<module>rpc-lib</module>
<module>rpc-provider</module>
<module>rpc-consumer</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>
<!--公共rpc模組-->
<dependency>
<groupId>com.github.linshenkx.test</groupId>
<artifactId>rpc-lib</artifactId>
<version>${project.version}</version>
</dependency>
<!--核心rpc-netty-spring-boot依賴-->
<dependency>
<groupId>com.github.linshenkx</groupId>
<artifactId>rpc-netty-client-spring-boot-starter</artifactId>
<version>${rpc-netty-linshen.version}</version>
</dependency>
<dependency>
<groupId>com.github.linshenkx</groupId>
<artifactId>rpc-netty-server-spring-boot-starter</artifactId>
<version>${rpc-netty-linshen.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>sonatype-repository</id>
<name>sonatype-repository</name>
<url>https://oss.sonatype.org/content/groups/staging</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>
四 編寫 rpc-lib 模組
該模組只提供介面,故無需依賴什麼。
結構及pom檔案
HelloService 介面
public interface HelloService {
String say(String name);
}
五 編寫rpc-provider模組
該模組負責服務提供,這裡我寫了兩個 profile的application配置檔案(slave1和slave2),模擬rpc-provider的叢集。
結構及pom檔案
HelloService實現類
@RpcService(HelloService.class)
public class HelloServiceImpl implements HelloService {
@Override
public String say(String name) {
return "hello " + name;
}
}
application檔案
如下,application.yml 提供公共配置,各個slave提供個性化配置。預設使用slave1。
另外,需要注意,這裡並沒有指定server.port,也沒有引入spring-web依賴,即該服務不是web服務,使用的是我們自己實現的RPC協議。
如果rpc-provider部署在不同的叢集上,則使用一個aplication.yml即可,這裡因為是偽叢集,所以需要提供profile指定不同埠。
########### application.yml ###############
zk:
addressList:
- IP:2181
- IP:2182
- IP:2183
connectTimeOut: 10000
sessionTimeOut: 10000
registryPath: "/defaultRegistry"
spring:
profiles:
active: slave1
########### application-slave1.yml ###############
rpc:
server:
port: 9991
########### application-slave2.yml ###############
rpc:
server:
port: 9992
六 編寫 rpc-consumer 模組
該模組依賴和rpc-provider基本一致,只是多了spring-boot-starter-web,application則對應多了server.port。另外需要注意,application不需要指定rpc.server.port,指定了也沒有用,服務地址是依靠服務發現獲取的。
結構及application檔案
HelloController
這裡我還用了org.springframework.util提供的 計時器 進行服務計時,小小地測試效能。
/**
* @version V1.0
* @author: lin_shen
* @date: 2018/11/1
* @Description: TODO
*/
@RestController
@Log4j2
public class HelloController {
@Autowired
private RpcClient rpcClient;
@GetMapping("/hello")
public String sayHello(@RequestParam(defaultValue = "lin") String name){
StopWatch stopwatch = new StopWatch();
stopwatch.start();
HelloService helloService= rpcClient.create(HelloService.class);
String returnString= helloService.say(name);
stopwatch.stop();
log.info("耗時:"+stopwatch.getTotalTimeSeconds()+"seconds");
return returnString;
}
}
七 專案測試
測試之前應先將公共模組 rpc-lib install到本地,然後再把整個examples install 到本地。
然後依次啟動 rpc-provider-slave1、rpc-provider-slave2和rpc-consumer
可以根據列印的日誌判斷啟動是否符合預期,如下為slave1的啟動資訊
可以看到其服務註冊地址為:/defaultRegistry/com.github.linshenkx.rpclib.HelloService/address-0000000036
自身服務地址為: 192.168.200.1:9991
這個時候分別開啟連結 http://localhost:9090/hello?name=linShen1,http://localhost:9090/hello?name=linShen2,http://localhost:9090/hello?name=linShen3等,可以順利獲得對應的 hello資訊。
另外,檢視兩個slave的控制檯輸出,可以發現請求被隨機轉發到所有的slave下,即實現了負載均衡(其實算不上,只是隨機選擇而已)。
另外這個專案1.0版本效能較差,根據測試,第一次請求大概耗時11s(需要到ZK叢集獲取服務資訊生成動態代理類,再建立RPC連接獲取結果),之後耗時都是5s多。