dubbox注解的一個坑


  我和我同事Daniel排查的一個問題,原文是我同事Daniel寫的,我做了些修改了補充。

  我們dubbox的provider端有很多service開發時沒有考慮到冪等問題,於是只能暫時關掉dubbo的重試功能。

  dubbo自帶的配置中有一個reties是可以配置重試次數的,官方文檔上說默認兩次,設置成0可以關閉重試。這種配置在使用xml 方式配置時是沒有問題的,然而用注解就比較坑。

  

  上圖是同事寫的使用注解的測試類截圖,有沒有發現0是灰色的?看看編譯后的.class文件:

  

  為什么呢,我們看這個注解的源碼:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface Reference {

   ...

    int retries() default 0;

   ...

}

  這個注解有個默認值0,編譯的時候被編譯器發現,於是優化掉了。而調用的時候:

  

  從注解中反射找reties,如果沒找到就取默認值2,於是就造成了一個現象,只要不設置0就沒問題,0就會等同於2。上圖的完整方法:

    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyinvokers = invokers;
        checkInvokers(copyinvokers, invocation);
        int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
        if (len <= 0) {
            len = 1;
        }
        // retry loop.
        RpcException le = null; // last exception.
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        for (int i = 0; i < len; i++) {
            //重試時,進行重新選擇,避免重試時invoker列表已發生變化.
            //注意:如果列表發生了變化,那么invoked判斷會失效,因為invoker示例已經改變
            if (i > 0) {
                checkWheatherDestoried();
                copyinvokers = list(invocation);
                //重新檢查一下
                checkInvokers(copyinvokers, invocation);
            }
            Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers((List)invoked);
            try {
                Result result = invoker.invoke(invocation);
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + invocation.getMethodName()
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers 
                            + " (" + providers.size() + "/" + copyinvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                return result;
            } catch (RpcException e) {
                if (e.isBiz()) { // biz exception.
                    throw e;
                }
                le = e;
            } catch (Throwable e) {
                le = new RpcException(e.getMessage(), e);
            } finally {
                providers.add(invoker.getUrl().getAddress());
            }
        }
        throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method "
                + invocation.getMethodName() + " in the service " + getInterface().getName() 
                + ". Tried " + len + " times of the providers " + providers 
                + " (" + providers.size() + "/" + copyinvokers.size() 
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le);
    }

   這個方法就是遠程調用中會執行的Invoke鏈中的一個,通過:

        int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
        if (len <= 0) {
            len = 1;
        }

  上面這個判斷可以猜到,文檔中說的值為0關閉重試就是說的這句判斷了。上一句中對反射得到的值進行了+1,這個+1就是加上了本身調用的一次,這里就是最大可能執行的總次數。文檔中給出了一個方便人理解的值0來控制是否重試。由於一些原因只能用注解的方式,又無法使用0,這里的判斷是<=0,那我們就在注解上設置-1或者更小都可以,於是結果就可以滿足需要了。經過測試發現確實可以,於是問題解決的。注意,雖然問題解決了,但這個方式非常不好,只是限於一些原因只能暫時采用這種別扭的方式去做了,並不提倡。

==========================================================

咱最近用的github:https://github.com/saaavsaaa

微信公眾號:

                      


免責聲明!

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



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