asp.net-mvc - 如何减少Azure表存储延迟?

标签 asp.net-mvc azure azure-storage azure-web-app-service azure-table-storage

我在 Azure 上有一个相当大的表(3000 万行,每行最多 5-100Kb)。
每个 RowKey 都是一个 Guid,PartitionKey 是第一个 Guid 部分,例如:

PartitionKey = "1bbe3d4b"
RowKey = "1bbe3d4b-2230-4b4f-8f5f-fe5fe1d4d006"

表每秒有 600 次读取和 600 次写入(更新),平均延迟为 60 毫秒。所有查询都使用 PartitionKeyRowKey
但是,某些读取需要长达 3000 毫秒(!)。平均而言,>1% 的读取需要超过 500 毫秒,并且与实体大小没有相关性(100Kb 行可能在 25 毫秒内返回,10Kb 行可能在 1500 毫秒内返回)。

我的应用程序是一个在 4-5 个大型实例上运行的 ASP.Net MVC 4 网站。

我已阅读所有有关 Azure 表存储性能目标的 MSDN 文章,并已执行以下操作:

  • UseNagle 已关闭
  • Expect100Continue 也被禁用
  • 表客户端的MaxConnections 设置为 250(设置 1000–5000 没有任何意义)

我还检查了:

  • 存储帐户监控计数器没有限制错误
  • 性能存在某种“波动”,尽管它们不依赖于负载

造成此类性能问题的原因是什么以及如何改进?

最佳答案

我使用MergeOption.NoTracking DataServiceContext.MergeOption 上的设置如果我不打算很快更新实体,则可以使用属性来获得额外的性能。这是一个例子:

var account = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));
var tableStorageServiceContext = new AzureTableStorageServiceContext(account.TableEndpoint.ToString(), account.Credentials);
tableStorageServiceContext.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
tableStorageServiceContext.MergeOption = MergeOption.NoTracking;
tableStorageServiceContext.AddObject(AzureTableStorageServiceContext.CloudLogEntityName, newItem);
tableStorageServiceContext.SaveChangesWithRetries();

另一个问题可能是您正在检索整个实体及其所有属性,即使您只想使用一两个属性 - 这当然是浪费,但无法轻易避免。但是,如果您使用 Slazure那么您可以使用查询投影仅从表存储中检索您感兴趣的实体属性,仅此而已,这将为您提供更好的查询性能。这是一个例子:

using SysSurge.Slazure;
using SysSurge.Slazure.Linq;
using SysSurge.Slazure.Linq.QueryParser;

namespace TableOperations
{
    public class MemberInfo
    {
        public string GetRichMembers()
        {
            // Get a reference to the table storage
            dynamic storage = new QueryableStorage<DynEntity>("UseDevelopmentStorage=true");

            // Build table query and make sure it only return members that earn more than $60k/yr
            // by using a "Where" query filter, and make sure that only the "Name" and 
            // "Salary" entity properties are retrieved from the table storage to make the
            // query quicker.   
            QueryableTable<DynEntity> membersTable = storage.WebsiteMembers;
            var memberQuery = membersTable.Where("Salary > 60000").Select("new(Name, Salary)");

            var result = "";

            // Cast the query result to a dynamic so that we can get access its dynamic properties
            foreach (dynamic member in memberQuery)
            {
                // Show some information about the member
                result += "LINQ query result: Name=" + member.Name + ", Salary=" + member.Salary + "<br>";
            }

            return result;
        }
    }
}

全面披露:我编写了 Slazure 代码。

如果您要检索大型数据集,您还可以考虑分页,例如:

// Retrieve 50 members but also skip the first 50 members
var memberQuery = membersTable.Where("Salary > 60000").Take(50).Skip(50);

关于asp.net-mvc - 如何减少Azure表存储延迟?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32077723/

相关文章:

c# - 如何在辅助角色中使用 WCF 进行批量插入

azure - 如何横向扩展 Azure 存储队列

c# - 在 ASP.NET Web API 2 中,ByteRangeStreamContent 在与来自 Azure 存储的流一起使用时返回不正确的数据

c# - 如何在.NET 中读取包含 Unicode 的 xml 文本文件,然后将其保存到数据库中?

c# - mvc4 actionlink 传递变量

asp.net-mvc - 如何在 Azure 上已托管的 Web API 旁边添加 MVC 项目?

asp.net-mvc - 对未经身份验证的用户和 AJAX 调用的不同响应

azure - 在sql azure中更改外部表

asp.net - 配置 Azure Web 角色以在启动时启动应用程序域

asp.net-mvc - session 状态在 Global.asax 的 AcquireRequestState 或 PostAcquireRequestState 事件中不可用