原文出處: oKong
前言
在18年年初時(shí),阿里巴巴開源的高性能服務(wù)框架
dubbo又開始了新一輪的更新,還加入了Apache孵化器。原先項(xiàng)目使用了spring cloud之后,已經(jīng)比較少用dubbo。目前又抽調(diào)回原來的行業(yè)應(yīng)用部門,可能還會(huì)使用dubbo進(jìn)行服務(wù)調(diào)用。趁著編寫教材的機(jī)會(huì)來進(jìn)行學(xué)習(xí)下。而且目前Dubbo也出了springboot的starter項(xiàng)目了,借著SpringBoot的東風(fēng),集成起來很方便,基本上就一個(gè)依賴包引入的問題了。廢話不多說,開始吧~
一點(diǎn)知識(shí)
對(duì)于沒有接觸過Dubbo的同學(xué),可以先了解下相關(guān)知識(shí)。
Dubbo簡介
Dubbo 是阿里巴巴公司一個(gè)開源的高性能服務(wù)框架,致力于提供高性能和透明化的 RPC 遠(yuǎn)程服務(wù)調(diào)用方案,以及 SOA 服務(wù)治理方案,使得應(yīng)用可通過高性能 RPC 實(shí)現(xiàn)服務(wù)的輸出、輸入功能和 Spring 框架無縫集成。Dubbo 包含遠(yuǎn)程通訊、集群容錯(cuò)和自動(dòng)發(fā)現(xiàn)三個(gè)核心部分。
它提供透明化的遠(yuǎn)程方法調(diào)用,實(shí)現(xiàn)像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程方法,只需簡單配置,沒有任何 API 侵入。同時(shí)它具備軟負(fù)載均衡及容錯(cuò)機(jī)制,可在內(nèi)網(wǎng)替代 F5 等硬件負(fù)載均衡器,降低成本,減少單點(diǎn)。它可以實(shí)現(xiàn)服務(wù)自動(dòng)注冊(cè)與發(fā)現(xiàn),不再需要寫死服務(wù)提供方地址,注冊(cè)中心基于接口名查詢服務(wù)提供者的 IP 地址,并且能夠平滑添加或刪除服務(wù)提供者。
2011 年末,阿里巴巴在 GitHub 上開源了基于 Java 的分布式服務(wù)治理框架 Dubbo,之后它成為了國內(nèi)該類開源項(xiàng)目的佼佼者,許多開發(fā)者對(duì)其表示青睞。同時(shí),先后有不少公司在實(shí)踐中基于 Dubbo 進(jìn)行分布式系統(tǒng)架構(gòu)。目前在 GitHub 上,它的 fork、star 數(shù)均已破萬。
Dubbo核心功能:
- 遠(yuǎn)程通訊,提供對(duì)多種基于長連接的 NIO 框架抽象封裝,包括多種線程模型,序列化,以及“請(qǐng)求-響應(yīng)”模式的信息交換方式。
- 集群容錯(cuò),提供基于接口方法的透明遠(yuǎn)程過程調(diào)用,包括多協(xié)議支持,以及軟負(fù)載均衡,失敗容錯(cuò),地址路由,動(dòng)態(tài)配置等集群支持。
- 自動(dòng)發(fā)現(xiàn),基于注冊(cè)中心目錄服務(wù),使服務(wù)消費(fèi)方能動(dòng)態(tài)的查找服務(wù)提供方,使地址透明,使服務(wù)提供方可以平滑增加或減少機(jī)器。
Dubbo架構(gòu)
- 服務(wù)提供者 - 啟動(dòng)時(shí)在指定端口上暴露服務(wù),并將服務(wù)地址和端口注冊(cè)到注冊(cè)中心上
- 服務(wù)消費(fèi)者 - 啟動(dòng)時(shí)向注冊(cè)中心訂閱自己感興趣的服務(wù),以便獲得服務(wù)提供方的地址列表
- 注冊(cè)中心 - 負(fù)責(zé)服務(wù)的注冊(cè)和發(fā)現(xiàn),負(fù)責(zé)保存服務(wù)提供方上報(bào)的地址信息,并向服務(wù)消費(fèi)方推送
- 監(jiān)控中心 - 負(fù)責(zé)收集服務(wù)提供方和消費(fèi)方的運(yùn)行狀態(tài),比如服務(wù)調(diào)用次數(shù)、延遲等,用于監(jiān)控
- 運(yùn)行容器 - 負(fù)責(zé)服務(wù)提供方的初始化、加載以及運(yùn)行的生命周期管理
部署階段
- 服務(wù)提供者在指定端口暴露服務(wù),并向注冊(cè)中心注冊(cè)服務(wù)信息。
- 服務(wù)消費(fèi)者向注冊(cè)中心發(fā)起服務(wù)地址列表的訂閱。
運(yùn)行階段
- 注冊(cè)中心向服務(wù)消費(fèi)者推送地址列表信息。
- 服務(wù)消費(fèi)者收到地址列表后,從其中選取一個(gè)向目標(biāo)服務(wù)發(fā)起調(diào)用。
- 調(diào)用過程服務(wù)消費(fèi)者和服務(wù)提供者的運(yùn)行狀態(tài)上報(bào)給監(jiān)控中心。
調(diào)用關(guān)系說明
- 服務(wù)容器負(fù)責(zé)啟動(dòng),加載,運(yùn)行服務(wù)提供者。
- 服務(wù)提供者在啟動(dòng)時(shí),向注冊(cè)中心注冊(cè)自己提供的服務(wù)。
- 服務(wù)消費(fèi)者在啟動(dòng)時(shí),向注冊(cè)中心訂閱自己所需的服務(wù)。
- 注冊(cè)中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更,注冊(cè)中心將基于長連接推送變更數(shù)據(jù)給消費(fèi)者。
- 服務(wù)消費(fèi)者,從提供者地址列表中,基于軟負(fù)載均衡算法,選一臺(tái)提供者進(jìn)行調(diào)用,如果調(diào)用失敗,再選另一臺(tái)調(diào)用。
- 服務(wù)消費(fèi)者和提供者,在內(nèi)存中累計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間,定時(shí)每分鐘發(fā)送一次統(tǒng)計(jì)數(shù)據(jù)到監(jiān)控中心。
Dubbo特點(diǎn)
Dubbo 架構(gòu)具有以下幾個(gè)特點(diǎn),分別是連通性、健壯性、伸縮性、以及向未來架構(gòu)的升級(jí)性。
連通性
- 注冊(cè)中心負(fù)責(zé)服務(wù)地址的注冊(cè)與查找,相當(dāng)于目錄服務(wù),服務(wù)提供者和消費(fèi)者只在啟動(dòng)時(shí)與注冊(cè)中心交互,注冊(cè)中心不轉(zhuǎn)發(fā)請(qǐng)求,壓力較小
- 監(jiān)控中心負(fù)責(zé)統(tǒng)計(jì)各服務(wù)調(diào)用次數(shù),調(diào)用時(shí)間等,統(tǒng)計(jì)先在內(nèi)存匯總后每分鐘一次發(fā)送到監(jiān)控中心服務(wù)器,并以報(bào)表展示
- 服務(wù)提供者向注冊(cè)中心注冊(cè)其提供的服務(wù),并匯報(bào)調(diào)用時(shí)間到監(jiān)控中心,此時(shí)間不包含網(wǎng)絡(luò)開銷
- 服務(wù)消費(fèi)者向注冊(cè)中心獲取服務(wù)提供者地址列表,并根據(jù)負(fù)載算法直接調(diào)用提供者,同時(shí)匯報(bào)調(diào)用時(shí)間到監(jiān)控中心,此時(shí)間包含網(wǎng)絡(luò)開銷
- 注冊(cè)中心,服務(wù)提供者,服務(wù)消費(fèi)者三者之間均為長連接,監(jiān)控中心除外
- 注冊(cè)中心通過長連接感知服務(wù)提供者的存在,服務(wù)提供者宕機(jī),注冊(cè)中心將立即推送事件通知消費(fèi)者
- 注冊(cè)中心和監(jiān)控中心全部宕機(jī),不影響已運(yùn)行的提供者和消費(fèi)者,消費(fèi)者在本地緩存了提供者列表
- 注冊(cè)中心和監(jiān)控中心都是可選的,服務(wù)消費(fèi)者可以直連服務(wù)提供者
健壯性
- 監(jiān)控中心宕掉不影響使用,只是丟失部分采樣數(shù)據(jù)
- 數(shù)據(jù)庫宕掉后,注冊(cè)中心仍能通過緩存提供服務(wù)列表查詢,但不能注冊(cè)新服務(wù)
- 注冊(cè)中心對(duì)等集群,任意一臺(tái)宕掉后,將自動(dòng)切換到另一臺(tái)
- 注冊(cè)中心全部宕掉后,服務(wù)提供者和服務(wù)消費(fèi)者仍能通過本地緩存通訊
- 服務(wù)提供者無狀態(tài),任意一臺(tái)宕掉后,不影響使用
- 服務(wù)提供者全部宕掉后,服務(wù)消費(fèi)者應(yīng)用將無法使用,并無限次重連等待服務(wù)提供者恢復(fù)
伸縮性
- 注冊(cè)中心為對(duì)等集群,可動(dòng)態(tài)增加機(jī)器部署實(shí)例,所有客戶端將自動(dòng)發(fā)現(xiàn)新的注冊(cè)中心
- 服務(wù)提供者無狀態(tài),可動(dòng)態(tài)增加機(jī)器部署實(shí)例,注冊(cè)中心將推送新的服務(wù)提供者信息給消費(fèi)者
升級(jí)性
當(dāng)服務(wù)集群規(guī)模進(jìn)一步擴(kuò)大,帶動(dòng)IT治理結(jié)構(gòu)進(jìn)一步升級(jí),需要實(shí)現(xiàn)動(dòng)態(tài)部署,進(jìn)行流動(dòng)計(jì)算,現(xiàn)有分布式服務(wù)架構(gòu)不會(huì)帶來阻力。下圖是未來可能的一種架構(gòu):

節(jié)點(diǎn)角色說明
| 節(jié)點(diǎn) | 角色說明 |
|---|---|
Deployer |
自動(dòng)部署服務(wù)的本地代理 |
Repository |
倉庫用于存儲(chǔ)服務(wù)應(yīng)用發(fā)布包 |
Scheduler |
調(diào)度中心基于訪問壓力自動(dòng)增減服務(wù)提供者 |
Admin |
統(tǒng)一管理控制臺(tái) |
Registry |
服務(wù)注冊(cè)與發(fā)現(xiàn)的注冊(cè)中心 |
Monitor |
統(tǒng)計(jì)服務(wù)的調(diào)用次數(shù)和調(diào)用時(shí)間的監(jiān)控中心 |
大家可訪問官網(wǎng)文檔:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html,里面有詳細(xì)說明和使用說明的。這里就不再闡述了。
Dubbo集成和使用
基于官方的
incubator-dubbo-spring-boot-project項(xiàng)目,在SpringBoot中集成起來很簡單。
注意:由于本系列還是使用1.5.x版本進(jìn)行講解,所以使用的版本為0.1.x。若使用SpringBoot2.x的同學(xué),可以使用0.2.x版本。
這里為了方便,直接創(chuàng)建了一個(gè)接口工程,spring-boot-dubbo-api。
IHelloService.java
/**
* 定義一個(gè)接口
* @author oKong
*
*/
public interface IHelloService {
String hello(String name);
}
服務(wù)提供者
創(chuàng)建一個(gè)spring-boot-dubbo-provider工程。
0.引入pom依賴。
<!-- 引入api -->
<dependency>
<groupId>cn.lqdev.learning</groupId>
<artifactId>spring-boot-dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 引入dubbo依賴 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.1</version>
</dependency>
<!-- 引入redis作為注冊(cè)中心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
注意:這里直接選用了redis作為注冊(cè)中心使用。默認(rèn)是zookeeper。
1.編寫接口實(shí)現(xiàn)類。
HelloServiceImpl.java
/**
* 定義一個(gè)服務(wù)實(shí)現(xiàn)類
* @author oKong
*
*/
// 這里注意 此類@service是dubbo的
@Service(
version = "${demo.service.version}", //版本
application = "${dubbo.application.id}", //應(yīng)用ID
protocol = "${dubbo.protocol.id}", //協(xié)議id
registry = "${dubbo.registry.id}")//注冊(cè)中心id
@Slf4j
public class HelloServiceImpl implements IHelloService {
@Override
public String hello(String name) {
log.info("dubbo提供者,參數(shù)name:{}", name);
return "hello " + name + ",this is a dubbo provider!";
}
}
說明下:這里的@Service是包路徑com.alibaba.dubbo.config.annotation.Service下的注解類,其指定了接口版本、協(xié)議id、注冊(cè)中心id等基本信息。這里注意還是版本號(hào)有用,因?yàn)闀?huì)一個(gè)接口多版本共存問題,所以一般上都會(huì)設(shè)置版本信息的。
2.設(shè)置配置文件信息,添加dubbo相關(guān)信息,比如注冊(cè)中心類型,地址等。
# 應(yīng)用名稱 便于識(shí)別
dubbo.application.id=spring-boot-dubbo-provider
dubbo.application.name=spring-boot-dubbo-provider
server.port=8686
# 設(shè)置版本
demo.service.version=1.0.0
#協(xié)議 可選dubbo redis、http、thrift等
dubbo.protocol.id=dubbo
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#設(shè)置掃描路徑 被注解@service和@Reference 等
dubbo.scan.basePackages=cn.lqdev.learning.springboot.dubbo.provider.service
# 注冊(cè)中心配置
dubbo.registry.id=okong-registry
#注冊(cè)中心類型 這里使用redis作為注冊(cè)中心
# zookeeper://127.0.0.1:2181
dubbo.registry.address=redis://127.0.0.1:6379
# 設(shè)置用戶名密碼 若有的話
#dubbo.registry.username=oKong
#dubbo.registry.password=oKong
# 設(shè)置redis參數(shù)
# 連接池中的最大空閑連接
dubbo.registry.parameters.max.idle=8
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
dubbo.registry.parameters.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
dubbo.registry.parameters.max-wait=-1
# 連接池中的最大空閑連接
dubbo.registry.parameters.max-idle=8
# 連接池中的最小空閑連接
dubbo.registry.parameters.min-idle=0
注意:這里為了方便,直接使用了Redis作為了注冊(cè)中心。對(duì)于redis連接相關(guān)配置參數(shù),可以通過dubbo.registry.parameters.xxx的形式來進(jìn)行設(shè)置,由于parameters是個(gè)Map對(duì)象,所以添加的key是不會(huì)進(jìn)行大小寫轉(zhuǎn)換的,填寫了什么就是什么。具體的registry配置對(duì)象,可以查看com.alibaba.dubbo.config.RegistryConfig類。而對(duì)于redis相關(guān)參數(shù)配置,可以查看com.alibaba.dubbo.registry.redis.RedisRegistry類。
其他的注冊(cè)中心,也是類似的,大家可在包com.alibaba.dubbo.registry找到都要的注冊(cè)中心配置類。
3.啟動(dòng)類編寫。
DubboProviderApplication.java
/**
* dubbo-提供者
* @author oKong
*
*/
@SpringBootApplication
@Slf4j
public class DubboProviderApplication {
public static void main(String[] args) throws Exception {
//由于dubbo提供者只是單純提供服務(wù)的 可以為一個(gè)非web環(huán)境
new SpringApplicationBuilder(DubboProviderApplication.class).web(false).run(args);
log.info("spring-boot-dubbo-provider啟動(dòng)!");
}
}
4.啟動(dòng)應(yīng)用,可以訪問下redis服務(wù),可以看見已經(jīng)有服務(wù)列表信息了。
服務(wù)消費(fèi)者
創(chuàng)建spring-boot-dubbo-consumer工程。
0.引入pom依賴
<!-- 引入api -->
<dependency>
<groupId>cn.lqdev.learning</groupId>
<artifactId>spring-boot-dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 引入dubbo依賴 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.1</version>
</dependency>
<!-- 引入redis作為注冊(cè)中心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1.配置文件添加注冊(cè)中心及服務(wù)版本相關(guān)信息
# 應(yīng)用名稱 便于識(shí)別
dubbo.application.id=spring-boot-dubbo-consumer
dubbo.application.name=spring-boot-dubbo-consumer
server.port=9696
#設(shè)置掃描路徑 被注解@service和@Reference 等
dubbo.scan.basePackages=cn.lqdev.learning.springboot.dubbo.consumer
# 注冊(cè)中心配置
dubbo.registry.id=okong-registry
#注冊(cè)中心類型 這里使用redis作為注冊(cè)中心
# zookeeper://127.0.0.1:2181
dubbo.registry.address=redis://127.0.0.1:6379
# 設(shè)置用戶名密碼 若有的話
#dubbo.registry.username=oKong
#dubbo.registry.password=oKong
# 設(shè)置redis參數(shù)
# 連接池中的最大空閑連接
dubbo.registry.parameters.max.idle=8
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
dubbo.registry.parameters.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
dubbo.registry.parameters.max-wait=-1
# 連接池中的最大空閑連接
dubbo.registry.parameters.max-idle=8
# 連接池中的最小空閑連接
dubbo.registry.parameters.min-idle=0
2.啟動(dòng)類編寫
DubboConsumerApplication.java
/**
* dubbo-消費(fèi)者實(shí)例
* @author oKong
*
*/
@SpringBootApplication
@Slf4j
public class DubboConsumerApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(DubboConsumerApplication.class, args);
log.info("spring-boot-dubbo-consumer啟動(dòng)!");
}
}
3.編寫一個(gè)restapi接口服務(wù),進(jìn)行服務(wù)調(diào)用。
/**
* 調(diào)用實(shí)例
* @author oKong
*
*/
@RestController
@Slf4j
public class DemoController {
/**
* 申明為一個(gè)reference,其實(shí)就是設(shè)置一個(gè)bean類了,
* 將原來xml配置替換成注解而已
* <dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” />
*/
@Reference(version = "1.0.0")
IHelloService helloService;
@GetMapping("/hello")
public String hello(String name) {
log.info("調(diào)用提供者服務(wù),參數(shù)name:{}", name);
return helloService.hello(name);
}
}
4.啟動(dòng)應(yīng)用,訪問:http://127.0.0.1:9696/hello?name=oKong ,可以看見服務(wù)調(diào)用成功了。
服務(wù)調(diào)用監(jiān)控后臺(tái)
官方監(jiān)控默認(rèn)支持了zookeeper。而且官方文檔也說了,對(duì)于
redis橋接實(shí)現(xiàn)只為開源版本提供,其可靠性依賴于 Redis 本身的可靠性。建議大家還是使用zookeeper吧,redis還是作為緩存使用吧。
監(jiān)控臺(tái)地址:https://github.com/apache/incubator-dubbo-ops
大家可自行安裝說明進(jìn)行編譯運(yùn)行下。
新的監(jiān)控界面:
[圖片上傳失敗...(image-3c6762-1553334118654)]
加入了Apache孵化器后,界面都是英文的了。。。還是原來的看的舒服呀!
[圖片上傳失敗...(image-6efd65-1553334118654)]
參考資料
總結(jié)
本章節(jié)主要介紹了
dubbo的集成和簡單的使用。具體其他的使用其實(shí)和原先是一樣的,并沒有什么區(qū)別。建議大家還是去看看官方文檔,目前改版后內(nèi)容豐富多了,干貨很多,建議還是去看看。這下終于是中文版的了,看的不頭疼了,⊙﹏⊙‖∣
最后
目前互聯(lián)網(wǎng)上很多大佬都有
SpringBoot系列教程,如有雷同,請(qǐng)多多包涵了。原創(chuàng)不易,碼字不易,還希望大家多多支持。若文中有所錯(cuò)誤之處,還望提出,謝謝。




