使用 Azure 地理冗余 (RA-GRS) 表存储时,如何更新 ASP.NET Core 中的 TableServiceClient 以指向次要区域?

Posted

技术标签:

【中文标题】使用 Azure 地理冗余 (RA-GRS) 表存储时,如何更新 ASP.NET Core 中的 TableServiceClient 以指向次要区域?【英文标题】:How do you update TableServiceClient in ASP.NET Core, to point to a secondary region, when using Azure geo redundant (RA-GRS) table storage? 【发布时间】:2022-01-18 17:33:54 【问题描述】:

我正在使用最新的 Azure.Data.Tables nuget 包,版本 12.3.0 连接到 ASP.NET Core C# 应用程序中的 Azure 表存储。

如果主要区域发生故障,我的应用程序需要故障转移到次要区域以进行读取

目前TableServiceClient的设置是在Startup.cs中完成的,如下:

public void ConfigureServices(IServiceCollection services)
     
   services.AddSingleton(new TableServiceClient(new Uri("PrimaryRegionConnectionURL"), new DefaultAzureCredential()));

如何使用指向次要区域的实例更新TableServiceClient 的当前实例?有没有更好的方法来实现这种故障转移?

只是为了澄清: 我知道客户端不支持故障转移,并且团队已经创建了一张票以在将来查看此功能。 我意识到我需要一个 TableServiceClient 的新实例。

我只是不确定在失败时如何用指向辅助实例的新实例替换启动时创建的实例

这是使用TableServiceClient的代码

    public class TableRepository : ITableStorageRepository

    readonly TableServiceClient _serviceClient;

    public TableRepository(TableServiceClient serviceClient)
    
        _serviceClient = serviceClient;
    

    public async Task<ICollection<T>> GetPartitionEntities<T>(string partitionKey, string tableName)
        where T : class, ITableEntity, new()
    
        var listOfEntities = new List<T>();

        var tableClient = _serviceClient.GetTableClient(tableName);

        var queryResults = tableClient.QueryAsync<T>(filter => filter.PartitionKey == partitionKey);

        await foreach (var row in queryResults) 
        
            listOfEntities.Add(row);
        

        return listOfEntities;
    

【问题讨论】:

您使用的 SDK 是什么? @GauravMantri 我正在使用一个 nuget 包 Azure.Data.Tables,它是此处找到的 azure-sdk-for-net 的一部分:github.com/Azure/azure-sdk-for-net 【参考方案1】:

不确定这是否是实现它的最佳方式,但考虑到我必须自己处理在主要和次要端点之间切换的逻辑,我会这样做。

首先,我会创建两个 TableServiceClient 实例 - 一个用于主实例,另一个用于辅助实例。

public void ConfigureServices(IServiceCollection services)
  
    Dictionary<string, TableServiceClient> tableServiceClients = new Dictionary()
    
      "Primary",  new TableServiceClient(new Uri("PrimaryRegionConnectionURL"), new DefaultAzureCredential()),
      "Secondary",  new TableServiceClient(new Uri("SecondaryRegionConnectionURL"), new DefaultAzureCredential())
    
    services.AddSingleton(tableServiceClients);

接下来,我将提取用于在单独函数中获取实体的逻辑并将客户端传递给该函数(我们称之为GetPartitionEntitiesImpl)。

然后在GetPartitionEntities 方法中,我会尝试从主端点获取实体并捕获异常。如果异常表明主端点失败,我会再次调用GetPartitionEntitiesImpl 函数并尝试从辅助端点获取实体。

public class TableRepository : ITableStorageRepository

    readonly TableServiceClient _primaryServiceClient, _secondaryServiceClient;

    public TableRepository(Dictionary<string, TableServiceClient> tableServiceClients)
    
        _primaryServiceClient = tableServiceClients["Primary"];
        _secondaryServiceClient = tableServiceClients["Secondary"];
    

    public async Task<ICollection<T>> GetPartitionEntities<T>(string partitionKey, string tableName)
        where T : class, ITableEntity, new()
    
        try
        
            return await GetPartitionEntitiesImpl(_primaryServiceClient, partitionKey, tableName);
        
        catch (Exception exception)
        
          //Check if there is a need for failover
          if (shouldTrySecondaryEndpoint)
          
              return await GetPartitionEntitiesImpl(_secondaryServiceClient, partitionKey, tableName);
          
        
    

    private async Task<ICollection<T>> GetPartitionEntitiesImpl<T>(TableServiceClient serviceClient, string partitionKey, string tableName)
        where T : class, ITableEntity, new()
    
        var listOfEntities = new List<T>();

        var tableClient = serviceClient.GetTableClient(tableName);

        var queryResults = tableClient.QueryAsync<T>(filter => filter.PartitionKey == partitionKey);

        await foreach (var row in queryResults) 
        
            listOfEntities.Add(row);
        

        return listOfEntities;
    


另外,请查看旧版 Azure 存储 SDK(版本 9.x)的代码,了解在主端点和辅助端点之间切换的逻辑。该 SDK 可以很好地处理这种情况。

【讨论】:

感谢您的解决方案,我认为这给了我一个良好的开端,非常感谢。【参考方案2】:

目前不支持使用同一客户端的自动故障转移;要使用次要区域,需要单独的TableServiceClient。此处提供更多上下文:https://github.com/Azure/azure-sdk-for-net/issues/25456

这里正在跟踪添加支持的工作:https://github.com/Azure/azure-sdk-for-net/issues/25710

【讨论】:

嗨 Jesse,我知道客户端不支持此功能,并意识到我需要一个新的 TableServiceClient 实例。我只是不确定如何将启动时创建的替换为失败时指向辅助实例的新实例。感谢您的回复。 嗨,杰西,我已经更新了问题以尝试使其更清晰,并感谢团队跟踪我的故障转移问题。 您能否编辑您的问题并在您使用 TableServiceClient 的位置包含代码? @GauravMantri 该代码与 nuget 包和版本一样在原始帖子中 您在配置依赖项的位置包含了代码。我对查看注入此依赖项的代码更感兴趣。很明显,至少到目前为止,您将需要 2 个不同的 TableServiceClient 实例 - 一个指向主端点,另一个指向辅助端点。

以上是关于使用 Azure 地理冗余 (RA-GRS) 表存储时,如何更新 ASP.NET Core 中的 TableServiceClient 以指向次要区域?的主要内容,如果未能解决你的问题,请参考以下文章

Azure 表存储备份

Azure VM Disk最佳实践

Azure VM Disk最佳实践

为啥 Azure 资源组与特定区域相关联?

Azure *** 专用 IP 冗余

C# 适用于 Azure 表存储上的地理数据的类型