sentinel-adapter模塊镶殷,見(jiàn)名知意,這個(gè)模塊的職能是適配来惧,目前適配主流的框架有dubbo,grpc和web.
由于最了解的是dubbo,目前就先以dubbo為例子進(jìn)行講解耙蔑。
由于dubbo框架的設(shè)計(jì)思想,具體不展開(kāi)了疟赊,有興趣可以去了解下郊供,我后續(xù)也會(huì)寫(xiě)dubbo源碼分析。
如下面三個(gè)配置的filter,在dubbo請(qǐng)求時(shí)會(huì)執(zhí)行到:SentinelDubboProviderFilter近哟,SentinelDubboConsumerFilter和DubboAppContextFilter 的invoke方法
sentinel.dubbo.provider.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter
sentinel.dubbo.consumer.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboConsumerFilter
dubbo.application.context.name.filter=com.alibaba.csp.sentinel.adapter.dubbo.DubboAppContextFilter
干貨
源碼分析SentinelDubboProviderFilter? dubbo調(diào)用方:
public Resultinvoke(Invoker invoker, Invocation invocation)throws RpcException {
? ? // Get origin caller.
//獲取客戶(hù)端 消費(fèi)方是否包含dubboApplication數(shù)據(jù)驮审,標(biāo)明調(diào)用方身份
? ? String application = DubboUtils.getApplication(invocation, "");
? ? Entry interfaceEntry =null;
? ? Entry methodEntry =null;
? ? try {
? ? ? ? String resourceName = getResourceName(invoker, invocation);
? ? ? ? String interfaceName = invoker.getInterface().getName();
? ? ? ?//將數(shù)據(jù)加載到容器中保存
? ? ? ? ContextUtil.enter(resourceName, application);
? ? ? ? //設(shè)置資源保護(hù),接口級(jí)別接口保護(hù)
? ? ? ? interfaceEntry = SphU.entry(interfaceName, EntryType.IN);
? ? ? ? //設(shè)置資源保護(hù),方法級(jí)別接口保護(hù)
? ? ? ? methodEntry = SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
? ? ? ? //調(diào)用
? ? ? ? Result result = invoker.invoke(invocation);
? ? ? ? if (result.hasException()) {
//統(tǒng)計(jì)異常比例
Tracer.trace(result.getException());
? ? ? ? }
return result;
? ? }catch (BlockException e) {
//當(dāng)出現(xiàn)拒絕后疯淫,進(jìn)入fallback地来,可定制化fallback,默認(rèn)DefaultDubboFallback熙掺,拋出SentinelRpcException異常
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
? ? }catch (RpcException e) {
//統(tǒng)計(jì)異常比例
Tracer.trace(e);
? ? ? ? throw e;
? ? }finally {
if (methodEntry !=null) {
//清理方法級(jí)別資源
methodEntry.exit(1, invocation.getArguments());
? ? ? ? }
if (interfaceEntry !=null) {
//清理接口級(jí)別資源
interfaceEntry.exit();
? ? ? ? }
//清理
ContextUtil.exit();
? ? }
}
源碼分析DubboAppContextFilter? dubbo被調(diào)用方:
@Override
public Resultinvoke(Invoker invoker, Invocation invocation)throws RpcException {
String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
? ? if (application !=null) {
RpcContext.getContext().setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, application);
? ? }
return invoker.invoke(invocation);
}
寫(xiě)入自定義的dubboApplication命名
源碼分析SentinelDubboConsumerFilter? dubbo被調(diào)用方:
@Override
public Resultinvoke(Invoker invoker, Invocation invocation)throws RpcException {
Entry interfaceEntry =null;
? ? Entry methodEntry =null;
? ? try {
//獲取調(diào)用方接口名稱(chēng)
String resourceName = getResourceName(invoker, invocation);
? ? ? ? ContextUtil.enter(resourceName);
//設(shè)置資源保護(hù)未斑,接口級(jí)別接口保護(hù)
? ? ? ? interfaceEntry = SphU.entry(invoker.getInterface().getName(), EntryType.OUT);
//設(shè)置資源保護(hù),方法級(jí)別接口保護(hù)
? ? ? ? methodEntry = SphU.entry(resourceName, EntryType.OUT);
? ? ? ? Result result = invoker.invoke(invocation);
? ? ? ? if (result.hasException()) {
//統(tǒng)計(jì)異常比例
? ? ? ? ? ? Tracer.trace(result.getException());
? ? ? ? }
return result;
? ? }catch (BlockException e) {
//fallback
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);
? ? }catch (RpcException e) {
//統(tǒng)計(jì)異常比例
Tracer.trace(e);
? ? ? ? throw e;
? ? }finally {
if (methodEntry !=null) {
//資源釋放
methodEntry.exit();
? ? ? ? }
if (interfaceEntry !=null) {
//資源釋放
interfaceEntry.exit();
? ? ? ? }
//資源釋放
ContextUtil.exit();
? ? }
}