Motan 調(diào)用執(zhí)行流程

客戶端服務(wù)接口所持有的對象為RefererInvocationHandler,jdk的代理實(shí)現(xiàn)纤虽,invoke調(diào)用,先封裝DefaultRequest迷扇,遍歷clusters鸥昏,如果存在降級的則跳過,默認(rèn)選第一個(gè)非降級的cluster

  • clusters處理
for (Cluster<T> cluster : clusters) {
    String protocolSwitcher = MotanConstants.PROTOCOL_SWITCHER_PREFIX + cluster.getUrl().getProtocol();

    Switcher switcher = switcherService.getSwitcher(protocolSwitcher);
    // 跳過降級的cluster
    if (switcher != null && !switcher.isOn()) {
         continue;
    }
    // request設(shè)置各種數(shù)據(jù)
    // 最后通過cluster.call調(diào)用
    response = cluster.call(request);
}
  • 高可用策略處理
// cluster.call烟逊,通過配置的HA策略 來實(shí)現(xiàn)調(diào)用(默認(rèn)配置:FailoverHaStrategy)
public Response call(Request request) {
    if (available.get()) {
        try {
            // loadBalance將在haStrategy中處理
            return haStrategy.call(request, loadBalance);
        } catch (Exception e) {
            return callFalse(request, e);
        }
    }
    return callFalse(request, new MotanServiceException(MotanErrorMsgConstant.SERVICE_UNFOUND));
}
  • 負(fù)載均衡處理
// 選擇Refer渣窜,通過loadBalance.selectToHolder(request, referers);選擇
List<Referer<T>> referers = selectReferers(request, loadBalance);
URL refUrl = referers.get(0).getUrl();
//
// 從第一個(gè)url中獲取重試次數(shù)
int tryCount = refUrl.getMethodParameter(request.getMethodName(), 
        request.getParamtersDesc(), URLParamType.retries.getName(),
        URLParamType.retries.getIntValue());
// 如果有問題,則設(shè)置為不重試
if (tryCount < 0) {
  tryCount = 0;
}
for (int i = 0; i <= tryCount; i++) {
  // 選擇一個(gè)服務(wù)
  Referer<T> refer = referers.get(i % referers.size());
  try {
    // 設(shè)置重試次數(shù)
    request.setRetries(i);
    // 開始遠(yuǎn)程調(diào)用
    return refer.call(request);
  } catch (RuntimeException e) {
  // 對于業(yè)務(wù)異常宪躯,直接拋出
  if (ExceptionUtil.isBizException(e)) {
    throw e;
  } else if (i >= tryCount) {
    throw e;
  }
  LoggerUtil.warn(String.format("FailoverHaStrategy Call false for request:%s error=%s", request, e.getMessage()));
}
// selectToHolder的處理(選擇refers)
public void selectToHolder(Request request, List<Referer<T>> refersHolder) {
  List<Referer<T>> referers = this.referers;

  if (referers == null) {
    throw new MotanServiceException(this.getClass().getSimpleName() + " No available referers for call : referers_size= 0 "
                    + MotanFrameworkUtil.toString(request));
  }

  if (referers.size() > 1) {
    // 多于一個(gè)乔宿,繼續(xù)選(這里就根據(jù)配置的負(fù)載均衡策略來處理,
    // 默認(rèn)的是RoundRobinLoadBalance)访雪,但也會返回多個(gè)refer
    doSelectToHolder(request, refersHolder);
  } else if (referers.size() == 1 && referers.get(0).isAvailable()) {
    // 只有一個(gè)详瑞,只記錄當(dāng)前的
    refersHolder.add(referers.get(0));
  }
  if (refersHolder.isEmpty()) {
    throw new MotanServiceException(this.getClass().getSimpleName() + " No available referers for call : referers_size="
                    + referers.size() + " " + MotanFrameworkUtil.toString(request));
  }
}
  • refer.call最后在DefaultRpcProtocol的DefaultRpcReferer中通過NettyClient發(fā)出請求
protected Response doCall(Request request) {
    try {
      // 為了能夠?qū)崿F(xiàn)跨group請求,需要使用server端的group冬阳。
      request.setAttachment(URLParamType.group.getName(), serviceUrl.getGroup());
      return client.request(request);
    } catch (TransportException exception) {
      throw new MotanServiceException("DefaultRpcReferer call Error: url=" + url.getUri(), exception);
    }
}
  • 最終通過netty將消息發(fā)出
ChannelFuture writeFuture = this.channel.write(request);
// 注冊一個(gè)回調(diào)蛤虐,用來處理調(diào)用情況
response.addListener(new FutureListener() {
    @Override
    public void operationComplete(Future future) throws Exception {
        if (future.isSuccess() || (future.isDone() && ExceptionUtil.isBizException(future.getException()))) {
            // 成功的調(diào)用 
            nettyClient.resetErrorCount();
        } else {
            // 失敗的調(diào)用 
            nettyClient.incrErrorCount();
        }
    }
});

服務(wù)器端通過Netty接收客戶端的請求,入口為NettyChannelHandler的messageReceived

  • netty 處理
if (message instanceof Request) {
    processRequest(ctx, e);  // 處理客戶端發(fā)來的請求
} else if (message instanceof Response) {
    processResponse(ctx, e);
}
//
// 使用線程池處理調(diào)用請求
threadPoolExecutor.execute(new Runnable() {
    @Override
    public void run() {
        try{
            RpcContext.init(request);
            processRequest(ctx, request, processStartTime);
        }finally{
            RpcContext.destroy();
        }
    }
});
  • ProviderProtectedMessageRouter處理
// key:motan-demo-rpc/com.weibo.motan.demo.service.MotanDemoService/1.0
String serviceKey = MotanFrameworkUtil.getServiceKey(request);
// 根據(jù)key獲取Provider(DefaultProvider)
Provider<?> provider = providers.get(serviceKey);
// 通過反射調(diào)用
Method method = lookup(request);
Object value = method.invoke(proxyImpl, request.getArguments());
  • 然后進(jìn)入service層代碼處理肝陪,后續(xù)就是結(jié)果返回處理了驳庭。

大概的示意圖:


call.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市氯窍,隨后出現(xiàn)的幾起案子饲常,更是在濱河造成了極大的恐慌,老刑警劉巖狼讨,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贝淤,死亡現(xiàn)場離奇詭異,居然都是意外死亡政供,警方通過查閱死者的電腦和手機(jī)播聪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來布隔,“玉大人离陶,你說我怎么就攤上這事⌒铺矗” “怎么了招刨?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哀军。 經(jīng)常有香客問我沉眶,道長打却,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任谎倔,我火速辦了婚禮柳击,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘片习。我一直安慰自己腻暮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布毯侦。 她就那樣靜靜地躺著,像睡著了一般具垫。 火紅的嫁衣襯著肌膚如雪侈离。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天筝蚕,我揣著相機(jī)與錄音卦碾,去河邊找鬼。 笑死起宽,一個(gè)胖子當(dāng)著我的面吹牛洲胖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坯沪,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼绿映,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腐晾?” 一聲冷哼從身側(cè)響起叉弦,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藻糖,沒想到半個(gè)月后淹冰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巨柒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年樱拴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洋满。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晶乔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芦岂,到底是詐尸還是另有隱情瘪弓,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布禽最,位于F島的核電站腺怯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏呛占。R本人自食惡果不足惜虑乖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晾虑。 院中可真熱鬧疹味,春花似錦、人聲如沸帜篇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笙隙。三九已至洪灯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竟痰,已是汗流浹背签钩。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坏快,地道東北人铅檩。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像莽鸿,于是被迫代替她去往敵國和親昧旨。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言 本文繼續(xù)分析dubbo的cluster層祥得,此層封裝多個(gè)提供者的路由及負(fù)載均衡臼予,并橋接注冊中心,以Invoke...
    Java大生閱讀 987評論 0 0
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,448評論 0 13
  • 原文:https://developer.android.com/reference/android/media/...
    thebestofrocky閱讀 6,049評論 0 6
  • “陽歷年孩子們放假了?回來一趟吧创千,帶孩子來玩兩天缰雇。” “媽追驴,倆孩子都快考試了械哟,放了寒假再去吧〉钛” “我們老了暇咆,是不...
    涼涼笙閱讀 611評論 8 11
  • 早上被電話叫醒,睜眼一看已經(jīng)7:13,是婷媽媽打電話看我們收拾好了沒爸业。我很焦急地告訴她我才醒其骄,婷媽媽說那她們...
    段師傅貼膜閱讀 99評論 0 0