標籤:blog http io ar os 使用 sp for strong
雲端運算設計模式(十八)——重試模式
啟用應用程式來處理預期的,暫時的失敗時,它會嘗試串連到由透明的重試操作了以前失敗的期望,失敗的原因是瞬時的服務或網路資源。這種模式可以提高應用程式的穩定性。
背景和問題
該通訊的應用程式與在雲中啟動並執行元素必須是可能發生在這樣的環境中的瞬時故障敏感。這些故障包括網路連接的過程中出現時,一個服務是忙碌的瞬時損失的組件和服務中,服務的臨時不可用,或逾時。
這些故障一般是自校正的,如果經過一個合適的延遲被重複觸發一個故障的動作很可能是成功的。例如,資料庫服務,它正在處理大量並發請求可以實現節流策略,暫時拒絕,直到它的工作量有所緩和任何進一步的請求。試圖訪問該資料庫的應用程式可能無法串連,但如果它經過一個合適的延遲再次嘗試它可能會成功。
解決方案
在雲中,瞬時故障的情況並不少見和應用應該被設計為優雅和透明地處理它們,減少的影響,這種故障可能對應用程式正在執行業務任務。
如果一個應用程式檢測到故障時,它試圖將請求發送到遠程服務,它可以通過使用以下策略處理失敗:
?如果故障指示故障不是瞬時的或不太成功,如果重複(例如,所造成的無效提供憑據的認證失敗是不可能成功的,無論是多少次未遂),應用程式應中止操作和報告一個合適的異常。
?如果報道的具體故障是不尋常的或罕見的,這可能是由於反常的情況,如網路資料包成為損壞,同時它被發送。在這種情況下,應用程式可以再次立即重試失敗的請求,因為相同的故障是不可能被重複和請求將可能是成功的。
?如果故障是由一種更加普遍的串連,或“忙”的失敗,網路或服務可能需要在短期內同時串連問題糾正或工作的積壓被清除。應用程式應該等待請求重試前一個合適的時間。
對於比較常見的短暫故障,重試期間,應選擇以傳播從應用程式中儘可能均勻的多個執行個體的請求。這可以減少繁忙的業務持續過載的可能性。如果一個應用程式的多個執行個體不斷轟擊與重試請求的服務,則可能需要該服務更長的時間來恢複。
如果請求仍然失敗,應用程式可以等待進一步的時期,再次嘗試。如果需要的話,這個過程可以重複而增加重試的延遲,直到請求的某一最大數目已經嘗試都失敗了。延遲時間可以逐步增加,或可使用的定時策略,如指數回退,取決於故障的性質和可能性,這將在這段時間內被校正。
圖1示出了這種模式。如果嘗試後的預定數量的請求不成功,應用程式應將故障為異常,並相應地處理它。
圖1 - 使用重試模式中調用託管服務的操作
應用程式應該換所有試圖訪問遠程服務,實現重試政策配套上面列出的策略之一的代碼。發送到不同的服務要求會受到不同的政策,有的供應商提供封裝這種方法庫。這些庫通常執行的政策是參數化的,而應用程式開發人員可以指定,如重試次數和重試之間的時間項的值。
在檢測故障和重試失敗的操作都應該記錄這些故障的詳細資料的應用程式的代碼。這個資訊可能是有用的運算子。如果一個服務被頻繁報道為不可用或忙,往往是因為該服務已耗盡其資源。則可以減少與這些故障發生時通過換算出該服務的頻率。例如,如果資料庫服務正在不斷超載,它可能是有利的分區資料庫和負載分散到多個伺服器。
注意:
微軟Azure提供了重試模式的廣泛支援。該模式與實踐瞬態故障處理塊允許應用程式通過一系列的重試策略來處理許多Azure服務瞬態故障。微軟Entity Framework版本6提供了用於重新嘗試資料庫操作。此外,許多在AzureService Bus和Azure儲存的API透明地執行重試邏輯。
問題和注意事項
在決定如何?這個模式時,您應考慮以下幾點:
?重試政策應進行調整,以滿足應用和故障性質的業務需求。它可能是更好一些非關鍵操作失敗快而不是重試幾次,並影響應用程式的輸送量。例如,在試圖訪問遠程服務的互動式Web應用程式,這可能是更好的重試之後用重試之間只有一個短的延遲的數量較少失敗,並顯示一個適當的訊息給使用者(例如,“請稍後“),再次嘗試阻止應用程式變得反應遲鈍。對於批處理應用程式,它可以是更合適的,以增加重試嘗試的次數與嘗試之間的指數增加的延遲。
?與嘗試之間最小的延遲和大量的重試的高攻擊重試的政策,可能會進一步降低正在接近運行或容量的佔用。此重試策略也可能會影響應用程式的響應,如果它被不斷地在嘗試執行失敗的操作,而不是做有用功。
?如果後一個顯著次數的重試請求仍然失敗,則可能是更好的應用程式,以防止進一步的請求將要在相同的資源為一個周期,並簡單地立即報告故障。當期限屆滿後,該應用程式可以暫時允許通過一個或多個請求,看看他們是否成功。對於這一策略的詳細資料,請參閱斷路器格局。
?在由它實現了一個重試策略可能需要為等冪的應用程式調用的服務的操作。例如,發送到服務的請求可以被接收和處理成功,但是,由於瞬時故障,它可能無法發送響應,指示該處理已完成。然後在應用程式的重試邏輯可能試圖重複上沒有接收到所述第一請求的假定該請求。
?一個請求到服務失敗可能由於各種原因而提出不同的異常,根據故障的性質。一些例外可指示故障,可以非常迅速地得到解決,而另一些可能表明該故障期間更長。可能是有益的重試策略,調整基於所述異常的類型的重試嘗試之間的時間。
?考慮如何重試的操作是事務的一部分,會影響整體交易的一致性。這可能是有用的微調對於事務性操作的重試政策,最大限度地取得成功的機會,並減少需要撤消所有交易步驟。
?確保所有重試代碼是完全針對各種故障條件下進行測試。檢查它不會嚴重影響應用程式的效能或可靠性,導致在服務和資源的過度負荷,或產生競態條件或瓶頸。
?實現只在一個失敗的操作的全方面瞭解重試邏輯。例如,如果包含的重試策略任務調用另一個任務還包含一個重試策略,這個額外的重試的層可加長的延遲的處理。它可能是更好的配置的低級任務失敗快速並報告失敗返回調用它的任務的原因。然後這個更進階別的任務可以決定如何處理是根據它自己的策略失效。
?記錄所有的串連故障,提示了重試,使潛在的問題與該應用程式,服務或資源可以被識別是很重要的。
?研究是最有可能發生於一個服務或資摘要搜索,如果它們有可能是持久或終端的故障。如果是這樣的話,它可能是更好地處理該故障為異常。該應用程式可以報告或記錄該異常,然後試圖通過調用另一個服務,持續或者(如果有一個可用的),或通過提供降級功能。關於如何檢測和處理持久故障的更多資訊,請參閱斷路器格局。
何時使用這個模式
使用這種模式:
?當一個應用程式可能會經曆短暫的故障,因為它與遠程服務進行互動,或訪問遠端資源。這些故障預計將是短暫的,並重複了以前沒有能夠成功的後續嘗試的請求。
這種模式可能不適合:
?當故障很可能是持久的,因為這可能會影響應用程式的響應性。該應用程式可以簡單地是浪費時間和資源試圖重複請求是最有可能失敗。
?對於處理故障是不因瞬時故障,如在應用程式的商務邏輯引起錯誤的內部的異常。
?作為一種替代解決系統中的可擴充性問題。如果一個應用程式有頻繁的“忙”的故障,這是通常指示被訪問的服務或資源應相應加大。
例子
本實施例說明的重試模式的實現。該OperationWithBasicRetryAsync方法,如下所示,通過TransientOperationAsync方法非同步呼叫外部服務(該方法的細節將特定於服務,並從樣本代碼被省略)。
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(){ ...}
調用此方法的聲明被包裹在一個迴圈一個try/catch塊中封裝。如果調用TransientOperationAsync方法成功,沒有拋出異常的for迴圈退出。如果TransientOperationAsync方法失敗,catch塊檢查為失敗的原因,並且如果它被認為是一個瞬時錯誤碼等待一個短暫的延時,然後重試該操作。
在for迴圈還跟蹤該操作已經嘗試的次數,並且如果代碼失敗三次異常被認為是更持久。如果該異常是不是暫時的,或者是長久的,catch處理拋出的異常。此異常退出for迴圈,應捕獲調用該OperationWithBasicRetryAsync方法的代碼。
該IsTransient方法,如下所示,檢查是否有特定的一組是相關的,其中所述代碼啟動並執行環境的異常。一過異常的定義可以根據被訪問的資源,並在其上執行的作業環境的不同而不同。
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;}
本文翻譯自MSDN:http://msdn.microsoft.com/en-us/library/dn589788.aspx
雲端運算設計模式(十八)——重試模式