短影片app開發,叢集容錯策略的程式碼分析
1 Failover
public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> { public FailoverClusterInvoker(Directory<T> directory) { super(directory); } @Override public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { // 所有生產者Invokers List<Invoker<T>> copyInvokers = invokers; checkInvokers(copyInvokers, invocation); String methodName = RpcUtils.getMethodName(invocation); // 獲取重試次數 int len = getUrl().getMethodParameter(methodName, Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1; if (len <= 0) { len = 1; } RpcException le = null; // 已經呼叫過的生產者 List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); Set<String> providers = new HashSet<String>(len); // 重試直到達到最大次數 for (int i = 0; i < len; i++) { if (i > 0) { // 如果當前例項被銷燬則丟擲異常 checkWhetherDestroyed(); // 根據路由策略選出可用生產者Invokers copyInvokers = list(invocation); // 重新檢查 checkInvokers(copyInvokers, invocation); } // 負載均衡選擇一個生產者Invoker 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 " + methodName + " 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()) { throw e; } le = e; } catch (Throwable e) { // RpcException不丟擲繼續重試 le = new RpcException(e.getMessage(), e); } finally { // 儲存已經訪問過的生產者 providers.add(invoker.getUrl().getAddress()); } } throw new RpcException(le.getCode(), "Failed to invoke the method " + methodName + " 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.getMessage(), le.getCause() != null ? le.getCause() : le); } }
2 Failfast
public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> { public FailfastClusterInvoker(Directory<T> directory) { super(directory); } @Override public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { // 檢查生產者Invokers是否合法 checkInvokers(invokers, invocation); // 負載均衡選擇一個生產者Invoker Invoker<T> invoker = select(loadbalance, invocation, invokers, null); try { // 服務消費發起遠端呼叫 return invoker.invoke(invocation); } catch (Throwable e) { // 服務消費失敗不重試直接丟擲異常 if (e instanceof RpcException && ((RpcException) e).isBiz()) { throw (RpcException) e; } throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); } } }
3 Failsafe
public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> { private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class); public FailsafeClusterInvoker(Directory<T> directory) { super(directory); } @Override public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { try { // 檢查生產者Invokers是否合法 checkInvokers(invokers, invocation); // 負載均衡選擇一個生產者Invoker Invoker<T> invoker = select(loadbalance, invocation, invokers, null); // 服務消費發起遠端呼叫 return invoker.invoke(invocation); } catch (Throwable e) { // 消費失敗包裝為一個空結果物件 logger.error("Failsafe ignore exception: " + e.getMessage(), e); return new RpcResult(); } } }
4 Failback
public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> { private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class); private static final long RETRY_FAILED_PERIOD = 5; private final int retries; private final int failbackTasks; private volatile Timer failTimer; public FailbackClusterInvoker(Directory<T> directory) { super(directory); int retriesConfig = getUrl().getParameter(Constants.RETRIES_KEY, Constants.DEFAULT_FAILBACK_TIMES); if (retriesConfig <= 0) { retriesConfig = Constants.DEFAULT_FAILBACK_TIMES; } int failbackTasksConfig = getUrl().getParameter(Constants.FAIL_BACK_TASKS_KEY, Constants.DEFAULT_FAILBACK_TASKS); if (failbackTasksConfig <= 0) { failbackTasksConfig = Constants.DEFAULT_FAILBACK_TASKS; } retries = retriesConfig; failbackTasks = failbackTasksConfig; } private void addFailed(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, Invoker<T> lastInvoker) { if (failTimer == null) { synchronized (this) { if (failTimer == null) { // 建立定時器 failTimer = new HashedWheelTimer(new NamedThreadFactory("failback-cluster-timer", true), 1, TimeUnit.SECONDS, 32, failbackTasks); } } } // 構造定時任務 RetryTimerTask retryTimerTask = new RetryTimerTask(loadbalance, invocation, invokers, lastInvoker, retries, RETRY_FAILED_PERIOD); try { // 定時任務放入定時器等待執行 failTimer.newTimeout(retryTimerTask, RETRY_FAILED_PERIOD, TimeUnit.SECONDS); } catch (Throwable e) { logger.error("Failback background works error,invocation->" + invocation + ", exception: " + e.getMessage()); } } @Override protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { Invoker<T> invoker = null; try { // 檢查生產者Invokers是否合法 checkInvokers(invokers, invocation); // 負責均衡選擇一個生產者Invoker invoker = select(loadbalance, invocation, invokers, null); // 消費服務發起遠端呼叫 return invoker.invoke(invocation); } catch (Throwable e) { logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: " + e.getMessage() + ", ", e); // 如果服務消費失敗則記錄失敗請求 addFailed(loadbalance, invocation, invokers, invoker); // 返回空結果 return new RpcResult(); } } @Override public void destroy() { super.destroy(); if (failTimer != null) { failTimer.stop(); } } /** * RetryTimerTask */ private class RetryTimerTask implements TimerTask { private final Invocation invocation; private final LoadBalance loadbalance; private final List<Invoker<T>> invokers; private final int retries; private final long tick; private Invoker<T> lastInvoker; private int retryTimes = 0; RetryTimerTask(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, Invoker<T> lastInvoker, int retries, long tick) { this.loadbalance = loadbalance; this.invocation = invocation; this.invokers = invokers; this.retries = retries; this.tick = tick; this.lastInvoker = lastInvoker; } @Override public void run(Timeout timeout) { try { // 負載均衡選擇一個生產者Invoker Invoker<T> retryInvoker = select(loadbalance, invocation, invokers, Collections.singletonList(lastInvoker)); lastInvoker = retryInvoker; // 服務消費發起遠端呼叫 retryInvoker.invoke(invocation); } catch (Throwable e) { logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e); // 超出最大重試次數記錄日誌不丟擲異常 if ((++retryTimes) >= retries) { logger.error("Failed retry times exceed threshold (" + retries + "), We have to abandon, invocation->" + invocation); } else { // 未超出最大重試次數重新放入定時器 rePut(timeout); } } } private void rePut(Timeout timeout) { if (timeout == null) { return; } Timer timer = timeout.timer(); if (timer.isStop() || timeout.isCancelled()) { return; } timer.newTimeout(timeout.task(), tick, TimeUnit.SECONDS); } } }
5 Forking
public class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T> { private final ExecutorService executor = Executors.newCachedThreadPool(new NamedInternalThreadFactory("forking-cluster-timer", true)); public ForkingClusterInvoker(Directory<T> directory) { super(directory); } @Override public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { try { checkInvokers(invokers, invocation); final List<Invoker<T>> selected; // 獲取配置引數 final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS); final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); // 獲取並行執行的Invoker列表 if (forks <= 0 || forks >= invokers.size()) { selected = invokers; } else { selected = new ArrayList<>(); for (int i = 0; i < forks; i++) { // 選擇生產者 Invoker<T> invoker = select(loadbalance, invocation, invokers, selected); // 防止重複增加Invoker if (!selected.contains(invoker)) { selected.add(invoker); } } } RpcContext.getContext().setInvokers((List) selected); final AtomicInteger count = new AtomicInteger(); final BlockingQueue<Object> ref = new LinkedBlockingQueue<>(); for (final Invoker<T> invoker : selected) { // 線上程池中併發執行 executor.execute(new Runnable() { @Override public void run() { try { // 執行消費邏輯 Result result = invoker.invoke(invocation); // 儲存消費結果 ref.offer(result); } catch (Throwable e) { // 如果異常次數大於等於forks引數值說明全部呼叫失敗,則把異常放入佇列 int value = count.incrementAndGet(); if (value >= selected.size()) { ref.offer(e); } } } }); } try { // 從佇列獲取結果 Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS); // 如果異常型別表示全部呼叫失敗則丟擲異常 if (ret instanceof Throwable) { Throwable e = (Throwable) ret; throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); } return (Result) ret; } catch (InterruptedException e) { throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e); } } finally { RpcContext.getContext().clearAttachments(); } } }
6 Broadcast
public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> { private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class); public BroadcastClusterInvoker(Directory<T> directory) { super(directory); } @Override public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { checkInvokers(invokers, invocation); RpcContext.getContext().setInvokers((List) invokers); RpcException exception = null; Result result = null; // 遍歷呼叫所有生產者節點 for (Invoker<T> invoker : invokers) { try { // 執行消費邏輯 result = invoker.invoke(invocation); } catch (RpcException e) { exception = e; logger.warn(e.getMessage(), e); } catch (Throwable e) { exception = new RpcException(e.getMessage(), e); logger.warn(e.getMessage(), e); } } // 任何一個出現異常則丟擲異常 if (exception != null) { throw exception; } return result; } }
來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/69978258/viewspace-3001233/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Dubbo原始碼分析-叢集容錯之Router原始碼
- Dubbo原始碼分析(八)叢集容錯機制原始碼
- 短影片app開發的付費熱門是什麼,短影片依舊內容為王APP
- 移動短影片直播開發,短影片原始碼搭建社交平臺原生APP原始碼APP
- 短影片app開發,短影片系統發展的收益方式是什麼?APP
- 短影片app原始碼,日常開發之RecycleView滑動APP原始碼View
- 短影片APP系統原始碼,定製開發功能APP原始碼
- Dubbo剖析-叢集容錯
- Dubbo示例——叢集容錯
- 短影片APP無加密原始碼,支援二次開發APP加密原始碼
- 開發短影片APP需要什麼功能APP
- 短影片的“火”,離不開短影片app原始碼的這三個核心功能APP原始碼
- 短影片app原始碼,自動捲軸擋住 div內容APP原始碼
- Dubbo原始碼分析(四)Dubbo呼叫鏈-消費端(叢集容錯機制)原始碼
- dubbo原始碼解析-叢集容錯架構設計原始碼架構
- 短影片直播APP原生開發直播系統無加密搭建定製短影片APP加密
- 短影片程式,仿抖音短影片熱門頁面開發
- 小影片app開發後,短影片軟體搭建部署教程APP
- 短影片直播APP原生開發提供演示APP定製開發多終端支援APP
- 短影片社交平臺開發,短影片直播帶貨,成品原始碼二次開發原始碼
- TOKTOK短影片系統DAPP開發丨去中心化短影片丨技術分析APP中心化
- 短影片直播APP系統:成品原始碼開發快速搭建部署平臺APP原始碼
- 短影片程式原始碼,如何實現短影片的熱門頁面原始碼
- 快手內容分發工具,一鍵分發短影片內容
- 短影片直播APP成品開發直播系統仿抖音APP無加密APP加密
- 免費分享短影片app開發的收益分成相關規則APP
- 短影片+直播 原生APP成品全套原始碼支援定製和二次開發APP原始碼
- 個人來開發短影片程式原始碼,先來看一下開發思路原始碼
- 奇樂短影片開發技術丨奇樂直播短影片系統程式設計開發詳情程式設計
- 短影片原始碼的開發搭建,哪些功能是重點?原始碼
- 秘樂短影片原始碼系統開發搭建原始碼
- 短影片程式原始碼,怎麼進行短影片稽核機制的架構原始碼架構
- hdfs叢集的擴容和縮容
- 短影片app開發,可以借鑑的幾個登入介面設計APP
- Java程式設計解密-Dubbo負載均衡與叢集容錯機制Java程式設計解密負載
- 短影片平臺開發,首先要搭建短影片框架框架
- 短影片app開發中存在的哪些要點是必須明確的?APP
- 短影片app原始碼,自定義快速捲軸FastScrollBarAPP原始碼AST