2012-10-05 24 views
9

Tabloya test verilerini ekleyen basit WorkerRole yazarım. Eklerin kodu böyle.Azure depolama tablolarıyla saniyede daha fazla 10 ekleme nasıl yapılır

var TableClient = this.StorageAccount.CreateCloudTableClient(); 
TableClient.CreateTableIfNotExist(TableName); 
var Context = TableClient.GetDataServiceContext(); 

this.Context.AddObject(TableName, obj); 
this.Context.SaveChanges(); 

Bu kod, her istemci isteği için çalışır. 1-30 istemci iş parçacığıyla test yapıyorum. Çeşitli boyutlarda çeşitli örnek sayısıyla birçok trys var. Neyi yanlış yaptığımı bilmiyorum ama saniyede 10 eke ulaşamıyorum. Hız nasıl artırılacağını bilen biri varsa lütfen bana haber verin. Teşekkür

GÜNCELLEME

  • CreateTableIfNotExist öldürmesi benim ekler testler için fark does't.
  • Bekleme modunda bekletme100Continue = "false" kullanımıNagleAlgorithm = "false", hız atlamayı 30-40 ips'ye eklerken kısa bir süre etkisi yapar. Ancak, 30 saniye sonra ekleme oranı% 50 zaman aşımına sahip 6 ips'ye düşer. (+

    foreach (var item in myItemsToAdd) 
    { 
        this.Context.AddObject(TableName, item); 
    } 
    this.Context.SaveChanges(SaveChangesOptions.Batch); 
    

    Sen Partitioner.Create ile bu birleştirebilirsiniz AsParallel: Eğer tek bir istek içinde 100 öğe işlemek için izin, toplu işlemleri (Varlık Grup İşlemleri) kullanmalıdır İşleri hızlandırmak için

+1

Bu mantığın tümünü bir döngüde CreateTableIfNotExist() ile çağırıyor musunuz? ya da sadece bir döngü içinde Add/SaveChanges()? CreateTableIfNotExist() ucuz bir çağrı değildir ve gerekmiyorsa atlamak istersiniz – Igorek

+0

Bu kod her istek için çalışır. Sen her zaman CreateTableIfNotExist çağırmak için pahalı pahalı haklısın. Bunu kaldırmaya çalışacağım ve sadece tablo hata yoksa. – gabba

cevap

29

) çok hızlı şeyler yapmak için 100 öğeden oluşan grup başına farklı thread/çekirdeklere birden fazla istek göndermek.

Ancak tüm bunları yapmadan önce, toplu işlemlerin kullanıldığı read through the limitations (100 öğe, işlem başına 1 bölüm, ...).

Güncelleme:

burada işlemleri kullanamazsınız diğer bazı ipuçları beri. Tablo depolamayı kullanırken performansı iyileştirmek için this MSDN thread'a bir göz atın.

private static void SequentialInserts(CloudTableClient client) 
    { 
     var context = client.GetDataServiceContext(); 
     Trace.WriteLine("Starting sequential inserts."); 

     var stopwatch = new Stopwatch(); 
     stopwatch.Start(); 

     for (int i = 0; i < 1000; i++) 
     { 
      Trace.WriteLine(String.Format("Adding item {0}. Thread ID: {1}", i, Thread.CurrentThread.ManagedThreadId)); 
      context.AddObject(TABLENAME, new MyEntity() 
      { 
       Date = DateTime.UtcNow, 
       PartitionKey = "Test", 
       RowKey = Guid.NewGuid().ToString(), 
       Text = String.Format("Item {0} - {1}", i, Guid.NewGuid().ToString()) 
      }); 
      context.SaveChanges(); 
     } 

     stopwatch.Stop(); 
     Trace.WriteLine("Done in: " + stopwatch.Elapsed.ToString()); 
    } 

Yani, bu ilk çalıştırdığınızda aşağıdaki çıktıyı almak: 1000 öğeler eklemek için en fazla 3 dakika sürer

Starting sequential inserts. 
Adding item 0. Thread ID: 10 
Adding item 1. Thread ID: 10 
.. 
Adding item 999. Thread ID: 10 
Done in: 00:03:39.9675521 

Sana farkı göstermek için bazı kodlar yazdım.

Starting sequential inserts. 
Adding item 0. Thread ID: 10 
Adding item 1. Thread ID: 10 
.. 
Adding item 999. Thread ID: 10 
Done in: 00:00:18.9342480 
:
<system.net> 
    <settings> 
     <servicePointManager expect100Continue="false" useNagleAlgorithm="false"/> 
    </settings> 
    <connectionManagement> 
     <add address = "*" maxconnection = "48" /> 
    </connectionManagement> 
    </system.net> 

Ve uygulamayı çalıştırdıktan sonra

yine sonuç alırsınız: Şimdi, MSDN forumunda ipuçlarını temel app.config değiştirdi (çekirdek CPU sayısı * maxconnection 12 olmalı)

3 dakikadan 18 saniyeye kadar. Ne fark! Ama daha iyisini yapabiliriz. İşte bazı kod, bir bölümleyici kullanarak tüm öğeleri ekler edilir (eklemeler paralel olur):

private static void ParallelInserts(CloudTableClient client) 
    {    
     Trace.WriteLine("Starting parallel inserts."); 

     var stopwatch = new Stopwatch(); 
     stopwatch.Start(); 

     var partitioner = Partitioner.Create(0, 1000, 10); 
     var options = new ParallelOptions { MaxDegreeOfParallelism = 8 }; 

     Parallel.ForEach(partitioner, options, range => 
     { 
      var context = client.GetDataServiceContext(); 
      for (int i = range.Item1; i < range.Item2; i++) 
      { 
       Trace.WriteLine(String.Format("Adding item {0}. Thread ID: {1}", i, Thread.CurrentThread.ManagedThreadId)); 
       context.AddObject(TABLENAME, new MyEntity() 
       { 
        Date = DateTime.UtcNow, 
        PartitionKey = "Test", 
        RowKey = Guid.NewGuid().ToString(), 
        Text = String.Format("Item {0} - {1}", i, Guid.NewGuid().ToString()) 
       }); 
       context.SaveChanges(); 
      } 
     }); 

     stopwatch.Stop(); 
     Trace.WriteLine("Done in: " + stopwatch.Elapsed.ToString()); 
    } 

Ve sonuç:

Starting parallel inserts. 
Adding item 0. Thread ID: 10 
Adding item 10. Thread ID: 18 
Adding item 999. Thread ID: 16 
.. 
Done in: 00:00:04.6041978 

Voila, biz 18s düştü ve şimdi bile düştü 3m39s gelen 4s.

+0

Ayrıca, paralel işlem için 500tps'ye kadar destek verebilen tek bir tablo geçişi olarak tavsiye ederim. Yani muhtemelen vurmak gerçekten 75-100ms yapabilirsiniz gerçek ekleme üzerindeki gecikme (bu nedenle gördüğünüz her saniye başına 10 performans). – BrentDaCodeMonkey

+0

Ayrıca grup işlemlerinin hızını ölçmeye çalıştım. Benim durumumda, elemanların başına 3 kat daha hızlı. Fakat maalesef davamda tek bir işlemde reqest'leri gruplayamıyorum. – gabba

+0

BrentDaCodeMonkey, açıklayabilir misiniz "paralel işlem" demek? Örneğimdeki kod, istemci isteklerine tepki veriyor. Farklı sayıda iş parçacığı ile istekleri simüle ediyorum. – gabba

İlgili konular