總結/朱季謙
先前在測試環境遇到過一個問題,即Dubbo廣播機制,在對各個提供者節點進行廣播操作過程中,存在最前面的兩個節點出現異常的情況,但後邊的其他節點仍能正常同步的情況。我以前就知道Dubbo的Broadcast機制,先前概念裏總以爲這是一個當廣播到某個節點若出現異常時,就會直接停止廣播操作,但在Dubbo的廣播機制裏,卻不是這樣。它會先遍歷所有的Invokers調用,若過程出現異常時,只會先將異常先類似日誌一樣記錄下來,等到Invokers遍歷完成後,最後纔會將最後保留的異常進行拋出。
這就能解釋了,爲啥存在兩個節點出現異常的情況下,後面的節點仍能正常被廣播通知到。
接下來,我們簡單看下Dubbo的Broadcast機制源碼,這裏的代碼很好看懂——
接下來,我們簡單看下Dubbo的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
@SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
//通過CollectionUtils.isEmpty(invokers)檢查invokers集合是否爲空,若爲空,拋出異常
checkInvokers(invokers, invocation);
//類似上下文操作保存invokers
RpcContext.getContext().setInvokers((List) invokers);
RpcException exception = null;
Result result = null;
//遍歷invoker遠程調用接口服務
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);
}
}
//等invokers遍歷完成後,若存在異常,再對異常進行拋出
if (exception != null) {
throw exception;
}
return result;
}
}
這裏的遍歷操作是單線程進行的,存在一個問題,若invokers數量很龐大,那麼,將會出現廣播耗時的情況,我覺得這裏若invokers數據量過大時,可以通過選擇有返回值的線程池併發執行。