Azure 服務的重試指引

大部分的 Azure 服務和用戶端 SDK 都包含重試機制。 不過,這些差異是因為每個服務都有不同的特性和需求,因此每個重試機制都會調整為特定的服務。 本指南摘要說明大部分 Azure 服務的重試機制功能,並包含可協助您使用、調整或擴充該服務重試機制的資訊。

如需處理暫時性錯誤,以及針對服務和資源重試連線和作業的一般指引,請參閱 重試指引

下表摘要說明本指南中所述之 Azure 服務的重試功能。

服務 重試功能 原則設定 範圍 遙測功能
Microsoft Entra ID MSAL 連結庫中的原生 內嵌至 MSAL 連結庫 內部
Azure Cosmos DB 服務中的原生 不可設定 全球 TraceSource
Data Lake Store 用戶端中的原生 不可設定 個別作業
事件中樞 用戶端中的原生 程式設計 用戶端
IoT 中樞 用戶端 SDK 中的原生 程式設計 用戶端
Azure Cache for Redis 用戶端中的原生 程式設計 用戶端 TextWriter
Search 用戶端中的原生 程式設計 用戶端 ETW 或自定義
服務匯流排 用戶端中的原生 程式設計 命名空間管理員、傳訊處理站和用戶端 ETW
Service Fabric 用戶端中的原生 程式設計 用戶端
使用 ADO.NET SQL 資料庫 Polly 宣告式和程序設計 單一語句或程式代碼區塊 自訂
使用 Entity Framework SQL 資料庫 用戶端中的原生 程式設計 每個 AppDomain 的全域
使用 Entity Framework Core SQL 資料庫 用戶端中的原生 程式設計 每個 AppDomain 的全域
Storage 用戶端中的原生 程式設計 用戶端和個別作業 TraceSource

注意

對於大部分的 Azure 內建重試機制,目前無法針對不同類型的錯誤或例外狀況套用不同的重試原則。 您應該設定提供最佳平均效能和可用性的原則。 微調原則的其中一種方法是分析記錄檔,以判斷發生的暫時性錯誤類型。

Microsoft Entra ID

Microsoft Entra ID 是整合核心目錄服務、進階身分識別治理、安全性和應用程式存取管理的完整身分識別和存取管理雲端解決方案。 Microsoft Entra ID 也為開發人員提供身分識別管理平臺,根據集中式原則和規則,為應用程式提供訪問控制。

注意

如需受控服務識別端點的重試指引,請參閱 如何使用 Azure VM 受控服務識別 (MSI) 取得令牌

重試機制

Microsoft 驗證連結庫中有 Microsoft Entra ID 的內建重試機制。 為了避免非預期的鎖定,我們建議第三方連結庫和應用程式程式代碼不會重試失敗的連線,但允許 MSAL 處理重試。

重試使用指引

使用 Microsoft Entra ID 時,請考慮下列指導方針:

  • 可能的話,請使用 MSAL 連結庫和重試的內建支援。
  • 如果您使用 REST API for Microsoft Entra ID,請在結果碼為 429 (太多要求) 或 5xx 範圍內的錯誤時重試作業。 請勿重試任何其他錯誤。
  • 針對 429 錯誤,只有在 Retry-After 標頭中所指出的時間之後才重試。
  • 針對 5xx 錯誤,請使用指數輪詢,並在響應之後至少重試 5 秒。
  • 請勿重試 429 和 5xx 以外的錯誤。

下一步

Azure Cosmos DB

Azure Cosmos DB 是完全受控的多模型資料庫,可支援無架構 JSON 數據。 它提供了可設定及可靠的效能、原生的 JavaScript 交易處理,是專門為彈性擴充的雲端所打造的。

重試機制

Azure Cosmos DB SDK 會自動在特定錯誤狀況上重試,並鼓勵使用者應用程式有自己的重試原則。 如需錯誤狀況的完整清單,以及何時重試,請參閱使用 Azure Cosmos DB SDK 設計復原應用程式的指南。

遙測

視應用程式的語言而定,診斷和遙測會公開為作業回應上的記錄或升級屬性。 如需詳細資訊,請參閱 Azure Cosmos DB C# SDK 和 Azure Cosmos DB Java SDK 中的一節。

Data Lake Store

Data Lake 儲存體 Gen2 讓 Azure 儲存體 在 Azure 上建置企業數據湖的基礎。 Data Lake 儲存體 Gen2 可讓您輕鬆地管理大量數據。

Azure 儲存體 Files Data Lake 用戶端連結庫包含所有必要功能,讓開發人員、數據科學家和分析師輕鬆地儲存任何大小、形狀和速度的數據,以及跨平臺和語言執行所有類型的處理和分析。

重試機制

DataLakeServiceClient 可讓您操作 Azure Data Lake 服務資源和文件系統。 記憶體帳戶會提供 Data Lake 服務的最上層命名空間。 當您建立用戶端時,您可以提供連線到 Azure Data Lake Service (DataLakeClientOptions) 的用戶端組態選項。 DataLakeClientOptions 包含可設定的 Retry 屬性(繼承自 Azure.Core.ClientOptions)(RetryOptions 類別)。

遙測

監視 Azure 儲存體的使用和效能是運作服務的重要部分。 範例包括頻繁的作業、高延遲的作業,或導致服務端節流的作業。

記憶體帳戶的所有遙測都可透過 Azure 監視器中的 Azure 儲存體 記錄來取得。 此功能會將記憶體帳戶與 Log Analytics 和事件中樞整合,同時可讓您將記錄封存到另一個記憶體帳戶。 若要查看計量和資源記錄及其相關聯架構的完整清單,請參閱 Azure 儲存體 監視數據參考

事件中樞

Azure 事件中樞 是超大規模遙測擷取服務,可收集、轉換及儲存數百萬個事件。

重試機制

Azure 事件中樞 客戶端連結庫中的重試行為是由 RetryPolicy 類別上的 EventHubClient 屬性所控制。 當 Azure 事件中樞 傳回暫時性EventHubsExceptionOperationCanceledException時,默認原則會使用指數輪詢重試。 事件中樞的預設重試原則是重試最多 9 次,而指數輪詢時間最多為 30 秒。

範例

EventHubClient client = EventHubClient.CreateFromConnectionString("[event_hub_connection_string]");
client.RetryPolicy = RetryPolicy.Default;

下一步

適用於 .NET 的 Azure 事件中樞 客戶端連結庫

IoT 中樞

Azure IoT 中樞 是一項服務,可用來連線、監視和管理裝置,以開發物聯網 (IoT) 應用程式。

重試機制

Azure IoT 裝置 SDK 可以偵測網路、通訊協定或應用程式中的錯誤。 根據錯誤類型,SDK 會檢查是否需要執行重試。 如果錯誤可復原,SDK 會使用設定的重試原則開始重試。

默認重試原則是 具有隨機抖動的指數輪詢,但可以設定。

原則設定

原則設定與語言不同。 如需詳細資訊,請參閱 IoT 中樞 重試原則設定

下一步

Azure Cache for Redis

Azure Cache for Redis 是以熱門開放原始碼 Redis 快取為基礎的快速數據存取和低延遲快取服務。 它是安全的、由 Microsoft 管理,且可從 Azure 中的任何應用程式存取。

本節中的指引是以使用 StackExchange.Redis 用戶端存取快取為基礎。 您可以在 Redis 網站上找到其他適當的用戶端清單,而這些用戶端可能會有不同的重試機制。

StackExchange.Redis 用戶端會透過單一聯機使用多任務處理。 建議的用法是在應用程式啟動時建立客戶端的實例,並針對快取的所有作業使用此實例。 基於這個理由,快取的連接只會進行一次,因此本節中的所有指引都與此初始連線的重試原則有關,而不是針對存取快取的每個作業。

重試機制

StackExchange.Redis 用戶端會使用透過一組選項設定的連接管理員類別,包括:

  • 連線 重試。 重試與快取連線失敗的次數。
  • ReconnectRetryPolicy。 要使用的重試策略。
  • 連線 Timeout。 等候時間上限,以毫秒為單位。

原則設定

在連線到快取之前,先設定客戶端的選項,以程式設計方式設定重試原則。 這可以藉由建立 ConfigurationOptions 類別的實例、填入其屬性,並將它傳遞至 連線 方法來完成。

內建類別支援具有隨機重試間隔的線性(常數)延遲和指數輪詢。 您也可以實 作 IReconnectRetryPolicy 介面來建立自定義重試原則。

下列範例會使用指數輪詢來設定重試策略。

var deltaBackOffInMilliseconds = TimeSpan.FromSeconds(5).TotalMilliseconds;
var maxDeltaBackOffInMilliseconds = TimeSpan.FromSeconds(20).TotalMilliseconds;
var options = new ConfigurationOptions
{
    EndPoints = {"localhost"},
    ConnectRetry = 3,
    ReconnectRetryPolicy = new ExponentialRetry(deltaBackOffInMilliseconds, maxDeltaBackOffInMilliseconds),
    ConnectTimeout = 2000
};
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(options, writer);

或者,您可以將選項指定為字串,並將此選項傳遞至 連線 方法。 只有透過程序代碼,才能以這種方式設定 ReconnectRetryPolicy 屬性。

var options = "localhost,connectRetry=3,connectTimeout=2000";
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(options, writer);

您也可以在連線到快取時直接指定選項。

var conn = ConnectionMultiplexer.Connect("redis0:6380,redis1:6380,connectRetry=3");

如需詳細資訊,請參閱 StackExchange.Redis 檔中的 Stack Exchange Redis 組態

下表顯示內建重試原則的預設設定。

內容 設定 預設值
(第1.2.2版)
意義
ConfigurationOptions 連線 Retry

ConnectTimeout

SyncTimeout

ReconnectRetryPolicy
3

最大 5000 毫秒加上 SyncTimeout
1000

LinearRetry 5000 毫秒
在初始連接作業期間重複連接嘗試的次數。
線上作業的逾時 (毫秒)。 重試嘗試之間不是延遲。
允許同步作業的時間 (毫秒)。

每 5000 毫秒重試一次。

注意

針對同步作業, SyncTimeout 可以新增至端對端延遲,但設定值太低可能會導致逾時過多。 請參閱 如何針對 Azure Cache for Redis 進行疑難解答。 一般而言,請避免使用同步作業,並改用異步操作。 如需詳細資訊,請參閱 管線和多任務器

重試使用指引

使用 Azure Cache for Redis 時,請考慮下列指導方針:

  • StackExchange Redis 用戶端會管理自己的重試,但只有在應用程式第一次啟動時建立快取的連線時。 您可以設定連線逾時、重試次數,以及建立此連線的重試間隔時間,但重試原則不適用於對快取的作業。
  • 請考慮改為存取原始數據源,而不是使用大量重試嘗試。

遙測

您可以使用 TextWriter 收集連線的相關信息(但無法收集其他作業)。

var writer = new StringWriter();
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(options, writer);

以下顯示這個產生的輸出範例。

localhost:6379,connectTimeout=2000,connectRetry=3
1 unique nodes specified
Requesting tie-break from localhost:6379 > __Booksleeve_TieBreak...
Allowing endpoints 00:00:02 to respond...
localhost:6379 faulted: SocketFailure on PING
localhost:6379 failed to nominate (Faulted)
> UnableToResolvePhysicalConnection on GET
No masters detected
localhost:6379: Standalone v2.0.0, master; keep-alive: 00:01:00; int: Connecting; sub: Connecting; not in use: DidNotRespond
localhost:6379: int ops=0, qu=0, qs=0, qc=1, wr=0, sync=1, socks=2; sub ops=0, qu=0, qs=0, qc=0, wr=0, socks=2
Circular op-count snapshot; int: 0 (0.00 ops/s; spans 10s); sub: 0 (0.00 ops/s; spans 10s)
Sync timeouts: 0; fire and forget: 0; last heartbeat: -1s ago
resetting failing connections to retry...
retrying; attempts left: 2...
...

範例

下列程式代碼範例會在初始化 StackExchange.Redis 用戶端時,設定重試之間的常數(線性)延遲。 此範例示範如何使用 ConfigurationOptions 實例來設定組態。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace RetryCodeSamples
{
    class CacheRedisCodeSamples
    {
        public async static Task Samples()
        {
            var writer = new StringWriter();
            {
                try
                {
                    var retryTimeInMilliseconds = TimeSpan.FromSeconds(4).TotalMilliseconds; // delay between retries

                    // Using object-based configuration.
                    var options = new ConfigurationOptions
                                        {
                                            EndPoints = { "localhost" },
                                            ConnectRetry = 3,
                                            ReconnectRetryPolicy = new LinearRetry(retryTimeInMilliseconds)
                                        };
                    ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(options, writer);

                    // Store a reference to the multiplexer for use in the application.
                }
                catch
                {
                    Console.WriteLine(writer.ToString());
                    throw;
                }
            }
        }
    }
}

下一個範例會將選項指定為字串,以設定組態。 線上逾時是等候快取連線的時間上限,而不是重試嘗試之間的延遲。 ReconnectRetryPolicy 屬性只能由程式代碼設定。

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace RetryCodeSamples
{
    class CacheRedisCodeSamples
    {
        public async static Task Samples()
        {
            var writer = new StringWriter();
            {
                try
                {
                    // Using string-based configuration.
                    var options = "localhost,connectRetry=3,connectTimeout=2000";
                    ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(options, writer);

                    // Store a reference to the multiplexer for use in the application.
                }
                catch
                {
                    Console.WriteLine(writer.ToString());
                    throw;
                }
            }
        }
    }
}

如需更多範例,請參閱項目網站上的設定。

下一步

Azure 搜尋服務可用來將強大且複雜的搜尋功能新增至網站或應用程式,快速且輕鬆地調整搜尋結果,以及建構豐富且微調的排名模型。

重試機制

適用於 .NET 的 Azure SDK 包含 來自 Azure SDK 小組的 Azure.Search.Documents 用戶端連結庫, 其功能相當於先前的用戶端連結庫 Microsoft.Azure.Search

Microsoft.Azure.Search 中的重試行為是由 SearchServiceClient 和 SearchIndexClient 類別上的 SetRetryPolicy 方法所控制。 當 Azure 搜尋服務傳回 5xx 或 408(要求逾時)回應時,默認原則會重試指數輪詢。

Azure.Search.Documents 中的重試行為是由 SearchClientOptions (它是 SearchClient 建構函式的一部分)控制,該屬性屬於 Azure.Core.RetryOptions 類別(其中所有組態皆可供使用)。

遙測

使用 ETW 或註冊自定義追蹤提供者進行追蹤。 如需詳細資訊,請參閱 AutoRest 檔

服務匯流排

服務匯流排 是一個雲端傳訊平臺,可為應用程式元件提供鬆散結合的訊息交換,以提升應用程式的規模和復原能力,無論是裝載於雲端還是內部部署。

重試機制

命名空間和一些組態詳細資料取決於使用哪些 服務匯流排 用戶端 SDK 套件:

Package 描述 Namespace
Azure.Messaging.ServiceBus 適用於 .NET 的用戶端連結庫 Azure 服務匯流排 Azure.Messaging.ServiceBus
WindowsAzure.ServiceBus 此套件是較舊的 服務匯流排 客戶端連結庫。 它需要 .NET Framework 4.5.2。 Microsoft.Azure.ServiceBus

重試使用指引

屬性 ServiceBusRetryOptions 會指定物件的重試選項 ServiceBusClient

設定 預設值 意義
CustomRetryPolicy 用來取代個別選項值的自定義重試原則。
Delay 0.8 秒 固定方法的重試嘗試之間的延遲,或要針對輪詢型方法進行基礎計算的延遲。
MaxDelay 60 秒鐘 重試嘗試之間的允許延遲上限。
MaxRetries 3 在考慮相關聯的作業失敗之前,重試嘗試次數上限。
模式 指數 用於計算重試延遲的方法。
TryTimeout 60 秒鐘 等候完成單一嘗試的最大持續時間,無論是初始嘗試還是重試。

設定 Mode 屬性以使用下列任何值設定 ServiceBusRetryMode

屬性 數值 Description
指數 1 重試嘗試會根據輪詢策略延遲,其中每次嘗試都會增加重試前等候的持續時間。
已修正 0 重試嘗試會以固定間隔發生;每個延遲都是一致的持續時間。

範例:

using Azure.Messaging.ServiceBus;

string connectionString = "<connection_string>";
string queueName = "<queue_name>";

// Because ServiceBusClient implements IAsyncDisposable, we'll create it
// with "await using" so that it is automatically disposed for us.
var options = new ServiceBusClientOptions();
options.RetryOptions = new ServiceBusRetryOptions
{
    Delay = TimeSpan.FromSeconds(10),
    MaxDelay = TimeSpan.FromSeconds(30),
    Mode = ServiceBusRetryMode.Exponential,
    MaxRetries = 3,
};
await using var client = new ServiceBusClient(connectionString, options);

遙測

服務匯流排 會收集與其他 Azure 資源相同的監視數據種類。 您可以使用 Azure 監視器監視 Azure 服務匯流排

您也可以使用 服務匯流排 .NET 用戶端連結庫傳送遙測的各種選項。

範例

下列程式代碼範例示範如何使用 Azure.Messaging.ServiceBus 封裝來:

  • 使用新的 ServiceBusClientOptions設定的重試原則ServiceBusClient
  • 使用的新實例 ServiceBusMessage建立新的訊息。
  • 使用 ServiceBusSender.SendMessageAsync(message) 方法將訊息傳送至 服務匯流排。
  • 使用 ServiceBusReceiver表示為 ServiceBusReceivedMessage 物件的 接收。
// using Azure.Messaging.ServiceBus;

using Azure.Messaging.ServiceBus;

string connectionString = "<connection_string>";
string queueName = "queue1";

// Because ServiceBusClient implements IAsyncDisposable, we'll create it 
// with "await using" so that it is automatically disposed for us.
var options = new ServiceBusClientOptions();
options.RetryOptions = new ServiceBusRetryOptions
{
    Delay = TimeSpan.FromSeconds(10),
    MaxDelay = TimeSpan.FromSeconds(30),
    Mode = ServiceBusRetryMode.Exponential,
    MaxRetries = 3,
};
await using var client = new ServiceBusClient(connectionString, options);

// The sender is responsible for publishing messages to the queue.
ServiceBusSender sender = client.CreateSender(queueName);
ServiceBusMessage message = new ServiceBusMessage("Hello world!");

await sender.SendMessageAsync(message);

// The receiver is responsible for reading messages from the queue.
ServiceBusReceiver receiver = client.CreateReceiver(queueName);
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

string body = receivedMessage.Body.ToString();
Console.WriteLine(body);

下一步

Service Fabric

在 Service Fabric 叢集中散發可靠的服務可防範本文所討論的大部分潛在暫時性錯誤。 不過,仍有一些暫時性錯誤。 例如,命名服務可能會在取得要求時處於路由變更的中間,導致它擲回例外狀況。 如果相同的要求在 100 毫秒之後出現,它可能會成功。

在內部,Service Fabric 會管理這類暫時性錯誤。 您可以在設定服務時使用 OperationRetrySettings 類別來設定某些設定。 下列程式碼為範例。 在大部分情況下,這不應該必要,而且預設設定會沒問題。

FabricTransportRemotingSettings transportSettings = new FabricTransportRemotingSettings
{
    OperationTimeout = TimeSpan.FromSeconds(30)
};

var retrySettings = new OperationRetrySettings(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(1), 5);

var clientFactory = new FabricTransportServiceRemotingClientFactory(transportSettings);

var serviceProxyFactory = new ServiceProxyFactory((c) => clientFactory, retrySettings);

var client = serviceProxyFactory.CreateServiceProxy<ISomeService>(
    new Uri("fabric:/SomeApp/SomeStatefulReliableService"),
    new ServicePartitionKey(0));

下一步

使用 ADO.NET SQL 資料庫

SQL 資料庫 是一種裝載的 SQL 資料庫,可在各種大小和標準(共用)和進階(非共用)服務中使用。

重試機制

使用 ADO.NET 存取時,SQL 資料庫 沒有內建的重試支援。 不過,來自要求的傳回碼可用來判斷要求失敗的原因。 如需 SQL 資料庫 節流的詳細資訊,請參閱 Azure SQL 資料庫 資源限制。 如需相關錯誤碼的清單,請參閱 SQL 資料庫 用戶端應用程式的 SQL 錯誤碼。

您可以使用 Polly 連結庫來實作 SQL 資料庫 的重試。 請參閱 使用 Polly 處理暫時性錯誤。

重試使用指引

使用 ADO.NET 存取 SQL 資料庫 時,請考慮下列指導方針:

  • 選擇適當的服務選項(共用或進階版)。 共用實例可能會因為共享伺服器的其他租使用者使用量而遭受的連線延遲和節流時間長。 如果需要更可預測的效能和可靠的低延遲作業,請考慮選擇進階選項。
  • 請確定您在適當的層級或範圍執行重試,以避免非等冪作業導致數據不一致。 在理想情況下,所有作業都應該是等冪的,因此可以重複執行,而不會造成不一致。 如果情況並非如此,則重試應該在一個作業失敗時,於層級或範圍執行,以允許復原所有相關變更;例如,從交易範圍內。 如需詳細資訊,請參閱 雲端服務基本概念數據存取層 – 暫時性錯誤處理
  • 不建議使用固定間隔策略來搭配 Azure SQL 資料庫,但只有一些短間隔重試的互動式案例除外。 相反地,請考慮針對大部分案例使用指數輪詢策略。
  • 在定義連線時,選擇適當的連接值和命令逾時。 逾時太短可能會導致資料庫忙碌時連線過早失敗。 逾時時間過長,可能會讓重試邏輯在偵測失敗的連線之前等候太久,以避免重試邏輯正常運作。 逾時的值是端對端延遲的元件;它會針對每次重試嘗試有效地新增至重試原則中指定的重試延遲。
  • 在一些重試之後關閉連線,即使使用指數輪詢重試邏輯,也會在新聯機上重試作業。 在同一個連線上多次重試相同的作業,可能是導致連線問題的因素。 如需這項技術的範例,請參閱 雲端服務基本概念數據存取層 – 暫時性錯誤處理
  • 當連接共用正在使用中時(預設值)時,即使關閉並重新開啟連線,也有可能從集區選擇相同的連線。 如果是,則解析其技術是呼叫 Sql 連線 ion 類別的 ClearPool 方法,將聯機標示為不可重複使用。 不過,只有在幾次連線嘗試失敗之後,才應該這麼做,而且只有在遇到與錯誤連線相關的特定暫時性失敗類別時,例如 SQL 逾時(錯誤碼 -2)。
  • 如果數據存取程式代碼使用以 TransactionScope 實例起始的交易,重試邏輯應該重新開啟連線並起始新的交易範圍。 基於這個理由,可重試的程式代碼區塊應該包含交易的整個範圍。

請考慮從下列設定開始重試作業。 這些設定是一般用途,您應該監視作業並微調值,以符合您自己的案例。

內容 範例目標 E2E
最大延遲
重試策略 設定 運作方式
互動式,UI,
或前景
2 秒 FixedInterval 重試計數
重試間隔
第一次快速重試
3
500 毫秒
true
嘗試 1 - 延遲 0 秒
嘗試 2 - 延遲 500 毫秒
嘗試 3 - 延遲 500 毫秒
背景
或批次
30 秒 ExponentialBackoff 重試計數
最小退場
最大退場時間
差異退場
第一次快速重試
5
0 秒
60 秒
2 秒
false
嘗試 1 - 延遲 0 秒
嘗試 2 - 延遲 ~2 秒
嘗試 3 - 延遲 ~6 秒
嘗試 4 - 延遲 ~14 秒
嘗試 5 - 延遲 ~30 秒

注意

端對端延遲目標會假設服務連線的預設逾時。 如果您指定較長的連線逾時,每次重試嘗試時,端對端延遲將會再延長一次。

範例

本節說明如何使用 Polly,透過 類別中Policy設定的一組重試原則來存取 Azure SQL 資料庫。

下列程式代碼顯示類別ExecuteAsync上呼叫指數輪詢的SqlCommand擴充方法。

public async static Task<SqlDataReader> ExecuteReaderWithRetryAsync(this SqlCommand command)
{
    GuardConnectionIsNotNull(command);

    var policy = Policy.Handle<Exception>().WaitAndRetryAsync(
        retryCount: 3, // Retry 3 times
        sleepDurationProvider: attempt => TimeSpan.FromMilliseconds(200 * Math.Pow(2, attempt - 1)), // Exponential backoff based on an initial 200 ms delay.
        onRetry: (exception, attempt) =>
        {
            // Capture some information for logging/telemetry.
            logger.LogWarn($"ExecuteReaderWithRetryAsync: Retry {attempt} due to {exception}.");
        });

    // Retry the following call according to the policy.
    await policy.ExecuteAsync<SqlDataReader>(async token =>
    {
        // This code is executed within the Policy

        if (conn.State != System.Data.ConnectionState.Open) await conn.OpenAsync(token);
        return await command.ExecuteReaderAsync(System.Data.CommandBehavior.Default, token);

    }, cancellationToken);
}

您可以使用這個異步擴充方法,如下所示。

var sqlCommand = sqlConnection.CreateCommand();
sqlCommand.CommandText = "[some query]";

using (var reader = await sqlCommand.ExecuteReaderWithRetryAsync())
{
    // Do something with the values
}

下一步

使用 Entity Framework 6 SQL 資料庫

SQL 資料庫 是一種裝載的 SQL 資料庫,可在各種大小及標準(共用)和進階(非共用)服務中使用。 Entity Framework 是對象關係型對應程式,可讓 .NET 開發人員使用特定領域對象來處理關係型數據。 有了 Entity Framework,開發人員便不再需要撰寫大多數必須撰寫的資料存取程式碼。

重試機制

透過稱為「連線 復原/重試邏輯」的機制,使用 Entity Framework 6.0 和更新版本存取 SQL 資料庫 時,會提供重試支援。 重試機制的主要功能包括:

  • 主要抽象概念是 IDbExecutionStrategy 介面。 這個介面:
    • 定義同步和異步 的Execute 方法。
    • 定義可以直接使用的類別,或可在資料庫內容上設定為預設策略、對應至提供者名稱,或對應至提供者名稱和伺服器名稱。 在內容上設定時,重試會在個別資料庫作業的層級進行,其中給定的內容作業可能會有數個。
    • 定義重試失敗連線的時機,以及如何。
  • 它包含數個 IDbExecutionStrategy 介面的內建實作:
    • 默認值:不重試。
    • 默認為 SQL 資料庫 (automatic):不重試,但會檢查例外狀況,並將它們包裝成建議使用 SQL 資料庫 策略。
    • SQL 資料庫 的預設值:指數型(繼承自基類),加上 SQL 資料庫 偵測邏輯。
  • 它會實作包含隨機化的指數輪詢策略。
  • 內建的重試類別是具狀態的,而且不是安全線程。 不過,在目前的作業完成之後,可以重複使用它們。
  • 如果超過指定的重試計數,結果會包裝在新例外狀況中。 它不會將目前的例外狀況反升。

原則設定

使用 Entity Framework 6.0 和更新版本存取 SQL 資料庫 時,會提供重試支援。 重試原則會以程式設計方式設定。 每個作業都無法變更組態。

將內容上的策略設定為預設值時,您可以指定函式來依需求建立新的策略。 下列程式代碼示範如何建立擴充 DbConfiguration 基類的 重試組態 類別。

public class BloggingContextConfiguration : DbConfiguration
{
  public BlogConfiguration()
  {
    // Set up the execution strategy for SQL Database (exponential) with 5 retries and 4 sec delay
    this.SetExecutionStrategy(
         "System.Data.SqlClient", () => new SqlAzureExecutionStrategy(5, TimeSpan.FromSeconds(4)));
  }
}

然後,您可以使用應用程式啟動時,使用 DbConfiguration 實例的 SetConfiguration 方法,將此指定為所有作業的預設重試策略。 根據預設,EF 會自動探索並使用組態類別。

DbConfiguration.SetConfiguration(new BloggingContextConfiguration());

您可以使用 DbConfigurationType 屬性來標註內容類別,以指定內容的重試組態類別。 不過,如果您只有一個組態類別,EF 會使用它,而不需要標註內容。

[DbConfigurationType(typeof(BloggingContextConfiguration))]
public class BloggingContext : DbContext

如果您需要針對特定作業使用不同的重試策略,或停用特定作業的 重試,您可以建立組態類別,讓您在 CallContext 中設定旗標來暫停或交換策略。 組態類別可以使用這個旗標來切換策略,或停用您所提供的策略並使用預設策略。 如需詳細資訊,請參閱 暫停執行策略 (EF6 及更新版本)。

針對個別作業使用特定重試策略的另一個技巧是建立必要策略類別的實例,並透過參數提供所需的設定。 然後,您會叫用它的 ExecuteAsync 方法。

var executionStrategy = new SqlAzureExecutionStrategy(5, TimeSpan.FromSeconds(4));
var blogs = await executionStrategy.ExecuteAsync(
    async () =>
    {
        using (var db = new BloggingContext("Blogs"))
        {
            // Acquire some values asynchronously and return them
        }
    },
    new CancellationToken()
);

使用 DbConfiguration 類別最簡單的方式,就是將它放在與 DbContext 類別相同的元件中。 不過,當不同案例中需要相同的內容時,這並不適用,例如不同的互動式和背景重試策略。 如果不同的內容在不同的 AppDomains 中執行,您可以使用內建支援來指定組態檔中的組態類別,或使用程式代碼明確設定。 如果不同的內容必須在相同的 AppDomain 中執行,則需要自定義解決方案。

如需詳細資訊,請參閱 程式代碼型 設定(EF6 及更新版本)。

下表顯示使用EF6時內建重試原則的預設設定。

設定 預設值 意義
原則 指數 指數輪詢。
MaxRetryCount 5 重試次數上限。
MaxDelay 30 秒 重試之間的最大延遲。 此值不會影響計算一系列延遲的方式。 它只會定義上限。
DefaultCoefficient 1 秒 指數輪詢計算的係數。 此值無法變更。
DefaultRandomFactor 1.1 用來為每個專案新增隨機延遲的乘數。 此值無法變更。
DefaultExponentialBase 2 用來計算下一個延遲的乘數。 此值無法變更。

重試使用指引

使用 EF6 存取 SQL 資料庫 時,請考慮下列指導方針:

  • 選擇適當的服務選項(共用或進階版)。 共用實例可能會因為共享伺服器的其他租使用者使用量而遭受的連線延遲和節流時間長。 如果需要可預測的效能和可靠的低延遲作業,請考慮選擇進階選項。

  • 不建議使用固定間隔策略來搭配 Azure SQL 資料庫 使用。 相反地,請使用指數輪詢策略,因為服務可能會超載,而較長的延遲可讓其有更多時間復原。

  • 在定義連線時,選擇適當的連接值和命令逾時。 根據商業規則設計和透過測試來設定逾時。 隨著數據量或商務程序變更,您可能需要隨著時間修改此值。 逾時太短可能會導致資料庫忙碌時連線過早失敗。 逾時時間過長,可能會讓重試邏輯在偵測失敗的連線之前等候太久,以避免重試邏輯正常運作。 逾時值是端對端延遲的元件,不過您無法輕易判斷儲存內容時會執行多少個命令。 您可以藉由設定 DbContext 實例的 CommandTimeout 屬性來變更預設逾時

  • Entity Framework 支援組態檔中定義的重試組態。 不過,為了在 Azure 上取得最大的彈性,您應該考慮在應用程式中以程式設計方式建立組態。 重試原則的特定參數,例如重試次數和重試間隔,可以儲存在服務組態檔中,並在運行時間用來建立適當的原則。 這可讓設定變更,而不需要重新啟動應用程式。

請考慮從下列設定開始重試作業。 您無法指定重試嘗試之間的延遲(它是固定的,併產生為指數序列)。 您只能指定最大值,如下所示:除非您建立自定義重試策略。 這些設定是一般用途,您應該監視作業並微調值,以符合您自己的案例。

內容 範例目標 E2E
最大延遲
重試原則 設定 運作方式
互動式,UI,
或前景
2 秒 指數 MaxRetryCount
MaxDelay
3
750 毫秒
嘗試 1 - 延遲 0 秒
嘗試 2 - 延遲 750 毫秒
嘗試 3 – 延遲 750 毫秒
背景
或批次
30 秒 指數 MaxRetryCount
MaxDelay
5
12 秒
嘗試 1 - 延遲 0 秒
嘗試 2 - 延遲 ~1 秒
嘗試 3 - 延遲 ~3 秒
嘗試 4 - 延遲 ~7 秒
嘗試 5 - 延遲 12 秒

注意

端對端延遲目標會假設服務連線的預設逾時。 如果您指定較長的連線逾時,每次重試嘗試時,端對端延遲將會再延長一次。

範例

下列程式代碼範例會定義使用 Entity Framework 的簡單數據存取解決方案。 它會定義名為 BlogConfiguration 的類別實例,以擴充 DbConfiguration 來設定特定的重試策略。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.SqlServer;
using System.Threading.Tasks;

namespace RetryCodeSamples
{
    public class BlogConfiguration : DbConfiguration
    {
        public BlogConfiguration()
        {
            // Set up the execution strategy for SQL Database (exponential) with 5 retries and 12 sec delay.
            // These values could be loaded from configuration rather than being hard-coded.
            this.SetExecutionStrategy(
                    "System.Data.SqlClient", () => new SqlAzureExecutionStrategy(5, TimeSpan.FromSeconds(12)));
        }
    }

    // Specify the configuration type if more than one has been defined.
    // [DbConfigurationType(typeof(BlogConfiguration))]
    public class BloggingContext : DbContext
    {
        // Definition of content goes here.
    }

    class EF6CodeSamples
    {
        public async static Task Samples()
        {
            // Execution strategy configured by DbConfiguration subclass, discovered automatically or
            // or explicitly indicated through configuration or with an attribute. Default is no retries.
            using (var db = new BloggingContext("Blogs"))
            {
                // Add, edit, delete blog items here, then:
                await db.SaveChangesAsync();
            }
        }
    }
}

如需使用 Entity Framework 重試機制的更多範例,請參閱 連線 復原/重試邏輯

使用 Entity Framework Core SQL 資料庫

Entity Framework Core 是對象關係型對應程式,可讓 .NET Core 開發人員使用領域特定對象來處理數據。 有了 Entity Framework,開發人員便不再需要撰寫大多數必須撰寫的資料存取程式碼。 這個版本的 Entity Framework 是從頭開始撰寫的,而且不會自動繼承 EF6.x 的所有功能。

重試機制

透過稱為連線復原的機制,使用 Entity Framework Core 存取 SQL 資料庫 時,會提供重試支援。 EF Core 1.1.0 引進了 連線 復原功能。

主要抽象概念是 IExecutionStrategy 介面。 SQL Server 的執行策略,包括 SQL Azure,知道可以重試的例外狀況類型,並有合理的預設值,以達到最大重試次數、重試之間的延遲等等。

範例

下列程式代碼會在設定 DbContext 物件時啟用自動重試,此物件代表與資料庫的會話。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EFMiscellaneous.ConnectionResiliency;Trusted_Connection=True;",
            options => options.EnableRetryOnFailure());
}

下列程式代碼示範如何使用執行策略,以自動重試來執行交易。 交易定義在委派中。 如果發生暫時性失敗,執行策略會再叫用委派一次。

using (var db = new BloggingContext())
{
    var strategy = db.Database.CreateExecutionStrategy();

    strategy.Execute(() =>
    {
        using (var transaction = db.Database.BeginTransaction())
        {
            db.Blogs.Add(new Blog { Url = "https://blogs.msdn.com/dotnet" });
            db.SaveChanges();

            db.Blogs.Add(new Blog { Url = "https://blogs.msdn.com/visualstudio" });
            db.SaveChanges();

            transaction.Commit();
        }
    });
}

Azure 儲存體

Azure 儲存體 服務包括 Blob 記憶體、檔案和記憶體佇列。

Blob、佇列和檔案

ClientOptions 類別是所有用戶端選項類型的基底類型,並公開各種常見的用戶端選項,例如診斷、重試、傳輸。 若要提供連線到 Azure 佇列、Blob 和檔案 儲存體 的用戶端組態選項,您必須使用對應的衍生類型。 在下一個範例中,您會使用 QueueClientOptions 類別(衍生自 ClientOptions)來設定用戶端以連線到 Azure 佇列服務。 Retry 屬性是一組選項,可指定以影響重試嘗試的方式,以及如何重試失敗。

using System;
using System.Threading;
using Azure.Core;
using Azure.Identity;
using Azure.Storage;
using Azure.Storage.Queues;
using Azure.Storage.Queues.Models;

namespace RetryCodeSamples
{
    class AzureStorageCodeSamples {

        public async static Task Samples() {

               // Provide the client configuration options for connecting to Azure Queue Storage
                QueueClientOptions queueClientOptions = new QueueClientOptions()
                {
                    Retry = {
                    Delay = TimeSpan.FromSeconds(2),     //The delay between retry attempts for a fixed approach or the delay on which to base
                                                         //calculations for a backoff-based approach
                    MaxRetries = 5,                      //The maximum number of retry attempts before giving up
                    Mode = RetryMode.Exponential,        //The approach to use for calculating retry delays
                    MaxDelay = TimeSpan.FromSeconds(10)  //The maximum permissible delay between retry attempts
                    },

                    GeoRedundantSecondaryUri = new Uri("https://...")
                    // If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for GET or HEAD requests during retries.
                    // If the status of the response from the secondary Uri is a 404, then subsequent retries for the request will not use the
                    // secondary Uri again, as this indicates that the resource may not have propagated there yet.
                    // Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
                };

                Uri queueServiceUri = new Uri("https://storageaccount.queue.core.windows.net/");
                string accountName = "Storage account name";
                string accountKey = "storage account key";

                // Create a client object for the Queue service, including QueueClientOptions.
                QueueServiceClient serviceClient = new QueueServiceClient(queueServiceUri, new DefaultAzureCredential(), queueClientOptions);

                CancellationTokenSource source = new CancellationTokenSource();
                CancellationToken cancellationToken = source.Token;

                // Return an async collection of queues in the storage account.
                var queues = serviceClient.GetQueuesAsync(QueueTraits.None, null, cancellationToken);

數據表支援

注意

WindowsAzure。儲存體 Nuget 套件和 Microsoft.Azure.Cosmos.Table Nuget 套件已被取代。 如需 Azure 數據表支援,請參閱 Azure.Data.Tables Nuget 套件

重試機制

用戶端連結庫是以 Azure Core 連結庫為基礎,這是提供跨領域服務給其他用戶端連結庫的連結庫。

當用戶端應用程式嘗試將網路要求傳送至服務時,可能會發生失敗的原因有很多。 有些範例包括逾時、網路基礎結構失敗、服務因節流/忙碌而拒絕要求、服務實例因服務相應減少而終止、服務實例關閉以另一個版本取代、服務因未處理的例外狀況而當機等。藉由提供內建的重試機制(使用預設設定,取用者可以覆寫),我們的 SDK 和取用者的應用程式就會對這類失敗具有彈性。 請注意,有些服務會針對每個要求收取實際費用,因此,如果取用者想要節省資金而不是復原能力,就應該能夠完全停用重試。

原則設定

重試原則會以程式設計方式設定。 組態是以 RetryOption 類別為基礎。 TableClientOptions 上有繼承自 ClientOptions 的屬性

      var tableClientOptions = new TableClientOptions();
      tableClientOptions.Retry.Mode = RetryMode.Exponential;
      tableClientOptions.Retry.MaxRetries = 5;
      var serviceClient = new TableServiceClient(connectionString, tableClientOptions);

下表顯示內建重試原則的可能性。

RetryOption

設定 意義
Delay 固定方法的重試嘗試之間的延遲,或要針對輪詢型方法進行基礎計算的延遲。 如果服務提供 Retry-After 回應標頭,則下一次重試會延遲標頭值所指定的持續時間。
MaxDelay 當服務未提供 Retry-After 回應標頭時,重試嘗試之間的允許延遲上限。 如果服務提供 Retry-After 回應標頭,則下一次重試會延遲標頭值所指定的持續時間。
模式 用於計算重試延遲的方法。
NetworkTimeout 套用至個別網路作業的逾時。

RetryMode

設定 意義
指數 重試嘗試會根據輪詢策略延遲,其中每次嘗試都會增加重試前等候的持續時間。
MaxDelay 重試嘗試會以固定間隔發生;每個延遲都是一致的持續時間。

遙測

查看記錄的最簡單方式是啟用主控台記錄。 若要建立將訊息輸出至控制台的 Azure SDK 記錄接聽程式,請使用 AzureEventSourceListener.CreateConsoleLogger 方法。

      // Setup a listener to monitor logged events.
      using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();

範例

在記憶體模擬器關機時執行下列程式代碼範例,可讓我們查看控制台中重試的相關信息。

using Azure.Core;
using Azure.Core.Diagnostics;
using Azure.Data.Tables;
using Azure.Data.Tables.Models;

namespace RetryCodeSamples
{
    class AzureStorageCodeSamples
    {
        private const string connectionString = "UseDevelopmentStorage=true";
        private const string tableName = "RetryTestTable";

        public async static Task SamplesAsync()
        {
            // Setup a listener to monitor logged events.
            using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();

            var tableClientOptions = new TableClientOptions();
            tableClientOptions.Retry.Mode = RetryMode.Exponential;
            tableClientOptions.Retry.MaxRetries = 5;

            var serviceClient = new TableServiceClient(connectionString, tableClientOptions);

            TableItem table = await serviceClient.CreateTableIfNotExistsAsync(tableName);
            Console.WriteLine($"The created table's name is {table.Name}.");
        }
    }
}

一般 REST 與重試指引

存取 Azure 或第三方服務時,請考慮下列事項:

  • 使用系統化方法來管理重試,或許作為可重複使用的程式代碼,讓您可以在所有用戶端和所有解決方案中套用一致的方法。

  • 如果目標服務或客戶端沒有內建的重試機制,請考慮使用 Polly 之類的重試架構來管理重試。 這可協助您實作一致的重試行為,而且可能會為目標服務提供適當的預設重試策略。 不過,您可能需要為不依賴例外狀況的服務建立自定義重試程序代碼,以指出暫時性失敗,或者如果您想要使用 Retry-Response 回復來管理重試行為。

  • 暫時性偵測邏輯將取決於您用來叫用 REST 呼叫的實際用戶端 API。 某些用戶端,例如較 新的 HttpClient 類別,不會針對具有非成功 HTTP 狀態代碼的已完成要求擲回例外狀況。

  • 從服務傳回的 HTTP 狀態代碼可協助指出失敗是否為暫時性。 您可能需要檢查用戶端或重試架構所產生的例外狀況,才能存取狀態代碼,或判斷對等的例外狀況類型。 下列 HTTP 程式代碼通常表示重試是適當的:

    • 408 要求逾時
    • 429 要求太多
    • 500 內部伺服器錯誤
    • 502 錯誤的閘道
    • 503 服務無法使用
    • 504 閘道逾時
  • 如果您根據例外狀況來建立重試邏輯,下列通常表示無法建立連線的暫時性失敗:

    • WebExceptionStatus。連線 ionClosed
    • WebExceptionStatus。連線 Failure
    • WebExceptionStatus.Timeout
    • WebExceptionStatus.RequestCanceled
  • 在服務無法使用狀態的情況下,服務可能會在重試后響應標頭或其他自定義標頭中重試之前,指出適當的延遲。 服務也可能以自定義標頭的形式傳送其他資訊,或內嵌在響應的內容中。

  • 請勿重試代表用戶端錯誤的狀態代碼(4xx 範圍內的錯誤),但 408 要求逾時和 429 個要求太多。

  • 在各種條件下徹底測試您的重試策略和機制,例如不同的網路狀態和不同的系統載入。

重試策略

以下是重試策略間隔的一般類型:

  • 指數。 執行指定次數重試的重試原則,使用隨機的指數輪詢方法來判斷重試之間的間隔。 例如:

    var random = new Random();
    
    var delta = (int)((Math.Pow(2.0, currentRetryCount) - 1.0) *
                random.Next((int)(this.deltaBackoff.TotalMilliseconds * 0.8),
                (int)(this.deltaBackoff.TotalMilliseconds * 1.2)));
    var interval = (int)Math.Min(checked(this.minBackoff.TotalMilliseconds + delta),
                    this.maxBackoff.TotalMilliseconds);
    retryInterval = TimeSpan.FromMilliseconds(interval);
    
  • 累加。 重試策略,具有指定次數的重試嘗試和重試之間的累加時間間隔。 例如:

    retryInterval = TimeSpan.FromMilliseconds(this.initialInterval.TotalMilliseconds +
                    (this.increment.TotalMilliseconds * currentRetryCount));
    
  • LinearRetry。 執行指定重試次數的重試原則,使用重試之間的指定固定時間間隔。 例如:

    retryInterval = this.deltaBackoff;
    

使用 Polly 處理暫時性錯誤

Polly 是以程式設計方式處理重試和 斷路器 策略的連結庫。 Polly 專案是 .NET Foundation 的成員。 對於用戶端原生不支援重試的服務,Polly 是有效的替代方法,並避免需要撰寫自定義重試程序代碼,這很難正確實作。 Polly 也提供追蹤錯誤發生時的方法,讓您能夠記錄重試。

下一步