Dubbo 介紹
2018 年 2 月 15 日,阿里巴巴的服務治理框架 dubbo 透過投票,順利成為 Apache 基金會孵化專案。
Apache Dubbo 是一款高效能、輕量級的開源 Java RPC 框架,它提供了三大核心能力:面向介面的遠端方法呼叫,智慧容錯和負載均衡,以及服務自動註冊和發現。
Dubbo 架構
Dubbo 提供三個核心功能:基於介面的遠端呼叫、容錯和負載均衡,以及服務的自動註冊與發現。Dubbo 框架廣泛的在阿里巴巴內部使用,以及噹噹、去哪兒、網易考拉、滴滴等都在使用。
節點角色說明
| 節點 | 角色說明 | | ——————- | ———————————————————— | |
Provider
| 暴露服務的服務提供方 | |
Consumer
| 呼叫遠端服務的服務消費方 | |
Registry
| 服務註冊與發現的註冊中心 | |
Monitor
| 統計服務的呼叫次數和呼叫時間的監控中心 | |
Container
| 服務執行容器 |
呼叫關係說明
服務容器負責啟動,載入,執行服務提供者。
服務提供者在啟動時,向註冊中心註冊自己提供的服務。
服務消費者在啟動時,向註冊中心訂閱自己所需的服務。
註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
服務消費者,從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心。
Dubbo 快速入門
我們先透過一個簡單的案例讓大家理解一下 Dubbo 的使用,然後基於 Spring Boot 和 Spring Cloud 環境整合 Dubbo。
Dubbo 採用全 Spring 配置方式,透明化接入應用,對應用沒有任何 API 侵入,只需用 Spring 載入 Dubbo 的配置即可。
依賴
JDK 1。6 以上和 Maven 3。0 以上,採用 Maven 多模組聚合工程構建 api 模組,provider 模組以及 consumer 模組。
聚合工程
專案結構如下圖,簡單介紹一下:
dubbo-api
:服務介面
dubbo-provider
:依賴服務介面,具體的業務實現,服務提供者
dubbo-coonsumer
:依賴服務介面,遠端呼叫服務,服務消費者
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-v8VaFKLD-1626229842283)(DubboRPC通訊。assets/image-20200614114932671。png)]
依賴關係
dubbo-parent 的 pom。xml 依賴 apache dubbo。
dubbo-provider 和 dubbo-consumer 的 pom。xml 依賴 dubbo-api 服務介面。
定義服務介面
dubbo-api 中編寫 HelloService。java
package org。example。service;/** * Hello服務 */public interface HelloService { String sayHello(String name);}
定義服務提供者
在 provider 模組中實現服務介面
dubbo-provider 中編寫 HelloServiceImpl。java
package org。example。service。impl;import org。example。service。HelloService;/** * 服務實現 */public class HelloServiceImpl implements HelloService { public String sayHello(String name) { return “hello ” + name; }}
配置服務提供者
dubbo-provider。xml
<?xml version=“1。0” encoding=“UTF-8”?>
載入 Spring 配置啟動服務
package org。example;import org。springframework。context。support。ClassPathXmlApplicationContext;/** * 釋出服務 */public class Provider { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:dubbo-provider。xml”); context。start(); System。out。println(“服務註冊成功!”); System。in。read(); // 按任意鍵退出 }}
定義服務消費者
透過 Spring 配置引用遠端服務
dubbo-consumer。xml
<?xml version=“1。0” encoding=“UTF-8”?>
載入 Spring 配置並呼叫遠端服務
package org。example;import org。example。service。HelloService;import org。springframework。context。support。ClassPathXmlApplicationContext;/** * 呼叫遠端服務 */public class Consumer { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:dubbo-consumer。xml”); context。start(); HelloService helloService = (HelloService) context。getBean(“helloService”); // 獲取遠端服務代理 String result = helloService。sayHello(“world”); // 執行遠端方法 System。out。println(result); // 顯示呼叫結果 }}
Dubbo 常用標籤
dubbo:application
:應用程式名稱
dubbo:registry
:連線註冊中心資訊(配置註冊中心)
dubbo:protocol
:服務提供者註冊服務採用的協議
Dubbo 協議,預設
RMI 協議
Hessian 協議
HTTP 協議
WebService 協議
Thrift 協議
Memcached 協議
Redis 協議
Rest 協議(RESTful)
Grpc 協議
dubbo:service
:宣告需要暴露的服務介面
dubbo:reference
:配置訂閱的服務(生成遠端服務代理)
註冊中心
註冊中心我們已經學習了不少,例如:ZooKeeper、Eureka、Consul、Nacos 等等,註冊中心可以更高效的管理系統的服務:比如服務介面的釋出、自動剔除無效的服務、自動恢復服務等。
Dubbo 支援五種註冊中心:Multicast、Nacos(推薦)、ZooKeeper(推薦) 、Redis、Simple。本文重點介紹前兩個,更多註冊中心的資訊請參考:http://dubbo。apache。org/zh-cn/docs/user/references/registry/introduction。html
Multicast 註冊中心
Multicast 註冊中心不需要啟動任何中心節點,只要廣播地址一樣,就可以互相發現。
提供方啟動時廣播自己的地址
消費方啟動時廣播訂閱請求
提供方收到訂閱請求時,單播自己的地址給訂閱者,如果設定了
unicast=false
,則廣播給訂閱者
消費方收到提供方地址時,連線該地址進行 RPC 呼叫。
組播受網路結構限制,只適合小規模應用或開發階段使用。組播地址段: 224。0。0。0 - 239。255。255。255
配置
或
為了減少廣播量,Dubbo 預設使用單播發送提供者地址資訊給消費者,如果一個機器上同時啟了多個消費者程序,消費者需宣告
unicast=false
,否則只會有一個消費者能收到訊息。
當服務者和消費者執行在同一臺機器上,消費者同樣需要宣告
unicast=false
,否則消費者無法收到訊息,導致 No provider available for the service 異常。
或
zookeeper 註冊中心
Zookeeper 是 Apache Hadoop 的子專案,是一個樹型的目錄服務,支援變更推送,適合作為 Dubbo 服務的註冊中心,工業強度較高,可用於生產環境,推薦使用。
流程說明:
服務提供者啟動時: 向
/dubbo/com。foo。BarService/providers
目錄下寫入自己的 URL 地址。
服務消費者啟動時: 訂閱
/dubbo/com。foo。BarService/providers
目錄下的提供者 URL 地址。並向
/dubbo/com。foo。BarService/consumers
目錄下寫入自己的 URL 地址。
監控中心啟動時: 訂閱
/dubbo/com。foo。BarService
目錄下的所有提供者和消費者 URL 地址。
支援以下功能:
當提供者出現斷電等異常停機時,註冊中心能自動刪除提供者資訊;
當註冊中心重啟時,能自動恢復註冊資料,以及訂閱請求;
當會話過期時,能自動恢復註冊資料,以及訂閱請求;
當設定
時,記錄失敗註冊和訂閱請求,後臺定時重試;
可透過
設定 zookeeper 登入資訊;
可透過
設定 zookeeper 的根節點,不配置將使用預設的根節點;
支援
*
號萬用字元
,可訂閱服務的所有分組和所有版本的提供者。
作為 Dubbo 的老牌黃金搭檔 ZooKeeper,我們在單獨講解 Dubbo 時已經給大家分享過如何使用了,本文系 Spring Cloud Alibaba 系列文章,重點物件是 Nacos,所以 ZooKeeper 這裡就不過多贅述了。
Nacos 註冊中心
Nacos 是 Alibaba 公司推出的開源工具,用於實現分散式系統的服務發現與配置管理。Nacos 是 Dubbo 生態系統中重要的註冊中心實現。
預備工作
當您將 Nacos 整合到您的 Dubbo 工程之前,請確保後臺已經啟動 Nacos 服務。
快速上手
Dubbo 融合 Nacos 成為註冊中心的操作步驟非常簡單,大致步驟可分為“增加 Maven 依賴”和“配置註冊中心“。
依賴
核心依賴主要是
dubbo-registry-nacos
和
nacos-client
。
<!—— https://mvnrepository。com/artifact/org。apache。dubbo/dubbo-registry-nacos ——>
配置註冊中心
服務提供者和服務消費者只需要調整
address
屬性配置即可。
單機配置:
<!—— 使用 Nacos 註冊中心,單機版 ——>
叢集配置:
<!—— 使用 Nacos 註冊中心,叢集版 ——>
隨後,重啟您的 Dubbo 應用,Dubbo 的服務提供和消費資訊在 Nacos 控制檯中即可顯示。
Spring Cloud Alibaba Nacos 整合 Dubbo
之前的文章中,無論我們學習 Eureka、Consul 還是 Nacos,負責服務間通訊的功能都是由 Ribbon 來完成的,接下來我們使用 Dubbo 來替換 Ribbon。
聚合工程
dubbo-demo
聚合工程。
SpringBoot 2。3。0。RELEASE
、
Spring Cloud Hoxton。SR5
。
專案結構如下圖,簡單介紹一下:
service-api
:服務介面
product-service
:商品服務,服務提供者,提供了
/product/list
介面
order-service
:訂單服務,服務消費者,遠端呼叫商品服務
依賴關係
dubbo-demo 的 pom。xml。
<?xml version=“1。0” encoding=“UTF-8”?>
service-api 的 pom。xml
<?xml version=“1。0” encoding=“UTF-8”?>
product-service 需要依賴 Nacos 和 Dubbo 的依賴,還有 service-api 的依賴,完整依賴如下:
<?xml version=“1。0” encoding=“UTF-8”?>
order-service 需要依賴 Nacos 和 Dubbo 的依賴,還有 service-api 的依賴,完整依賴如下:
<?xml version=“1。0” encoding=“UTF-8”?>
定義服務介面
我們在
service-api
模組中定義實體類和服務介面資訊。
實體類
package com。example。product。pojo;import lombok。AllArgsConstructor;import lombok。Data;import lombok。NoArgsConstructor;import java。io。Serializable;@Data@NoArgsConstructor@AllArgsConstructorpublic class Product implements Serializable { private Integer id; private String productName; private Integer productNum; private Double productPrice;}package com。example。product。pojo;import lombok。AllArgsConstructor;import lombok。Data;import lombok。NoArgsConstructor;import java。io。Serializable;import java。util。List;@Data@NoArgsConstructor@AllArgsConstructorpublic class Order implements Serializable { private Integer id; private String orderNo; private String orderAddress; private Double totalPrice; private List
服務介面
package com。example。product。service;import com。example。product。pojo。Product;import java。util。List;/** * 商品服務 */public interface ProductService { /** * 查詢商品列表 * * @return */ List
定義服務提供者
配置檔案
配置檔案需要配置 Nacos 註冊中心和 Dubbo 相關資訊,核心配置如下:
server: port: 7070 # 埠spring: application: name: product-service # 應用名稱 # 配置 Nacos 註冊中心 cloud: nacos: discovery: enabled: true # 如果不想使用 Nacos 進行服務註冊和發現,設定為 false 即可 server-addr: 127。0。0。1:8848 # Nacos 伺服器地址,單機版# Dubbodubbo: # 提供方應用資訊,用於計算依賴關係 application: name: product-service # 使用 nacos 註冊中心暴露服務地址 registry: protocol: nacos address: spring-cloud://localhost # 用 dubbo 協議在 20880 埠暴露服務 protocol: name: dubbo port: 20880 # 掃描需要暴露的服務,可以被 @EnableDubbo 註解替代 #scan: # base-packages: com。example。service
服務提供者
product-service 的 ProductServiceImpl。java
package com。example。service。impl;import com。example。product。pojo。Product;import com。example。product。service。ProductService;import lombok。extern。slf4j。Slf4j;import org。apache。dubbo。config。annotation。Service;import java。util。Arrays;import java。util。List;/** * 商品服務 * timeout 呼叫該服務的超時時間 * version 為版本號 * group 為分組 * interface、group、version 三者確定一個服務 */@Slf4j@Service(timeout = 5000, version = “1。0”, group = “product-service”)public class ProductServiceImpl implements ProductService { /** * 查詢商品列表 * * @return */ @Override public List
值得注意的是
@Service
註解不是 Spring 的註解而是
Dubbo
的註釋:
啟動類
啟動類透過
@EnableDubbo
註解掃描需要暴露的服務,如果配置檔案中配置了該選項,那麼這裡可以省略。
package com。example;import org。apache。dubbo。config。spring。context。annotation。EnableDubbo;import org。springframework。boot。SpringApplication;import org。springframework。boot。autoconfigure。SpringBootApplication;// 掃描需要暴露的服務@EnableDubbo(scanBasePackages = “com。example。service”)// 開啟 @EnableDiscoveryClient 註解,當前版本預設會開啟該註解//@EnableDiscoveryClient@SpringBootApplicationpublic class ProductServiceApplication { public static void main(String[] args) { SpringApplication。run(ProductServiceApplication。class, args); }}
定義服務消費者
配置檔案
配置檔案需要配置 Nacos 註冊中心和 Dubbo 相關資訊,核心配置如下:
server: port: 9090 # 埠spring: application: name: order-service # 應用名稱 # 配置 Nacos 註冊中心 cloud: nacos: discovery: enabled: true # 如果不想使用 Nacos 進行服務註冊和發現,設定為 false 即可 server-addr: 127。0。0。1:8848 # Nacos 伺服器地址,單機版# Dubbodubbo: # 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 application: name: order-service # 發現 nacos 註冊中心暴露的服務 registry: protocol: nacos address: spring-cloud://localhost cloud: subscribed-services: product-service # 訂閱服務,遠端呼叫的服務名稱
服務消費者
order-service 的 OrderServiceImpl。java
package com。example。service。impl;import com。example。product。pojo。Order;import com。example。product。service。ProductService;import com。example。service。OrderService;import lombok。extern。slf4j。Slf4j;import org。apache。dubbo。config。annotation。Reference;import org。springframework。stereotype。Service;@Slf4j@Servicepublic class OrderServiceImpl implements OrderService { // dubbo 提供了 @Reference 註解,可替換 @Autowired 註解,用於引入遠端服務 // 如果註冊服務時設定了版本及分組資訊,呼叫遠端服務時也要設定對應的版本及分組資訊 @Reference(timeout = 5000, version = “1。0”, group = “product-service”) private ProductService productService; /** * 根據主鍵查詢訂單 * * @param id * @return */ @Override public Order selectOrderById(Integer id) { log。info(“訂單服務查詢訂單資訊。。。”); return new Order(id, “order-001”, “中國”, 22788D, productService。selectProductList()); }}
啟動類
package com。example;import org。springframework。boot。SpringApplication;import org。springframework。boot。autoconfigure。SpringBootApplication;// 開啟 @EnableDiscoveryClient 註解,當前版本預設會開啟該註解//@EnableDiscoveryClient@SpringBootApplicationpublic class OrderServiceApplication { public static void main(String[] args) { SpringApplication。run(OrderServiceApplication。class, args); }}
測試
先啟動 Nacos 伺服器,然後啟動服務提供者 product-service,訪問:http://localhost:8848/nacos/ 控制檯顯示如下:
然後啟動服務消費者,控制檯顯示如下:
訂單服務呼叫遠端商品服務,結果如下:
Dubbo 負載均衡
在叢集負載均衡時,Dubbo 提供了多種均衡策略,預設為
random
隨機呼叫,也可以自行擴充套件負載均衡策略。
負載均衡策略
Random LoadBalance
隨機
,按權重設定隨機機率。
在一個截面上碰撞的機率高,但呼叫量越大分佈越均勻,而且按機率使用權重後也比較均勻,有利於動態調整提供者權重。
RoundRobin LoadBalance
輪詢
,按公約後的權重設定輪詢比率。
存在慢的提供者累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。
LeastActive LoadBalance
最少活躍呼叫數
,ping 值(延遲低)的呼叫,相同延遲的情況下隨機。
使慢的提供者收到更少請求,因為越慢的提供者的呼叫前後計數差會越大。
ConsistentHash LoadBalance
一致性 Hash
,相同引數的請求總是發到同一提供者。
當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。
演算法參見:http://en。wikipedia。org/wiki/Consistent_hashing
預設只對第一個引數 Hash,如果要修改,請配置
預設用 160 份虛擬節點,如果要修改,請配置
配置
一般在專案中不會在程式碼層面指定權重,而是透過監控中心(dubbo-admin)對服務動態的指定權重,
xml
服務端服務級別
客戶端服務級別
服務端方法級別
客戶端方法級別
yaml
dubbo: provider: loadbalance: roundrobin weight: 100 consumer: loadbalance: roundrobin
註解
@Service(loadbalance = “roundrobin”, weight = 100)@Reference(loadbalance = “roundrobin”)
至此 Dubbo RPC 通訊所有的知識點就講解結束了。
stent_hashing - 預設只對第一個引數 Hash,如果要修改,請配置
- 預設用 160 份虛擬節點,如果要修改,請配置
配置
一般在專案中不會在程式碼層面指定權重,而是透過監控中心(dubbo-admin)對服務動態的指定權重
xml
服務端服務級別
客戶端服務級別
服務端方法級別
客戶端方法級別
yaml
dubbo: provider: loadbalance: roundrobin weight: 100 consumer: loadbalance: roundrobin
註解
@Service(loadbalance = “roundrobin”, weight = 100)@Reference(loadbalance = “roundrobin”)
至此 Dubbo RPC 通訊所有的知識點就講解結束了。