sentinel結(jié)合dubbo進(jìn)行熱點(diǎn)參數(shù)限流
(1)dubbo中接入sentinel
方法:
(1)只需要在pom中假如三行配置即可接入sentinel
(2)進(jìn)行熱點(diǎn)參數(shù)限流時(shí)候秦爆,需要接入熱點(diǎn)限流模塊尔苦。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>1.6.2</version>
</dependency>
**普通的熱點(diǎn)參數(shù)限流只需要在entry中傳入相應(yīng)的參數(shù)就可以,但是由于我們需要對(duì)dubbo的服務(wù)根據(jù)企業(yè)id來(lái)進(jìn)行限流,dubbo在接入sentinel的時(shí)候?qū)ntry封裝進(jìn)了adapter里面,故此:
- 需要改寫(xiě)官方提供的adaper,將企業(yè)的id傳入到entry中
- 通過(guò)dubbo的rpccontext拿到從consumer傳入的企業(yè)id 和用戶id **
接入原理:
Dubbo
通過(guò)dubbo的攔截器將服務(wù)實(shí)例進(jìn)行攔截,同時(shí)接入sentinel core對(duì)服務(wù)實(shí)例的調(diào)用進(jìn)行統(tǒng)計(jì)。
(1)SPI擴(kuò)展原理
ExtensionLoader:1. 通過(guò)接口類(lèi)名和key值獲取一個(gè)實(shí)現(xiàn) 2. 利用IOC依賴注入功能(實(shí)現(xiàn)一個(gè)代理類(lèi)) 3. 采用裝飾器模式進(jìn)行功能增強(qiáng)哄酝,自動(dòng)實(shí)現(xiàn)包裝
- ExtensionLoader 實(shí)現(xiàn)初始化
- 掃描配置文件,根據(jù)配置文件中的類(lèi)名進(jìn)行類(lèi)加載
- 擴(kuò)展適配器
(2)Filter鏈原理
-
構(gòu)造Filter鏈
Dubbo的Filter實(shí)現(xiàn)入口是 在ProtocolFilterWrapper祷膳,因?yàn)镻rotocolFilterWrapper是Protocol的包裝類(lèi)陶衅,所以會(huì)在加載的Extension的時(shí)候被自動(dòng)包裝進(jìn)來(lái),該封裝器實(shí)現(xiàn)了Protocol接口直晨,并提供了一個(gè)參數(shù)類(lèi)型為Protocol的構(gòu)造方法搀军。Dubbo依據(jù)這個(gè)構(gòu)造方法識(shí)別出封裝器,并將該封裝器作為其他Protocol接口實(shí)現(xiàn)的代理勇皇。
Sentinel
(1) 基本原理
限流入口是entry(),在創(chuàng)建entry()的時(shí)候一些列插槽會(huì)被創(chuàng)建罩句。
(1)插槽組成:StatisticSlot,systemslot,autheityslot,NodeSelectorSlot等
? NodeSelectorSlot負(fù)責(zé)收集資源的路徑敛摘,并將路徑以樹(shù)狀結(jié)構(gòu)存儲(chǔ)起來(lái)门烂。
(2)本質(zhì)上是基于信號(hào)量對(duì)資源進(jìn)行監(jiān)控(類(lèi)似于AQS)
(3)每一個(gè)插槽都有一個(gè)入口entry(),還有一個(gè)出口(也是進(jìn)入下一個(gè)插槽的起點(diǎn))fullentry(),在經(jīng)過(guò)NodeSelectorSlot收集資源路徑,ClusterBuilderSlot記錄監(jiān)控信息之后屯远,后面每過(guò)一次entry(即經(jīng)歷過(guò)一個(gè)插槽就會(huì)進(jìn)行一次checkrule蔓姚,判斷是否符合規(guī)定,如果不符合則block,符合則pass)【總的來(lái)說(shuō)慨丐,每經(jīng)過(guò)一次slot的entry就是一次檢查坡脐,檢查當(dāng)前對(duì)服務(wù)的訪問(wèn)是否符合規(guī)則】
Sentinel接入Dubbo(同時(shí)實(shí)現(xiàn)企業(yè)id的流控)
(1)利用dubbo的filter將provider的服務(wù)進(jìn)行攔截
(2)通過(guò)rpcontext獲取consumer傳遞過(guò)來(lái)的企業(yè)id和用戶id
(3)將企業(yè)id、用戶id傳入entry房揭,entry經(jīng)過(guò)StatisticSlot時(shí)候會(huì)對(duì)其進(jìn)行統(tǒng)計(jì)备闲,判斷是否是熱點(diǎn)數(shù)據(jù),若是則觸發(fā)流控規(guī)則捅暴。
(4)在實(shí)現(xiàn)步驟(3)的時(shí)候需要接入
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>1.6.2</version>
</dependency>
具體實(shí)現(xiàn)代碼:
@Activate(group = "provider")
public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter {
public SentinelDubboProviderFilter() {
RecordLog.info("Sentinel Dubbo provider filter initialized");
}
private static final String ENTERPRISE_ID = "enterpriseId";
private static final String USER_ID = "userId";
private static final String DEFAULT_ENTERPRISE_ID = "0";
private static final String DEFAULT_USER_ID = "0";
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// Get origin caller.
String application = DubboUtils.getApplication(invocation, "");
Entry interfaceEntry = null;
Entry methodEntry = null;
String enterpriseId = null;
String userId = null;
try {
enterpriseId = RpcContext.getContext().getAttachment(ENTERPRISE_ID);
userId = RpcContext.getContext().getAttachment(USER_ID);
if (userId == null){
userId = DEFAULT_USER_ID;
}
if (enterpriseId == null){
enterpriseId = DEFAULT_ENTERPRISE_ID;
}
String resourceName = getResourceName(invoker, invocation);
String interfaceName = invoker.getInterface().getName();
ContextUtil.enter(resourceName, application);
interfaceEntry = SphU.entry(interfaceName, EntryType.IN,1,enterpriseId);
methodEntry = SphU.entry(resourceName, EntryType.IN, 1, enterpriseId,userId);
Result result = invoker.invoke(invocation);
if (result.hasException()) {
Tracer.trace(result.getException());
}
return result;
} catch (BlockException e) {
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
} catch (RpcException e) {
Tracer.trace(e);
throw e;
} finally {
if (methodEntry != null) {
methodEntry.exit(1,enterpriseId,userId);
}
if (interfaceEntry != null) {
interfaceEntry.exit(1,enterpriseId);
}
ContextUtil.exit();
}
}
}
總結(jié):只需要將dubbo與sentinel的適配器進(jìn)行適配恬砂,將rpccontext中的企業(yè)id、用戶id傳入entry即可通過(guò)控制臺(tái)對(duì)接口蓬痒、方法進(jìn)行流控泻骤。