2012-10-05 14 views
9

Escribo WorkerRole simple que agrega datos de prueba en la tabla. El código de insertos es así.Cómo obtener más 10 inserciones por segundo con tablas de almacenamiento azur

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

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

Este código se ejecuta para cada solicitud de cliente. Yo pruebo con 1-30 hilos de clientes. Tengo muchas pruebas con varios recuentos de instancias de varios tamaños. No sé lo que hago mal, pero no puedo llegar a más de 10 inserciones por segundo. Si alguien sabe cómo aumentar la velocidad, por favor avíseme. Gracias

ACTUALIZACIÓN

  • la eliminación de CreateTableIfNotExist does't hacer diferencia para mis pruebas insertos.
  • modo de conmutación a expect100Continue = "false" useNagleAlgorithm = "false" hace efecto a corto plazo cuando la tasa de inserción salta a 30-40 ips. Pero luego, después de 30 segundos, el índice de inserción cae a 6 ips con un 50% de tiempo de espera.
+1

¿Está llamando por casualidad toda esa lógica con CreateTableIfNotExist() en un bucle? o solo Add/SaveChanges() en un bucle? CreateTableIfNotExist() no es una llamada barata y desea omitirla si no es necesaria – Igorek

+0

Este código se ejecuta para cada solicitud. Tienes razón, es caro llamar a CreateTableIfNotExist en cualquier momento. Intentaré eliminarlo y lo haré solo si la tabla no existe error. – gabba

Respuesta

29

Para acelerar las cosas que usted debe utilizar las operaciones en bloque (Transacciones grupo de entidades), lo que le permite comprometerse hasta 100 artículos dentro de una única solicitud:

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

Esto se puede combinar con Partitioner.Create (+ AsParallel) para enviar solicitudes múltiples en diferentes hilos/núcleos por lote de 100 elementos para hacer las cosas realmente rápido.

Pero antes de hacer todo esto, read through the limitations de usar transacciones por lotes (100 elementos, 1 partición por transacción, ...).

Actualización:

Dado que no se puede utilizar transacciones Éstos son algunos otros consejos. Eche un vistazo a this MSDN thread para mejorar el rendimiento al usar el almacenamiento de tablas. Escribí algo de código para mostrar la diferencia:

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

Así, la primera vez que ejecute esta me da el siguiente resultado:

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 

Se tarda más de 3 minutos y añadir artículos 1000. Ahora, he cambiado el app.config en función de las extremidades en el foro de MSDN (maxconnection debe ser de 12 * número de núcleos de CPU):

<system.net> 
    <settings> 
     <servicePointManager expect100Continue="false" useNagleAlgorithm="false"/> 
    </settings> 
    <connectionManagement> 
     <add address = "*" maxconnection = "48" /> 
    </connectionManagement> 
    </system.net> 

Y después de ejecutar la aplicación de nuevo me sale esta salida:

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 

De más de 3 minutos a 18 segundos. ¡Que diferencia! Pero podemos hacerlo aún mejor. Aquí hay un código inserta todos los elementos usando una Partitioner (inserciones sucederán en paralelo):

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

Y el resultado:

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, de 3m39s que cayó a 18 años y ahora incluso caer a 4s.

+0

También recomendaría la operación en paralelo, ya que una tabla única puede soportar hasta 500tps. Entonces, lo que probablemente está golpeando es la latencia en la inserción real que puede fácilmente 75-100ms (de ahí el rendimiento de 10 por segundo que está viendo). – BrentDaCodeMonkey

+0

También intenté medir la velocidad de las operaciones grupales. En mi caso, es 3 veces más rápido que las inserciones por elemento. Pero desafortunadamente en mi caso no puedo agrupar los requisitos en una transacción. – gabba

+0

BrentDaCodeMonkey, ¿podría explicarme qué quiere decir "operación en paralelo"? El código en mi ejemplo reacciona en los requerimientos del cliente. Simulo requerimientos con varios conteos de hilos. – gabba

Cuestiones relacionadas