說明:內容主要來至於官方文檔
官方文檔地址: https://dubbo.apache.org/
配置優先級:
Dubbo支持的配置來源,默認有四種配置來源:
- JVM System Properties,-D參數
- Externalized Configuration,外部化配置
- ServiceConfig、ReferenceConfig等編程接口採集的配置
- 本地配置文件dubbo.properties,在Springboot中application.yml中也可以配置,dubbo-spring-boot-starter做了支持
配置的粒度說明:
dubbo的很多配置粒度可以細化到方法級別,也可以粗放到一個接口(接口又分爲消費者、調用者),甚至可以粗放到所有消費者和服務提供者。
通過上面圖,我們知道針對Dubbo配置的優先級、以及配置的粒度,那麼接一下我對配置的說明都針對@Service、@Reference註解來進行配置。
1、啓動依賴檢查,啓動檢查作用:在服務啓動時檢查可用性,讓服務問題儘早暴露出來。
/** 可以在指定的接口中設置是否檢查可用性 */
@Reference(check = true)
private DemoService demoService;
可以在註解上針對某個服務設置啓動時
或者在 application.yml中可以配置
spring:
application:
name: hello-api
dubbo:
# 指定註冊中心
registry:
address: zookeeper://192.168.50.220:2181
# 指定消費者,提供者所在的包路徑
scan:
base-packages:
- com.example.demo.web
# 設置消費者啓動時不檢查服務可用性,默認是true,需要檢查可用性,建議開啓
consumer:
check: true
改配置是針對消費者啓動時,是否進行服務可用性檢查,當然也可以在配置中針對指定服務進行配置,但是不建議那樣配置!至於爲什麼?可以自己想想的。
2、集羣容錯
集羣容錯:我理解的是,保證服務調用可用性,及爲集羣容錯
dubbo提供了多種集羣容錯方案,默認爲failover。
Failover Cluster
失敗自動切換,當出現失敗,重試其它服務器 [1]。通常用於讀操作,但重試會帶來更長延遲。可通過 retries="2"
來設置重試次數(不含第一次)。
重試次數配置如下:
@Reference(retries = 1)
private DemoService demoService2;
或者 針對方法進行配置
@Reference(methods = { @Method(name = "sayHello", retries = 1) })
private DemoService demoService2;
或者 配置中針對所有提供者
dubbo:
provider:
retries: 1
更多配置方式參考官方文檔: https://dubbo.apache.org/zh-cn/docs/user/demos/fault-tolerent-strategy.html
Failfast Cluster
快速失敗,只發起一次調用,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
@Reference(cluster = "failfast")
private DemoService demoService3;
代碼說明:cluster的值,可以點到註解的cluster方法上查看。
Failsafe Cluster
失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於消息通知操作。
Forking Cluster
並行調用多個服務器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks="2"
來設置最大並行數。
@Reference(cluster = "forking")
private DemoService demoService;
我沒有在註解中找到: forks這個配置參數
Broadcast Cluster
廣播調用所有提供者,逐個調用,任意一臺報錯則報錯 [2]。通常用於通知所有提供者更新緩存或日誌等本地資源信息。
3、負載均衡
@Reference(loadbalance = "random")
private DemoService demoService3;
Random LoadBalance
- 隨機,按權重設置隨機概率。
- 在一個截面上碰撞的概率高,但調用量越大分佈越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者權重。
RoundRobin LoadBalance
- 輪詢,按公約後的權重設置輪詢比率。
- 存在慢的提供者累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。
LeastActive LoadBalance
- 最少活躍調用數,相同活躍數的隨機,活躍數指調用前後計數差。
- 使慢的提供者收到更少請求,因爲越慢的提供者的調用前後計數差會越大。
ConsistentHash LoadBalance
- 一致性 Hash,相同參數的請求總是發到同一提供者。
- 當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。
- 算法參見:http://en.wikipedia.org/wiki/Consistent_hashing
- 缺省只對第一個參數 Hash,如果要修改,請配置
<dubbo:parameter key="hash.arguments" value="0,1" />
- 缺省用 160 份虛擬節點,如果要修改,請配置
<dubbo:parameter key="hash.nodes" value="320" />
從官網的配置看,存在4中負載均衡策略,但是從配置中看是3中配置,一致性Hash不再,需要專題看看這個問題。以及自定義負載均衡器。
/**
* Load balance strategy, legal values include: random, roundrobin, leastactive
*
* see Constants#DEFAULT_LOADBALANCE
*/
String loadbalance() default "";
4、直連、只訂閱
這兩種方式的組合,正好支持本地開發調試的操作。
只訂閱配置:
dubbo:
registry:
address: zookeeper://192.168.50.220:2181
register: false
直連配置:
@Reference(url = "dubbo://192.168.50.30:12345")
private DemoService demoService;
4、只註冊
如果有兩個鏡像環境,兩個註冊中心,有一個服務只在其中一個註冊中心有部署,另一個註冊中心還沒來得及部署,而兩個註冊中心的其它應用都需要依賴此服務。這個時候,可以讓服務提供者方只註冊服務到另一註冊中心,而不從另一註冊中心訂閱服務。
目的:讓另一個註冊中心的其他服務可以使用該服務,但是該服務運行時所需要的服務不從另一個註冊中心訂閱。
基於application.yml的多註冊中心支持配置: https://blog.csdn.net/q258523454/article/details/103481326
5、多協議暴露
Dubbo 允許配置多協議,在不同服務上支持不同協議或者同一服務上同時支持多種協議。
不同服務在性能上適用不同協議進行傳輸,比如大數據用短連接協議,小數據大併發用長連接協議
一個服務也可以同時暴露多種協議。
基於application.yml的多協議暴露配置: https://blog.csdn.net/u013887008/article/details/89738398
6、多註冊中心配置
支持一個服務同時註冊到多個註冊中心
支持不同的服務從不同的註冊到不同的註冊中心。
支持不同服務從不同的註冊中心註冊。
多註冊中心配置,豎號分隔表示同時連接多個不同註冊中心,同一註冊中心的多個集羣地址用逗號分隔
7、服務分組
當一個接口有多種實現時,可以用 group 區分。
@Service(group = "message")
public class DemoServiceImpl implements DemoService {
private final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@Override
public String sayHello(String name) {
logger.info("welcome {}", name);
return name + ", hi";
}
}
8、多版本
當一個接口實現,出現不兼容升級時,可以用版本號過渡,版本號不同的服務相互間不引用。
可以按照以下的步驟進行版本遷移:
- 在低壓力時間段,先升級一半提供者爲新版本
- 再將所有消費者升級爲新版本
- 然後將剩下的一半提供者升級爲新版本
9、分組聚合
基於註解不支持聚合!!!!
10、回聲檢查
回聲測試用於檢測服務是否可用,回聲測試按照正常請求流程執行,能夠測試整個調用是否通暢,可用於監控。
所有服務自動實現 EchoService
接口,只需將任意服務引用強制轉型爲 EchoService
,即可使用。
package com.example.demo.web;
import java.util.List;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.rpc.service.EchoService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.hello.service.DemoService;
@RestController
public class TestController {
@Reference
private DemoService demoService;
@GetMapping("/test")
public String hello(String name) {
EchoService echoService = (EchoService) demoService;
Object status = echoService.$echo("hello");
System.out.println("回聲檢查:" + status);
return demoService.sayHello(name);
}
}
11、參數回調
參數回調方式與調用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中聲明哪個參數是 callback 類型即可(註解中指明也可以)。Dubbo 將基於長連接生成反向代理,這樣就可以從服務器端調用客戶端邏輯。
示例:以創建訂單爲例,創建完成後回調調用方,告知最終狀態。
定義回調接口:
package com.example.hello.service.callback;
@FunctionalInterface
public interface CreatedOrderCallback {
Boolean done(Integer orderId, Integer orderStatus);
}
定義創建訂單接口:
package com.example.hello.service;
import com.example.hello.service.callback.CreatedOrderCallback;
public interface CreateOrderService {
Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback);
}
服務提供者 - 實現創建訂單:
package com.example.demo.provider.service;
import org.apache.dubbo.config.annotation.Argument;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import com.example.hello.service.CreateOrderService;
import com.example.hello.service.callback.CreatedOrderCallback;
@Service(callbacks = 1000, connections = 1, methods = {
@Method(name = "createdOrder", arguments = {
@Argument(index = 2, callback = true)
})
}
)
public class CreateOrderServiceImpl implements CreateOrderService {
@Override
public Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback) {
System.out.println("created, id: " + id + ", count: " + count);
// 可以先將callback示例存儲起來,可以在異步處理後進行callback,執行這個回調
callback.done(id, -10);
return id;
}
}
註解說明: 配置callbacks的超時時間,通過methods定義方法配置,通過Method的arguments指定參數配置,在參數配置中指定第幾個參數是回調對象,index從0開始,callback設置爲true
服務消費者-調用方實現
@Reference
private CreateOrderService createOrderService;
@GetMapping("/order")
public Integer order(Integer id, Integer count) {
return createOrderService.createdOrder(id, count, (orderId, status) -> {
System.out.println("callback success, orderId: " + orderId + ", status: " + status);
return Boolean.TRUE;
});
}
執行結果:
12、本地存根,類似Feign的異常Handler
基於【參數回調】中的例子,進行測試
新建CreateOrderServiceStub.java,用於本地存根處理,該代碼放到公共Jar中
package com.example.hello.service.stub;
import com.example.hello.service.CreateOrderService;
import com.example.hello.service.callback.CreatedOrderCallback;
public class CreateOrderServiceStub implements CreateOrderService {
private final CreateOrderService createOrderService;
public CreateOrderServiceStub(CreateOrderService createOrderService) {
this.createOrderService = createOrderService;
}
@Override
public Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback) {
// 此代碼在客戶端執行, 你可以在客戶端做ThreadLocal本地緩存,或預先驗證參數是否合法,等等
try {
return createOrderService.createdOrder(id, count, callback);
} catch (Exception e) {
System.out.println(e.getMessage());
// 你可以容錯,可以做任何AOP攔截事項
return -1;
}
}
}
說明:
-
Stub 必須有可傳入 Proxy 的構造函數。 ↩︎
-
在 interface 旁邊放一個 Stub 實現,它實現 BarService 接口,並有一個傳入遠程 BarService 實例的構造函
服務提供者,修改一下註解配置
package com.example.demo.provider.service;
import org.apache.dubbo.config.annotation.Argument;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import com.example.hello.service.CreateOrderService;
import com.example.hello.service.callback.CreatedOrderCallback;
@Service(callbacks = 1000, connections = 1, methods = {
@Method(name = "createdOrder", arguments = {
@Argument(index = 2, callback = true)
})
}, stub = "com.example.hello.service.stub.CreateOrderServiceStub"
)
public class CreateOrderServiceImpl implements CreateOrderService {
@Override
public Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback) {
System.out.println("created, id: " + id + ", count: " + count);
// 這一步callback操作,可以在異步處理後,執行這個回調
callback.done(id, -10);
if(id.intValue() == -100) {
throw new RuntimeException("任性的異常拋出");
}
return id;
}
}
說明: @Service註解上新增stub屬性,指定stub的實現類的類名