熔斷策略(Circuit-breaker)
如果調(diào)用某個(gè)目標(biāo)服務(wù)出現(xiàn)過(guò)多超時(shí)、異常等情況,可以采取一定時(shí)間內(nèi)熔斷該服務(wù)的調(diào)用,熔斷期間的請(qǐng)求將不再繼續(xù)調(diào)用目標(biāo)服務(wù),而是直接返回,節(jié)約資源,提高服務(wù)的穩(wěn)定性,熔斷周期結(jié)束后如果目標(biāo)服務(wù)情況好轉(zhuǎn)則恢復(fù)調(diào)用。
注意:為了服務(wù)的穩(wěn)定性,在執(zhí)行需要多次 Retry(重試策略)的情況下,最好組合熔斷策略,預(yù)防可能存在的風(fēng)險(xiǎn)。
熔斷狀態(tài)

- 打開(kāi)(Open)
熔斷器打開(kāi)狀態(tài),此時(shí)對(duì)目標(biāo)服務(wù)的調(diào)用都直接返回錯(cuò)誤,熔斷周期內(nèi)不會(huì)走網(wǎng)絡(luò)請(qǐng)求,當(dāng)熔斷周期結(jié)束時(shí)進(jìn)入半開(kāi)狀態(tài);
- 關(guān)閉(Closed)
關(guān)閉狀態(tài)下正常發(fā)生網(wǎng)絡(luò)請(qǐng)求,但會(huì)記錄符合熔斷條件的連續(xù)執(zhí)行次數(shù),如果錯(cuò)誤數(shù)量達(dá)到設(shè)定的閾值(如果在沒(méi)有達(dá)到閾值之前恢復(fù)正常,之前的累積次數(shù)將會(huì)歸零),熔斷狀態(tài)進(jìn)入到打開(kāi)狀態(tài);
- 半開(kāi)(Half-Open)
半開(kāi)狀態(tài)下允許定量的服務(wù)請(qǐng)求,如果調(diào)用都成功則認(rèn)為恢復(fù)了,關(guān)閉熔斷器,否則認(rèn)為還沒(méi)好,又回到熔斷器打開(kāi)狀態(tài);
熔斷使用說(shuō)明
// 在連續(xù)3次異常后熔斷,并保持1分鐘的熔斷狀態(tài),調(diào)用者將收到斷路保護(hù)的異常信息
Policy
.Handle<SomeExceptionType>()
.CircuitBreaker(3, TimeSpan.FromMinutes(1));
熔斷代碼測(cè)試
private static int times = 0;
public static void TestPolicy()
{
var circuitBreakerPolicy = Policy
.Handle<Exception>()
.CircuitBreaker(
exceptionsAllowedBeforeBreaking: 4, // 連續(xù)4次異常
durationOfBreak: TimeSpan.FromMinutes(1), // 斷開(kāi)1分鐘
onBreak: (exception, breakDelay) => // 斷路器打開(kāi)時(shí)
Console.WriteLine($"熔斷: {breakDelay.TotalMilliseconds } ms, 異常: " + exception.Message),
onReset: () => // 熔斷器關(guān)閉時(shí)
Console.WriteLine("熔斷器關(guān)閉了"),
onHalfOpen: () => // 熔斷時(shí)間結(jié)束時(shí),從斷開(kāi)狀態(tài)進(jìn)入半開(kāi)狀態(tài)
Console.WriteLine("熔斷時(shí)間到,進(jìn)入半開(kāi)狀態(tài)")
);
for (int i = 0; i < 12; i++) // 模擬多次調(diào)用,觸發(fā)熔斷
{
try
{
var result = circuitBreakerPolicy.Execute(Test);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("try-catch:" + ex.Message);
}
Thread.Sleep(500);
}
}
private static string Test()
{
times++;
if (times % 5 != 0) // 模仿某些錯(cuò)誤情況下拋異常
{
throw new Exception("exception message");
}
return "success";
}

熔斷高級(jí)配置
根據(jù)時(shí)間段內(nèi)總請(qǐng)求數(shù)中的異常比例觸發(fā)熔斷:
var advancedCircuitBreakerPolicy = Policy
.Handle<Exception>()
.AdvancedCircuitBreaker(
failureThreshold: 0.5, // 至少50%有異常則熔斷
samplingDuration: TimeSpan.FromSeconds(10), // 10秒內(nèi)
minimumThroughput: 8, // 最少共有多少次調(diào)用
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (exception, breakDelay) => // 斷路器打開(kāi)時(shí)
Console.WriteLine($"熔斷: {breakDelay.TotalMilliseconds } ms, 異常: " + exception.Message),
onReset: () => // 熔斷器關(guān)閉時(shí)
Console.WriteLine("熔斷器關(guān)閉了"),
onHalfOpen: () => // 熔斷時(shí)間結(jié)束時(shí),從斷開(kāi)狀態(tài)進(jìn)入半開(kāi)狀態(tài)
Console.WriteLine("熔斷時(shí)間到,進(jìn)入半開(kāi)狀態(tài)")
);