rpc框架dubbo學習入門及環境搭建(spring boot+Kotlin)


學習之前,確保有以下知識基礎:

  • Java網絡編程
  • Socket傳輸數據
  • IO流

rpc簡介及實現

rpc是remote procedure call的簡寫,意思為遠程過程調用。

rpc應用較多的情景是分布式開發,那什么是分布式開發呢?

原本我也是想自己解釋的,奈何網上大佬解釋得很清楚了,這里就不獻丑了,建議閱讀完下面推薦的幾篇再繼續往下

剛開始的時候,服務和調用都是在同一機器,這叫本地過程調用

之后,由於客戶量增長,一個服務器並不能滿足要求,之后便是把調用和服務分開,分別部署在不同的機器,負責調用服務方法的稱之為客戶機,負責提供服務方法的稱為服務機

上圖的原理可能步驟有點多,但是只要記住一點,客戶機是把數據通過Socket或者是其他協議傳遞到了服務機,讓服務機進行處理,從而以相同的協議方式把數據傳遞回來

如何實現一個簡單的RPC一文中,大佬已經實現了一個簡潔的rpc框架,然后對於這個rpc框架,並提出來的一些可以優化的點:

1. 缺乏通用性

我通過給Calculator接口寫了一個CalculatorRemoteImpl,來實現計算器的遠程調用,下一次要是有別的接口需要遠程調用,是不是又得再寫對應的遠程調用實現類?這肯定是很不方便的。

2、集成Spring

在實現了代理對象通用化之后,下一步就可以考慮集成Spring的IOC功能了,通過Spring來創建代理對象,這一點就需要對Spring的bean初始化有一定掌握了。

3、長連接or短連接

總不能每次要調用RPC接口時都去開啟一個Socket建立連接吧?是不是可以保持若干個長連接,然后每次有rpc請求時,把請求放到任務隊列中,然后由線程池去消費執行?只是一個思路,后續可以參考一下Dubbo是如何實現的。

4、 服務端線程池

我們現在的Server端,是單線程的,每次都要等一個請求處理完,才能去accept另一個socket的連接,這樣性能肯定很差,是不是可以通過一個線程池,來實現同時處理多個RPC請求?同樣只是一個思路。

5、服務注冊中心

正如之前提到的,要調用服務,首先你需要一個服務注冊中心,告訴你對方服務都有哪些實例。Dubbo的服務注冊中心是可以配置的,官方推薦使用Zookeeper。如果使用Zookeeper的話,要怎樣往上面注冊實例,又要怎樣獲取實例,這些都是要實現的。

6、負載均衡

如何從多個實例里挑選一個出來,進行調用,這就要用到負載均衡了。負載均衡的策略肯定不只一種,要怎樣把策略做成可配置的?又要如何實現這些策略?同樣可以參考Dubbo,Dubbo - 負載均衡

7、結果緩存

每次調用查詢接口時都要真的去Server端查詢嗎?是不是要考慮一下支持緩存?

8、多版本控制

服務端接口修改了,舊的接口怎么辦?

9、異步調用

客戶端調用完接口之后,不想等待服務端返回,想去干點別的事,可以支持不?

10、優雅停機

服務端要停機了,還沒處理完的請求,怎么辦?

PS:使用rpc的時候,需要考慮到網絡問題,需要采用重試機制

由上述的這些問題,之后便是出現了一些優秀的rpc框架,如dubbo、spring cloud等

dubbo簡介

Dubbo是阿里巴巴開源的基於 Java 的高性能 RPC(遠程過程調用) 分布式服務框架(SOA),致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案,其內部使用了 Netty、Zookeeper,保證了高性能高可用性。

dubbo結構圖:

節點 角色說明
Provider 暴露服務的服務提供方
Consumer 調用遠程服務的服務消費方
Registry 服務注冊與發現的注冊中心
Monitor 統計服務的調用次數和調用時間的監控中心
Container 服務運行容器

其中,注冊中心Registry和監控中心Monitor都是可選的,所以,我們下文先簡單實現dubbo(點對點傳輸數據)

<dependency>
	<groupId>com.starsone</groupId>
	<artifactId>dubbo-api</artifactId>
	<version>0.0.1</version>
</dependency>

dubbo簡單實現

項目說明:
項目基於spring boot,分為三個部分,apiconsumerprovider

  • api主要是用來聲明一些服務的接口(maven項目)
  • provider則是對服務接口的具體實現(spring boot項目,通過maven依賴api項目)
  • consumer則是遠程調用provider提供的服務接口(spring boot項目,通過maven依賴api),

本質上consumer相當於客戶機,而provider相當於客戶機

1.新建項目

使用IDEA,建立一個空白的項目,之后新建module

之后IDEA會彈出一個新建module的窗口

依次新建api、provider、cousmer三個module

api選擇maven項目,之后填寫相關的包名信息直接新建即可(不需要選擇具體的maven結構),而另外兩個則是spring boot項目,選擇spring initializr新建即可,同樣,不要勾選其他的依賴,填寫好包名相關信息新建即可

2.api項目聲明服務接口

在api項目中,我們新建一個CalculatorService接口,里面定義一個add的方法

public interface CalculatorService {
    int add(int a,int b);
}

3.配置api項目的依賴

原本,之后的provider和consumer項目都是需要引用dubbo-spring-boot-starter這個依賴,dubbo-spring-boot-starter依賴中已經包含了dubbo依賴,這樣就可以不需要寫dubbo的依賴了

由於之后我們的provider和consumer項目都是需要引用api這個項目,所以,我們可以把provider和consumer所需要的依賴dubbo-spring-boot-starter添加到api這個項目中

之后的provider和consumer項目也就是依賴了api項目,也成功依賴了dubbo-spring-boot-starter

<dependency>
	<groupId>org.apache.dubbo</groupId>
	<artifactId>dubbo-spring-boot-starter</artifactId>
	<version>2.7.5</version>
</dependency>

4.provider和consumer項目引用api項目依賴

由於之前我們創建的api項目是maven項目,所以添加依賴就很簡單,在provider和consumer各自的pom.xml添加依賴即可

5.provider實現api中的服務接口

我們在provider項目中新建一個類CalculatorServiceImpl,去實現CalculatorService接口

@Service(interfaceName = "calculatorService")
class CalculatorServiceImpl:CalculatorService {
    override fun add(a: Int, b: Int): Int {
        val result = a+b
        println("$a+$b=$result")
        return result
    }
}

注意,這里的Service注解是dubbo包里面的注解,而不是spring中的Service,定義接口名interfaceNamecalculatorService,方便之后容器進行查找

6.配置provider項目

我們需要修改spring boot的配置文件,這里我使用yml的形式進行配置,閱讀比較舒適

spring:
  application:
    name: dubbo-provider-application
dubbo:
  scan:
    #掃描指定包是否包含有dubbo中Service注解的類
    base-packages: com.starsone.provider.service
  protocol:
    name: dubbo #協議,默認為dubbo(其他協議webserovice、Thrift、Hessain、http)
    port: 12345 #端口,默認為20880
  registry:
    address: N/A #不需要注冊中心

PS:如果不想在配置文件制定掃描包含有Service注解的類,可以在provider項目中的application類中添加開啟dubbo自動掃描的注解@EnableDubbo

provider項目結構圖:

7.運行provider

由於我們沒有引入注冊中心,所以得先運行provider,獲得ip地址

之后consumer項目中,才能讓springr容器去根據ip地址+端口號去找到對應的實例並自動裝載

由輸出日志,我們可以看到ip地址

8.consumer獲得service對象

@Component
class MyRunner:ApplicationRunner {
    @Reference(url ="dubbo://192.168.52.1:12345",interfaceName = "calculatorService" )
    private lateinit var calculatorService: CalculatorService

    override fun run(args: ApplicationArguments?) {
        println(calculatorService.add(5,14))
    }
}

這里,由於是為了簡單考慮,沒有使用web依賴,所以,使用了ApplicationRunner這個接口進行測試,spring容器在加載完成會自動回調此接口

Reference注解是dubbo中的注解,consumer項目運行之后,consumer中的dubbo就會根據此url和一些其他的信息進行數據的傳遞,遠程調用provider中的服務,之后,provider接收數據並進行處理,返回數據給consumer,是不是有了rpc的感覺?

9.配置consumer及測試

配置的話,只配置了應用的名稱

之后,我們運行consumer的application,可以看到結果

同樣,在provider項目,也是打印出了consumer項目傳遞過來的參數

引入注冊中心

前面的實現,是沒有注冊中心的,屬於一種直連的方式,但是,實際上,分布式開發,具有多台服務機

客戶機應該是向注冊中心請求,由注冊中心查詢當前空閑的服務機,並根據某種策略,選擇其中一台服務機,將其ip地址返回給客戶機,之后客戶機通過ip地址,與該服務機進行連接,進行rpc操作

dubbo框架中,推薦使用ZooKeeper作為注冊中心

ZooKeeper是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。

1.下載zookeeper

http://mirror.bit.edu.cn/apache/zookeeper/

注意,這里下載的版本最好與項目中的依賴版本一致

2.導入zookeeper依賴

我們需要修改api項目中的依賴,這樣provider和consumer兩個項目的依賴也是得以修改

<dependency>
	<groupId>org.apache.zookeeper</groupId>
	<artifactId>zookeeper</artifactId>
	<version>3.4.14</version>
	<exclusions>
		<exclusion>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
		</exclusion>
		<exclusion>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
		</exclusion>
		<exclusion>
			<groupId>io.netty</groupId>
			<artifactId>netty</artifactId>
		</exclusion>
	</exclusions>
</dependency>

<!-- Zookeeper客戶端 -->
<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-recipes</artifactId>
	<version>4.2.0</version>
</dependency>

3.配置provider和consumer的注冊中心

provider:

consumer:

4.取消consumer指定url

由於我們使用的是注冊中心,所以,不需要指定url了,把Reference注解中的url刪掉

5.運行zookeeper

解壓下載的zookeeper壓縮包,進入到conf目錄,把zoo_sample.cfg文件改為zoo.cfg

進入bin目錄,點擊zkserver.cmd文件,運行zookeeper

6.運行provider和consumer

先運行provider,之后運行consumer,可以看到結果

本篇文章也是折騰了幾天,參考了十幾篇文章,一步步測試才弄成功,有些知識點並沒有太深入,像dubbo控制台、監控中心等如何搭建,后期學習的時候再進行補充說明吧

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM