一、概述
在 Sentinel 裡面,所有的資源都對應一個資源名稱(
resourceName
),每次資源調用都會建立一個
Entry
對象。Entry 可以通過對主流架構的适配自動建立,也可以通過注解的方式或調用
SphU
API 顯式建立。Entry 建立的時候,同時也會建立一系列功能插槽(slot chain),這些插槽有不同的職責,例如:
-
負責收集資源的路徑,并将這些資源的調用路徑,以樹狀結構存儲起來,用于根據調用路徑來限流降級;NodeSelectorSlot
-
則用于存儲資源的統計資訊以及調用者資訊,例如該資源的 RT, QPS, thread count 等等,這些資訊将用作為多元度限流,降級的依據;ClusterBuilderSlot
-
則用于記錄用于記錄塊異常,為故障排除提供具體的日志LogSlot
-
則用于記錄、統計不同緯度的 runtime 名額監控資訊;StatisticSlot
-
則用于根據預設的限流規則以及前面 slot 統計的狀态,來進行流量控制;FlowSlot
-
則根據配置的黑白名單和調用來源資訊,來做黑白名單控制;AuthoritySlot
-
則通過統計資訊以及預設的規則,來做熔斷降級;DegradeSlot
-
則通過系統的狀态,例如 load1 等,來控制總的入口流量;SystemSlot
下面是關系結構圖

二、AuthoritySlot分析
1.AuthoritySlot介紹
官方文檔是這樣描述AuthoritySlot的:
很多時候,我們需要根據調用來源來判斷該次請求是否允許放行,這時候可以使用 Sentinel 的來源通路控制(黑白名單控制)的功能。來源通路控制根據資源的請求來源(
origin
)限制資源是否通過,若配置白名單則隻有請求來源位于白名單内時才可通過;若配置黑名單則請求來源位于黑名單時不通過,其餘的請求通過。
調用方資訊通過方法中的
ContextUtil.enter(resourceName, origin)
參數傳入。
origin
規則配置
來源通路控制規則()非常簡單,主要有以下配置項:
AuthorityRule
:資源名,即限流規則的作用對象。
resource
:對應的黑名單/白名單,不同 origin 用
limitApp
分隔,如
,
。
appA,appB
:限制模式,
strategy
為白名單模式,
AUTHORITY_WHITE
為黑名單模式,預設為白名單模式。
AUTHORITY_BLACK
示例
比如我們希望控制對資源的通路設定白名單,隻有來源為
test
和
appA
的請求才可通過,則可以配置如下白名單規則:
appB
AuthorityRule rule = new AuthorityRule(); rule.setResource("test"); rule.setStrategy(RuleConstant.AUTHORITY_WHITE); rule.setLimitApp("appA,appB"); AuthorityRuleManager.loadRules(Collections.singletonList(rule));
2.源碼解讀
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args)throws Throwable {
checkBlackWhiteAuthority(resourceWrapper, context);
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
1.在
entry
階段,執行了一個校驗方法.
void checkBlackWhiteAuthority(ResourceWrapper resource, Context context) throws AuthorityException {
Map<String, Set<AuthorityRule>> authorityRules = AuthorityRuleManager.getAuthorityRules();
if (authorityRules == null) {
return;
}
Set<AuthorityRule> rules = authorityRules.get(resource.getName());//根據resource擷取指定rules
if (rules == null) {
return;
}
for (AuthorityRule rule : rules) {
if (!AuthorityRuleChecker.passCheck(rule, context)) {
throw new AuthorityException(context.getOrigin(), rule);
}
}
}
2.如果
AuthorityRuleManager
裡面的
authorityRules
為空,則跳過黑白名單的校驗,否則根據
resource
擷取本資源的
rules
(Set),循環這個
rules
,在循環裡面調用校驗方法(
AuthorityRuleChecker.passCheck(rule, context)
)
static boolean passCheck(AuthorityRule rule, Context context) {
String requester = context.getOrigin();
// Empty origin or empty limitApp will pass.
if (StringUtil.isEmpty(requester) || StringUtil.isEmpty(rule.getLimitApp())) {
return true;
}
// Do exact match with origin name.
int pos = rule.getLimitApp().indexOf(requester);//包含關系驗證
boolean contain = pos > -1;
if (contain) {//equals驗證
boolean exactlyMatch = false;
String[] appArray = rule.getLimitApp().split(",");
for (String app : appArray) {
if (requester.equals(app)) {
exactlyMatch = true;
break;
}
}
contain = exactlyMatch;
}
int strategy = rule.getStrategy();
if (strategy == RuleConstant.AUTHORITY_BLACK && contain) {//黑名單驗證
return false;
}
if (strategy == RuleConstant.AUTHORITY_WHITE && !contain) {//白名單驗證
return false;
}
return true;
}
3.這個核心的校驗方法内,首先會進行基礎判斷,
Empty origin or empty limitApp will pass.
。然後判斷
resource
中的
rule
,是否已經注冊到了
rule
中,如果注冊了并且能夠對應的上,
exactlyMatch
參數會被置為
true
4.拿到了對應結果
contain(exactlyMatch)
後,開始進行
strategy
的判斷。如果是黑名單,則傳回
contain
;如果是白名單驗證則傳回
!contain
作為
sentinel
的黑白名單控制,實作的功能也比較簡單,隻需要我們需要定義控制規則就行了。
多個相同的
resource
(name),對應着不同的
context
(name),那麼我們就可以快速統計出某個資源的總統計資訊。對應着多個(歸屬于同一個resource的)
DefaultNode
對應同一個
ClusterNode
三、SystemSlot分析
1.SystemSlot介紹
官方文檔是這樣描述SystemSlot的:一句話概括就是系統級限流的控制器
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {
SystemRuleManager.checkSystem(resourceWrapper);//整個系統限流的切入點
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
1.在下一個slot的開始前,直接調用了com.alibaba.csp.sentinel.slots.system.SystemRuleManager的checkSystem方法。
public static void checkSystem(ResourceWrapper resourceWrapper) throws BlockException {
if (resourceWrapper == null) {
return;
}
// 是否打開校驗開關
if (!checkSystemStatus.get()) {
return;
}
// 是否為入口流量
if (resourceWrapper.getEntryType() != EntryType.IN) {
return;
}
//qps 的對比
double currentQps = Constants.ENTRY_NODE == null ? 0.0 : Constants.ENTRY_NODE.successQps();
if (currentQps > qps) {
throw new SystemBlockException(resourceWrapper.getName(), "qps");
}
//線程數的對比
int currentThread = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.curThreadNum();
if (currentThread > maxThread) {
throw new SystemBlockException(resourceWrapper.getName(), "thread");
}
//獲得總成功計數的對比
double rt = Constants.ENTRY_NODE == null ? 0 : Constants.ENTRY_NODE.avgRt();
if (rt > maxRt) {
throw new SystemBlockException(resourceWrapper.getName(), "rt");
}
// 按照BBR算法
if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) {
if (!checkBbr(currentThread)) {
throw new SystemBlockException(resourceWrapper.getName(), "load");
}
}
// cpu狀态
if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) {
throw new SystemBlockException(resourceWrapper.getName(), "cpu");
}
}
2.進入到校驗方案,慣例 的校驗了一次resource的非空。
3.開始校驗是否打開系統限流開關,流量類型(全局限流隻校驗入口流量)。
4.進行qps,線程數的校驗,當超過任何系統規則的門檻值時throws BlockException。
5.進行成功通路數,RT,CPU狀态的校驗,當超過任何系統規則的門檻值時throws BlockException。
四、小結
本期我們講述了Slot的子類
LogSlot
StatisticSlot
的基本實作原理。
現在建立我們的知識樹
執行個體化DefaultNode和ClusterNode,建立結構樹
建立上下文時,首先會在
NodeSelectorSlot
中判斷是否有
DefaultNode
如果沒有則新增一個基于
resource
的
DefaultNode
,然後執行下一個
slot
下一個
slot
是
ClusterBuilderSlot
,
ClusterBuilderSlot
會判斷是否有對應的
ClusterNode
,如果沒有則新增一個基于resource的
ClusterNode
并繼續下一個流程(
slot
)。
總結來說,這個兩個
slot
奠定了一個基于
resource
進行全局控制的基調。
進行資訊收集
LogSlot
在
DefaultNode
ClusterNode
初始化後,作為業務執行個體子產品的分界點,收集全局異常并處理。
StatisticSlot
作為全局統計的執行個體,依托于
ClusterNode
,将全局的
RT
,
QPS
thread
count
等等資訊存放在
clusterNodeMap
裡面。
進行權限校驗及系統級限流
在樹結構和資訊收集的slot建立完畢後,開始業務邏輯的實作,首先實作的就是AuthoritySlot的黑白名單能力,依托sentinel的resource的定義,我們很簡單就可以拿到關于resource的authorityRules,将對應的rules取出後,以此進行黑、白名單判斷,也可以了解為一種權限級别的限流措施。
SystemSlot則是全統計的全局限流,從調用點origins級别的配置中讀取了配置好的限流措施,在下一個slot實作前完成了所有的判斷,如qps,線程數,成功通路數,RT,CPU狀态。如果出現異常,則throws BlockException,交給之前的slot去處理相應邏輯。到這裡,一個基礎的限流架構已經基本實作。