若您需要對特定的方法或者代碼塊進行流控,可以使用定義資源來實現。AHAS提供了5種定義資源的方法,定義資源后,在AHAS控制臺為應用配置相應規則即可生效。
背景信息
AHAS是圍繞著資源來工作的。編碼的時,只需關注如何定義資源,即哪些方法或代碼塊可能需要保護,而無需關注這個資源要如何保護。可通過定義資源來實現對代碼塊的流控,定義資源方式如下:
- 注解方式定義資源
- 拋出異常的方式定義資源
- 返回布爾值方式定義資源
- 異步調用支持
- 主流框架的默認適配
方式一:注解方式定義資源
通過@SentinelResource
注解定義資源并配置blockHandler
和fallback
函數來進行限流之后的處理。
示例:
// 原本的業務方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
// blockHandler 函數,原方法調用被限流/降級/系統保護的時候調用
public User blockHandlerForGetUser(String id, BlockException ex) {
return new User("admin");
}
blockHandler
函數會在方法觸發限流、降級或系統保護規則的時候調用,而fallback
函數僅會在原方法被降級時作為Fallback方法,其它時候不會被調用。更多信息請參見Sentinel 注解支持文檔。
方式二:拋出異常的方式定義資源
使用拋出異常的方式定義資源后,當資源發生了限流之后會拋出BlockException
。您可以按需捕捉異常,并進行限流之后的邏輯處理。示例代碼如下:
Entry entry = null;
// 務必保證finally會被執行
try {
// 資源名可使用任意有業務語義的字符串
entry = SphU.entry("自定義資源名");
// 被保護的業務邏輯
// do something...
} catch (BlockException ex) {
// 資源訪問阻止,被限流或被降級
// 進行相應的處理操作
} finally {
if (entry != null) {
entry.exit();
}
}
SphU.entry(xxx)
需要與entry.exit()
方法需匹配調用,否則會導致調用鏈記錄異常,拋出ErrorEntryFreeException
異常。方式三:返回布爾值方式定義資源
使用返回布爾值方式定義資源方式后,當資源發生了限流之后會返回false
。可以根據返回值,進行限流之后的邏輯處理。示例代碼如下:
// 資源名可使用任意有業務語義的字符串
if (SphO.entry("自定義資源名")) {
// 務必保證finally會被執行
try {
/**
* 被保護的業務邏輯
*/
} finally {
SphO.exit();
}
} else {
// 資源訪問阻止,被限流或被降級
// 進行相應的處理操作
}
方式四:異步調用支持
AHAS支持異步調用鏈路的統計。在異步調用中,需要通過SphU.asyncEntry(xxx)
方法定義資源,并通常需要在異步的回調函數中調用exit
方法。示例如下:
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// 異步調用
doAsync(userId, result -> {
try {
// 在此處處理異步調用的結果
} finally {
// 在回調結束后 exit
entry.exit();
}
});
} catch (BlockException ex) {
// Request blocked
// Handle the exception (e.g. retry or fallback)
}
SphU.asyncEntry(xxx)
不會影響當前調用線程的Context,因此以下兩個entry在調用鏈上是平級關系(處于同一層),而不是嵌套關系:
// 調用鏈類似于:
// -parent
// ---asyncResource
// ---syncResource
asyncEntry = SphU.asyncEntry(asyncResource);
entry = SphU.entry(normalResource);
若在異步回調中需要嵌套其它的資源調用(無論是entry
還是asyncEntry
),只需要借助Sentinel提供的上下文切換功能,在對應的地方通過ContextUtil.runOnContext(context, f)
進行Context變換,將對應資源調用處的Context切換為生成的異步Context,即可維持正確的調用鏈路關系。示例如下:
public void handleResult(String result) {
Entry entry = null;
try {
entry = SphU.entry("handleResultForAsync");
// Handle your result here
} catch (BlockException ex) {
// Blocked for the result handler
} finally {
if (entry != null) {
entry.exit();
}
}
}
public void someAsync() {
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// Asynchronous invocation
doAsync(userId, result -> {
// 在異步回調中進行上下文變換,通過 AsyncEntry 的 getAsyncContext 方法獲取異步 Context
ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
try {
// 此處嵌套正常的資源調用
handleResult(result);
} finally {
entry.exit();
}
});
});
} catch (BlockException ex) {
// Request blocked
// Handle the exception (e.g. retry or fallback)
}
}
此時的調用鏈如下:
-parent
---asyncInvocation
-----handleResultForAsync
普通資源與異步資源之間嵌套示例請參見AsyncEntryDemo.java。
方式五:主流框架的默認適配
為了減少開發的復雜程度,AHAS對主流框架進行了適配,詳情請參見支持組件列表。使用時只需要引入任意一個對應的SDK依賴,它們框架的方法和服務都會自動被定義為資源,無需修改現有代碼。