1. 程式人生 > 實用技巧 >dubbo超時重試

dubbo超時重試

dubbo超時重試概述

consumer端和provider端都可以設定timeout。

超時優先順序:consumer方法級>provider方法級>consumer介面級>provider介面級>consumer級>provider級

當consumer端呼叫超時,會觸發重試呼叫。

重試對應的配置屬性是retries。預設的重試次數是2。就是說,當呼叫超時,會最多重試2次,如果仍然失敗,會提示異常。

對於查詢或刪除來說,介面重試是冪等的。

對於新增資料,如果retries>0,則要做冪等處理,否則會造成重複資料入庫而產生bug。安全起見,可單獨設定retries=0。

【說明】在直連的情況下,是不會觸發重試的。

程式碼

Provider application.yml dubbo配置:

dubbo:
  application:
    name: zhanggz-dubbodemo
  registry:
#    address: N/A
    address: zookeeper://127.0.0.1:2181
  protocol:
    port: 28088
    name: dubbo
  scan:
    base-packages: dubbodemo.provider
  provider:
    timeout: 2200
    retries: 
3
View Code

Provider程式碼:

package dubbodemo.provider;

import dubbodemo.contract.HelloWord;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@Service(retries 
= 3) @SpringBootApplication public class ProviderApplication implements HelloWord { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class); } public String add(String str) { log.info("add入參:{}", str); long start = System.currentTimeMillis(); try { //int i=1/0; try { int r = RandomUtils.nextInt(1000, 2000); log.info("sleep time={}", r); Thread.sleep(r); } catch (InterruptedException e) { e.printStackTrace(); } return "test retry:" + str; } finally { log.info("duration={}", System.currentTimeMillis() - start); } } public String say() { return ("hello"); } }
View Code

Consumerapplication.yml dubbo配置:

dubbo:
  application:
    name: zhanggz-dubbodemo-consumer
  registry:
    address: zookeeper://127.0.0.1:2181
  #    address: N/A
  protocol:
    name: dubbo
  consumer:
    timeout: 1000
#    retries: 0
View Code

Consumer程式碼:

package dubbodemo.consumer;

import dubbodemo.contract.HelloWord;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class DubboConsumerTest {
    @Reference(/*url = "dubbo://localhost:28088",*/)
    private HelloWord helloWord;

    @Test
    public void testAddRetry() {
        long start = System.currentTimeMillis();
        log.info("請求開始...");
        try {
            String str = helloWord.add("str");
            log.info("返回值={}", str);
        } finally {
            log.info("duration=={}", System.currentTimeMillis() - start);
        }
    }
}
View Code

介面定義:

package dubbodemo.contract;

public interface HelloWord {
    String say();

    String add(String str);
}

測試結論

--------consumer不設定timeout(預設值=1000ms),改變provider的timeout值

【provider】
provider:
timeout: 1000
2020-07-23 18:53:57.427 INFO 13356 --- [:20880-thread-2] dubbodemo.provider.ProviderApplication : duration=2000
2020-07-23 18:53:57.432 WARN 13356 --- [:20880-thread-2] o.apache.dubbo.rpc.filter.TimeoutFilter : [DUBBO] invoke time out. method: add arguments: [str] , url is dubbo://192.168.40.69:20880/dubbodemo.contract.HelloWord?anyhost=true&application=zhanggz-dubbodemo&bean.name=ServiceBean:dubbodemo.contract.HelloWord&bind.ip=192.168.40.69&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=dubbodemo.contract.HelloWord&methods=add,say&pid=13356&qos.enable=false&register=true&release=2.7.3&side=provider&timeout=1000&timestamp=1595501612605, invoke elapsed 2005 ms., dubbo version: 2.7.3, current host: 192.168.40.69


【provider】
provider:
timeout: 2200
2020-07-23 18:57:16.949 INFO 12280 --- [:20880-thread-2] dubbodemo.provider.ProviderApplication : duration=2000
(沒有提示invoke timeout)

【consumer都會收到timeout異常】
2020-07-23 18:53:56.273 INFO 13216 --- [ main] dubbodemo.consumer.DubboConsumerTest : duration==1040

org.apache.dubbo.rpc.RpcException: Invoke remote method timeout. method: add, provider: dubbo://localhost:20880/dubbodemo.contract.HelloWord?application=zhanggz-dubbodemo-consumer&interface=dubbodemo.contract.HelloWord&lazy=false&pid=13216&qos.enable=false&register.ip=192.168.40.69&remote.application=&side=consumer&sticky=false, cause: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2020-07-23 18:53:55.250, end time: 2020-07-23 18:53:56.272, client elapsed: 106 ms, server elapsed: 916 ms, timeout: 1000 ms, request: Request [id=0, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=add, parameterTypes=[class java.lang.String], arguments=[str], attachments={path=dubbodemo.contract.HelloWord, interface=dubbodemo.contract.HelloWord, version=0.0.0}]], channel: /192.168.40.69:1813 -> /192.168.40.69:20880


----------------------------- 服務端停止執行後,客戶端無法啟動

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dubbodemo.consumer.DubboConsumerTest': Injection of @Reference dependencies is failed; nested exception is org.apache.dubbo.rpc.RpcException: Fail to create remoting client for service(dubbo://localhost:20880/dubbodemo.contract.HelloWord?application=zhanggz-dubbodemo-consumer&codec=dubbo&heartbeat=60000&interface=dubbodemo.contract.HelloWord&lazy=false&pid=5236&qos.enable=false&register.ip=192.168.40.69&remote.application=&side=consumer&sticky=false&timeout=2200): client(url: dubbo://localhost:20880/dubbodemo.contract.HelloWord?application=zhanggz-dubbodemo-consumer&codec=dubbo&heartbeat=60000&interface=dubbodemo.contract.HelloWord&lazy=false&pid=5236&qos.enable=false&register.ip=192.168.40.69&remote.application=&side=consumer&sticky=false&timeout=2200) failed to connect to server localhost/127.0.0.1:20880, error message is:Connection refused: no further information: /192.168.40.69:20880

----------------------------- consumer端設定dubbo.consumer.check=false。則可以啟動consumer服務。不過,當呼叫遠端服務的時候,由於遠端服務處於停止狀態,所以會報錯。org.apache.dubbo.rpc.RpcException: Failed to invoke remote method: add, provider: dubbo://localhost:20880/dubbodemo.contract.HelloWord?application=zhanggz-dubbodemo-consumer&check=false&interface=dubbodemo.contract.HelloWord&lazy=false&pid=12504&qos.enable=false&register.ip=192.168.40.69&remote.application=&side=consumer&sticky=false&timeout=2200, cause: message can not send, because channel is closed . url:dubbo://localhost:20880/dubbodemo.contract.HelloWord?application=zhanggz-dubbodemo-consumer&check=false&codec=dubbo&heartbeat=60000&interface=dubbodemo.contract.HelloWord&lazy=false&pid=12504&qos.enable=false&register.ip=192.168.40.69&remote.application=&side=consumer&sticky=false&timeout=2200

----------------------------------

consumer端,設定retries=3
2020-07-24 17:12:57.389 INFO 7468 --- [ main] dubbodemo.consumer.DubboConsumerTest : 請求開始...
2020-07-24 17:13:00.202 INFO 7468 --- [ main] dubbodemo.consumer.DubboConsumerTest : 返回值=test retry:str
2020-07-24 17:13:00.202 INFO 7468 --- [ main] dubbodemo.consumer.DubboConsumerTest : duration==2813

provider端:最多會被執行1+retries=4次
2020-07-24 17:12:57.540 INFO 2372 --- [28088-thread-17] dubbodemo.provider.ProviderApplication : add入參:str
2020-07-24 17:12:57.541 INFO 2372 --- [28088-thread-17] dubbodemo.provider.ProviderApplication : r=1169
2020-07-24 17:12:58.444 INFO 2372 --- [28088-thread-18] dubbodemo.provider.ProviderApplication : add入參:str
2020-07-24 17:12:58.444 INFO 2372 --- [28088-thread-18] dubbodemo.provider.ProviderApplication : r=1934
2020-07-24 17:12:58.711 INFO 2372 --- [28088-thread-17] dubbodemo.provider.ProviderApplication : duration=1170
2020-07-24 17:12:59.461 INFO 2372 --- [28088-thread-19] dubbodemo.provider.ProviderApplication : add入參:str
2020-07-24 17:12:59.461 INFO 2372 --- [28088-thread-19] dubbodemo.provider.ProviderApplication : r=736
2020-07-24 17:13:00.198 INFO 2372 --- [28088-thread-19] dubbodemo.provider.ProviderApplication : duration=737
2020-07-24 17:13:00.379 INFO 2372 --- [28088-thread-18] dubbodemo.provider.ProviderApplication : duration=1935