啟用應(yīng)用程序來處理預(yù)期的,暫時的失敗時,它會嘗試連接到由透明的重試操作了以前失敗的期望,失敗的原因是瞬時的服務(wù)或網(wǎng)絡(luò)資源。這種模式可以提高應(yīng)用程序的穩(wěn)定性。
該通信的應(yīng)用程序與在云中運行的元素必須是可能發(fā)生在這樣的環(huán)境中的瞬時故障敏感。這些故障包括網(wǎng)絡(luò)連接的過程中出現(xiàn)時,一個服務(wù)是忙碌的瞬時損失的組件和服務(wù)中,服務(wù)的臨時不可用,或超時。
這些故障一般是自校正的,如果經(jīng)過一個合適的延遲被重復(fù)觸發(fā)一個故障的動作很可能是成功的。例如,數(shù)據(jù)庫服務(wù),它正在處理大量并發(fā)請求可以實現(xiàn)節(jié)流策略,暫時拒絕,直到它的工作量有所緩和任何進(jìn)一步的請求。試圖訪問該數(shù)據(jù)庫的應(yīng)用程序可能無法連接,但如果它經(jīng)過一個合適的延遲再次嘗試它可能會成功。
在云中,瞬時故障的情況并不少見和應(yīng)用應(yīng)該被設(shè)計為優(yōu)雅和透明地處理它們,減少的影響,這種故障可能對應(yīng)用程序正在執(zhí)行業(yè)務(wù)任務(wù)。
如果一個應(yīng)用程序檢測到故障時,它試圖將請求發(fā)送到遠(yuǎn)程服務(wù),它可以通過使用以下策略處理失?。?/p>
對于比較常見的短暫故障,重試期間,應(yīng)選擇以傳播從應(yīng)用程序中盡可能均勻的多個實例的請求。這可以減少繁忙的業(yè)務(wù)持續(xù)過載的可能性。如果一個應(yīng)用程序的多個實例不斷轟擊與重試請求的服務(wù),則可能需要該服務(wù)更長的時間來恢復(fù)。
如果請求仍然失敗,應(yīng)用程序可以等待進(jìn)一步的時期,再次嘗試。如果需要的話,這個過程可以重復(fù)而增加重試的延遲,直到請求的某一最大數(shù)目已經(jīng)嘗試都失敗了。延遲時間可以逐步增加,或可使用的定時策略,如指數(shù)回退,取決于故障的性質(zhì)和可能性,這將在這段時間內(nèi)被校正。
圖1示出了這種模式。如果嘗試后的預(yù)定數(shù)量的請求不成功,應(yīng)用程序應(yīng)將故障為異常,并相應(yīng)地處理它。
圖1 - 使用重試模式中調(diào)用托管服務(wù)的操作
應(yīng)用程序應(yīng)該換所有試圖訪問遠(yuǎn)程服務(wù),實現(xiàn)重試政策配套上面列出的策略之一的代碼。發(fā)送到不同的服務(wù)請求會受到不同的政策,有的供應(yīng)商提供封裝這種方法庫。這些庫通常執(zhí)行的政策是參數(shù)化的,而應(yīng)用程序開發(fā)人員可以指定,如重試次數(shù)和重試之間的時間項的值。
在檢測故障和重試失敗的操作都應(yīng)該記錄這些故障的詳細(xì)信息的應(yīng)用程序的代碼。這個信息可能是有用的運算符。如果一個服務(wù)被頻繁報道為不可用或忙,往往是因為該服務(wù)已耗盡其資源。則可以減少與這些故障發(fā)生時通過換算出該服務(wù)的頻率。例如,如果數(shù)據(jù)庫服務(wù)正在不斷超載,它可能是有利的分區(qū)數(shù)據(jù)庫和負(fù)載分散到多個服務(wù)器。
注意: 微軟 Azure 提供了重試模式的廣泛支持。該模式與實踐瞬態(tài)故障處理塊允許應(yīng)用程序通過一系列的重試策略來處理許多 Azure 服務(wù)瞬態(tài)故障。微軟實體框架版本6提供了用于重新嘗試數(shù)據(jù)庫操作。此外,許多在 Azure Service Bus 和 Azure 存儲的 API 透明地執(zhí)行重試邏輯。
在決定如何實現(xiàn)這個模式時,您應(yīng)考慮以下幾點:
使用這種模式:
本實施例說明的重試模式的實現(xiàn)。該 OperationWithBasicRetryAsync 方法,如下所示,通過 TransientOperationAsync 方法異步調(diào)用外部服務(wù)(該方法的細(xì)節(jié)將特定于服務(wù),并從樣本代碼被省略)。
private int retryCount = 3;
...
?
public async Task OperationWithBasicRetryAsync()
{
int currentRetry = 0;
?
for (; ;)
{
try
{
// Calling external service.
await TransientOperationAsync();
?
// Return or break.
break;
}
catch (Exception ex)
{
Trace.TraceError("Operation Exception");
?
currentRetry++;
?
// Check if the exception thrown was a transient exception
// based on the logic in the error detection strategy.
// Determine whether to retry the operation, as well as how
// long to wait, based on the retry strategy.
if (currentRetry > this.retryCount || !IsTransient(ex))
{
// If this is not a transient error
// or we should not retry re-throw the exception.
throw;
}
}
?
// Wait to retry the operation.
// Consider calculating an exponential delay here and
// using a strategy best suited for the operation and fault.
Await.Task.Delay();
}
}
?
// Async method that wraps a call to a remote service (details not shown).
private async Task TransientOperationAsync()
{
...
}
調(diào)用此方法的聲明被包裹在一個循環(huán)一個 try/ catch 塊中封裝。如果調(diào)用 TransientOperationAsync 方法成功,沒有拋出異常的 for 循環(huán)退出。如果 TransientOperationAsync 方法失敗,catch 塊檢查為失敗的原因,并且如果它被認(rèn)為是一個瞬時錯誤代碼等待一個短暫的延時,然后重試該操作。
在 for 循環(huán)還跟蹤該操作已經(jīng)嘗試的次數(shù),并且如果代碼失敗三次異常被認(rèn)為是更持久。如果該異常是不是暫時的,或者是長久的,catch 處理拋出的異常。此異常退出 for 循環(huán),應(yīng)捕獲調(diào)用該OperationWithBasicRetryAsync 方法的代碼。
該 IsTransient 方法,如下所示,檢查是否有特定的一組是相關(guān)的,其中所述代碼運行的環(huán)境的異常。一過異常的定義可以根據(jù)被訪問的資源,并在其上執(zhí)行的操作環(huán)境的不同而不同。
private bool IsTransient(Exception ex)
{
// Determine if the exception is transient.
// In some cases this may be as simple as checking the exception type, in other
// cases it may be necessary to inspect other properties of the exception.
if (ex is OperationTransientException)
return true;
?
var webException = ex as WebException;
if (webException != null)
{
// If the web exception contains one of the following status values
// it may be transient.
return new[] {WebExceptionStatus.ConnectionClosed,
WebExceptionStatus.Timeout,
WebExceptionStatus.RequestCanceled }.
Contains(webException.Status);
}
?
// Additional exception checking logic goes here.
return false;
}
更多建議: