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

Asp.net mvc 如何减少Azure表存储延迟?,asp.net-mvc,azure,azure-storage,azure-web-app-service,azure-table-storage,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次写入(更新),平均延迟为60ms。所有查询都使用PartitionKey和RowKey 但是,有些阅读需要高达3000ms的时间。平均而言,超过1%的读取

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

PartitionKey = "1bbe3d4b"
RowKey = "1bbe3d4b-2230-4b4f-8f5f-fe5fe1d4d006"
表每秒有600次读取和600次写入(更新),平均延迟为60ms。所有查询都使用
PartitionKey
RowKey

但是,有些阅读需要高达3000ms的时间。平均而言,超过1%的读取时间超过500ms,并且与实体大小无关(100Kb行可能在25ms内返回,10Kb行可能在1500ms内返回)

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

我已经阅读了所有有关Azure Table Storage性能目标的MSDN文章,并且已经做了以下工作:

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

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

出现这种性能问题的原因是什么?如何改进?

通常,如果特定查询需要扫描大量行,则需要更长的时间。您看到的行为是特定的查询/数据吗?或者,您是否看到相同数据和查询的性能有所不同?

如果我不打算在短期内更新实体,我会使用属性上的设置来提高性能。以下是一个例子:

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();
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;
        }
    }
}
另一个问题可能是,您正在检索整个enity及其所有属性,即使您只打算使用一个或两个属性-这当然是浪费,但不容易避免。但是,如果使用,则可以使用查询投影仅从表存储中检索您感兴趣的实体属性,仅此而已,这将提高查询性能。以下是一个例子:

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();
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;
        }
    }
}

您的存储帐户是否与您的网站位于同一地区?对于给定的PartitionKey,您大约有多少行?对于600次读取和600次写入,它们是发生在同一个分区密钥内还是分布在多个分区上?@zain rizvi,是的,当然,在区域之间,我无法平均获得60毫秒。@rick rainey,读取/写入是随机分布在分区之间的。每个分区有1-5行,每秒读取不超过1-5次。根本不进行扫描,所有查询同时包含PartitionKey和RowKey。性能也不取决于入口大小。