5

Ho un numero piuttosto elevato (30 mln righe, fino a 5-100 KB ciascuna) Tabella su Azure.
Ogni RowKey è un GUID e PartitionKey è una prima parte Guid, ad esempio:Come ridurre la latenza di Archiviazione tabella di Azure?

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

tabella include 600 letture e 600 scritture (aggiornamenti) al secondo con una latenza media di 60ms. Tutte le query utilizzano sia PartitionKey e RowKey.
MA alcune letture richiedono fino a 3000 ms (!). In media, l'1% di tutte le letture richiede più di 500ms e non vi è alcuna correlazione con la dimensione dell'entità (la riga 100Kb può essere restituita in 25ms e 10Kb una - in 1500ms).

La mia applicazione è un sito Web ASP.Net MVC 4 in esecuzione su 4-5 istanze di grandi dimensioni.

Ho letto tutti gli articoli di MSDN per quanto riguarda gli obiettivi di performance Azure Table di stoccaggio e già ha fatto la seguente:

  • UseNagle è spento
  • Expect100Continue è anche disattivato
  • MaxConnections per il cliente tabella è impostato su 250 (impostazione 1000-5000 non ha senso)

Inoltre ho controllato che:

  • contatori di monitoraggio account di archiviazione non presentino errori di limitazione
  • Ci sono una sorta di "onde" in termini di prestazioni, anche se non dipende dal carico

Quale potrebbe essere il motivo di tali problemi di prestazioni e come migliorarlo?

+0

Il tuo account di archiviazione trova nella stessa regione di tuo sito web? –

+0

Per una determinata PartitionKey, approssimativamente quante righe hai? Per le 600 letture e 600 scritture, si verificano all'interno della stessa PartitionKey o sono distribuite su più partizioni? –

+0

@ zain-rizvi, sì, di causa, tra regioni non sarei in grado di ottenere 60ms in media. –

risposta

0

In genere, se una query specifica richiede la scansione di un numero elevato di righe, ci vorrà più tempo. Il comportamento che stai vedendo è specifico per una query/dati? Oppure, stai vedendo le prestazioni varia per gli stessi dati e query?

+0

non c'è alcuna scansione, tutte le query contengono sia PartitionKey che RowKey. Anche le prestazioni non dipendono dalle dimensioni della voce. –

1

Io uso l'impostazione MergeOption.NoTracking sulla proprietà DataServiceContext.MergeOption per prestazioni extra se non ho intenzione di aggiornare l'entità in qualsiasi momento presto. Ecco un esempio:

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

Un altro problema potrebbe essere che si stanno recuperando l'intero enity con tutte le sue proprietà, anche se si ha intenzione di utilizzare solo uno o due proprietà - questo è, naturalmente, uno spreco, ma non può essere facilmente evitato . Tuttavia, se si utilizza Slazure, è possibile utilizzare le proiezioni della query per recuperare solo le proprietà dell'entità a cui si è interessati dalla memoria della tabella e nient'altro, il che consentirebbe prestazioni migliori della query. Ecco un esempio:

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

Full disclosure: Ho codificato Slazure.

Si potrebbe anche prendere in considerazione l'impaginazione, se si recuperano grandi insiemi di dati, ad esempio:

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