Azure 服務的重試指引

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

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

下列資料表摘要說明本指引中所述的 Azure 服務重試功能。

服務 重試功能 原則組態 Scope 遙測功能
Microsoft Entra ID MSAL 程式庫中的原生 內嵌至 MSAL 程式庫 內部
Azure Cosmos DB 服務中的原生 不可設定 全球 TraceSource
Data Lake Store 用戶端中的原生: 不可設定 個別作業
事件中樞 用戶端中的原生: 程式設計 用戶端
IoT 中樞 用戶端 SDK 中的原生: 程式設計 用戶端
Azure Cache for Redis 用戶端中的原生: 程式設計 用戶端 TextWriter
Search 用戶端中的原生: 程式設計 用戶端 Windows 事件追蹤 (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 識別碼是一套結合核心目錄服務、進階身分識別治理和應用程式存取權管理的全方位、身分識別與存取權管理雲端解決方案。 Microsoft Entra 識別碼也為開發人員提供身分識別管理平台,以根據集中化原則和規則,提供應用程式的存取控制。

注意

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

重試機制

Microsoft 驗證程式庫有 Microsoft Entra 識別碼適用的內建重試機制。 為了避免非預期的鎖定,我們建議協力廠商程式庫和應用程式程式代碼不要重試失敗的連線,但允許 MSAL 處理重試。

重試使用指引

使用 Microsoft Entra 識別碼時,請考慮下列指引:

  • 可能的話,請使用 MSAL 程式庫和重試的內建支援。
  • 如果您使用 REST API 進行 Microsoft Entra 識別碼,請在結果碼為 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 Storage Gen2 使 Azure 儲存體成為在 Azure 上構建企業資料湖的基礎。 Data Lake Storage Gen2 可讓您輕鬆管理大量資料。

Azure 儲存體檔案資料湖用戶端程式庫內含的功能可讓開發人員、資料科學家以及分析師的工作更加輕鬆,包括可儲存任何大小、形狀及速度的資料,以及跨各平台和語言進行任何類型的處理及分析。

重試機制

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

遙測

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

儲存體帳戶的所有遙測資料都可透過 Azure 監視器的 Azure 儲存體記錄取得。 這項功能會整合您的儲存體帳戶與記錄分析和事件中樞,同時讓您將記錄封存至另一個儲存體帳戶。 若要查看計量和資源記錄及其相關結構描述的完整清單,請參閱 Azure 儲存體監視資料參考

事件中樞

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

重試機制

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

範例

EventHubClient client = EventHubClient.CreateWithManagedIdentity(new Uri("sb://full_namespace_url", "entity_path");
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 用戶端會使用透過一組選項設定的連接管理員類別,包括:

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

原則設定

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

內建類別支援具有隨機重試間隔的線性 (常數) 延遲和指數輪詢。 您也可以實作 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);

或者,您可以將選項指定為字串,並將此選項傳遞至 Connect 方法。 只有透過程式碼,才能以這種方式設定 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 組態

下列資料表顯示了內建重試原則的預設設定。

內容 設定 預設值
(v 1.2.2)
意義
ConfigurationOptions ConnectRetry

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 內的重試行為受到 Retry 屬性中的 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 用來取代個別選項值的自訂重試原則。
延遲 0.8 秒鐘 固定方法的重試嘗試之間的延遲,或要針對輪詢型方法進行基礎計算的延遲。
MaxDelay 60 秒鐘 重試嘗試之間允許的延遲上限。
MaxRetries 3 在考慮相關聯的作業失敗之前,重試嘗試的次數上限。
[模式] 指數 用於計算重試延遲的方法。
TryTimeout 60 秒鐘 等候完成單一嘗試的持續時間上限,無論是初始嘗試還是重試。

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

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

範例:

using Azure.Identity;
using Azure.Messaging.ServiceBus;

string namespace = "<namespace>";
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(namespace, new DefaultAzureCredential(), options);

遙測

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

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

範例

下列程式碼範例示範如何使用 Azure.Messaging.ServiceBus 套件至:

  • 使用新的 ServiceBusClientOptions 設定適用 ServiceBusClient 的重試原則。
  • 使用 ServiceBusMessage 的新執行個體建立新訊息。
  • 使用 ServiceBusSender.SendMessageAsync(message) 方法將訊息傳送至服務匯流排。
  • 使用 ServiceBusReceiver 接收,其會以 ServiceBusReceivedMessage 物件呈現。
using Azure.Identity;
using Azure.Messaging.ServiceBus;

string namespace = "<namespace>";
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(namespace, new DefaultAzureCredential(), 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 Cluster 中散發可靠的服務,可避免發生本文中所討論的大部分潛在暫時性錯誤。 不過,仍可能發生一些暫時性錯誤。 例如,命名服務可能會在取得要求時處於路線規劃變更之中,導致它擲回例外狀況。 如果相同的要求在 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 資料庫,可在各種大小和標準 (共用) 和進階 (非共用) 服務中使用。

重試機制

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

您可以使用 Polly 程式庫來實作 SQL 資料庫的重試。 有關更多資訊,請參閱使用 Polly 處理暫時性錯誤

重試使用指引

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

  • 選擇適當的服務選項 (共用或進階版)。 共用執行個體可能會收到共用伺服器的其他租用戶使用量影響,而遭受比平常更長的連線延遲和節流時間。 如果需要更可預測的效能和可靠的低延遲作業,請考慮選擇進階選項。
  • 請確定您在適當的層級或範圍執行重試,以避免非等冪作業導致資料不一致。 在理想情況下,所有作業都應該是等冪的,因此可以重複執行,而不會造成不一致。 如果案例並非如此,則在一個作業失敗時,重試應該於層級或範圍執行,以允許復原所有相關變更,例如,在交易範圍內執行。 如需詳細資訊,請參閱雲端服務基本概念資料存取層 – 暫時性錯誤處理
  • 不建議使用固定間隔策略來搭配 Azure SQL 資料庫,除了在短間隔內只有少數重試的互動式案例之外。 相反地,請考慮對大部分案例使用指數輪詢策略。
  • 在定義連接時,選擇適當的連接值和命令逾時。 逾時太短可能會在資料庫忙碌時導致連線過早失敗。 逾時時間過長,可能會讓重試邏輯在偵測失敗的連線之前等候太久,而無法正常運作。 逾時的值是端對端延遲的元件,它會針對每次重試嘗試有效地新增至重試原則中指定的重試延遲。
  • 在一些重試之後關閉連接,就算使用指數輪詢重試邏輯也一樣,並在新連接上重試作業。 在同一個連接上多次重試相同的作業,可能是導致連線問題的因素。 如需這項技術的範例,請參閱雲端服務基本概念資料存取層 – 暫時性錯誤處理
  • 當連接集區正在使用中時 (預設值) 時,即使關閉並重新開啟連線後,也有可能從集區選擇相同的連接。 如果是這樣,解決的技巧是呼叫 SqlConnection 類別的 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 資料庫。

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

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 資料庫 (自動):不重試,但會檢查例外狀況,並加上建議,以使用 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());

您可以使用 DbConfigurtionTypea 屬性來標註內容類別,以指定內容的重試組態類別。 不過,如果您只有一個組態類別,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 的執行策略,包括 Azure SQL,可掌握例外狀況類型,並有合理的預設值,以達到最大重試次數、重試之間的延遲等等。

範例

下列程式碼會在設定 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.Storage 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("<endpoint>", new DefaultAzureCredential(), tableClientOptions);

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

RetryOption

設定 意義
延遲 固定方法的重試嘗試之間的延遲,或要針對輪詢型方法進行基礎計算的延遲。 如果服務提供了 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;
using Azure.Identity;

namespace RetryCodeSamples
{
    class AzureStorageCodeSamples
    {
        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("<endpoint>", new DefaultAzureCredential(), 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.ConnectionClosed
    • WebExceptionStatus.ConnectFailure
    • WebExceptionStatus.Timeout
    • WebExceptionStatus.RequestCanceled
  • 在服務為無法使用狀態的案例下,服務可能會在 Retry-After 回應標頭中或其他自訂標頭中重試之前,指出適當的延遲。 服務也可能以自訂標頭的形式傳送其他資訊,或內嵌在回應的內容中。

  • 請勿重試代表用戶端錯誤的狀態碼 (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 也提供追蹤錯誤發生時機的方法,讓您能夠記錄重試。

下一步