5

Ho da qualche parte nelle vicinanze di 4,2 milioni di immagini ho bisogno di spostarmi dagli Stati Uniti centro-nord a Stati Uniti occidentali, come parte di una migrazione di grandi dimensioni per sfruttare il supporto di Azure VM (per quelli che non lo sanno, gli Stati Uniti del Nord Centrale non li sostengono). Le immagini sono tutte in un unico contenitore, suddivise in circa 119.000 directory.Spostamento di milioni di elementi da un account di archiviazione a un altro

sto utilizzando la seguente dal API Copia Blob:

public static void CopyBlobDirectory(
     CloudBlobDirectory srcDirectory, 
     CloudBlobContainer destContainer) 
{ 
    // get the SAS token to use for all blobs 
    string blobToken = srcDirectory.Container.GetSharedAccessSignature(
     new SharedAccessBlobPolicy 
     { 
      Permissions = SharedAccessBlobPermissions.Read | 
          SharedAccessBlobPermissions.Write, 
      SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromDays(14) 
     }); 

    var srcBlobList = srcDirectory.ListBlobs(
     useFlatBlobListing: true, 
     blobListingDetails: BlobListingDetails.None).ToList(); 

    foreach (var src in srcBlobList) 
    { 
     var srcBlob = src as ICloudBlob; 

     // Create appropriate destination blob type to match the source blob 
     ICloudBlob destBlob; 
     if (srcBlob.Properties.BlobType == BlobType.BlockBlob) 
      destBlob = destContainer.GetBlockBlobReference(srcBlob.Name); 
     else 
      destBlob = destContainer.GetPageBlobReference(srcBlob.Name); 

     // copy using src blob as SAS 
     destBlob.BeginStartCopyFromBlob(new Uri(srcBlob.Uri.AbsoluteUri + blobToken), null, null);   
    } 
} 

Il problema è che è troppo lento. Waaaay troppo lento. Alla velocità che sta impiegando per emettere comandi per copiare tutte queste cose, ci vorranno da qualche parte nel vicinato di quattro giorni. Non sono veramente sicuro di quale sia il collo di bottiglia (lato del client del limite di connessione, limitazione della velocità su Azure, multithreading, ecc.).

Quindi, mi chiedo quali sono le mie opzioni. C'è un modo per velocizzare le cose o sono semplicemente bloccato con un lavoro che richiederà quattro giorni per essere completato?

Edit: Come sto distribuendo il lavoro per copiare tutto

//set up tracing 
InitTracer(); 

//grab a set of photos to benchmark this 
var photos = PhotoHelper.GetAllPhotos().Take(500).ToList(); 

//account to copy from 
var from = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
    "oldAccount", 
    "oldAccountKey"); 
var fromAcct = new CloudStorageAccount(from, true); 
var fromClient = fromAcct.CreateCloudBlobClient(); 
var fromContainer = fromClient.GetContainerReference("userphotos"); 

//account to copy to 
var to = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
    "newAccount", 
    "newAccountKey"); 
var toAcct = new CloudStorageAccount(to, true); 
var toClient = toAcct.CreateCloudBlobClient(); 

Trace.WriteLine("Starting Copy: " + DateTime.UtcNow.ToString()); 

//enumerate sub directories, then move them to blob storage 
//note: it doesn't care how high I set the Parallelism to, 
//console output indicates it won't run more than five or so at a time 
var plo = new ParallelOptions { MaxDegreeOfParallelism = 10 }; 
Parallel.ForEach(photos, plo, (info) => 
{ 
    CloudBlobDirectory fromDir = fromContainer.GetDirectoryReference(info.BuildingId.ToString()); 

    var toContainer = toClient.GetContainerReference(info.Id.ToString()); 
    toContainer.CreateIfNotExists(); 

    Trace.WriteLine(info.BuildingId + ": Starting copy, " + info.Photos.Length + " photos..."); 

    BlobHelper.CopyBlobDirectory(fromDir, toContainer, info); 
    //this monitors the container, so I can restart any failed 
    //copies if something goes wrong 
    BlobHelper.MonitorCopy(toContainer); 
}); 

Trace.WriteLine("Done: " + DateTime.UtcNow.ToString()); 
+0

Stai utilizzando molti thread per farlo? Il più delle volte è nella copia. Potresti parallelizzarlo enormemente, penso. Forse con un sacco di ruoli di lavoro in azzurro. –

+0

Ho avuto lo stesso pensiero; inizialmente stavo eseguendo tutto in modo sincrono. Dopo alcuni test, ci sarebbero voluti quasi due settimane, quindi l'ho riscritto per utilizzare BeginStartCopyFromBlob() e ho avvolto le chiamate su CopyBlobDirectory() in Parallel.ForEach.Tuttavia, il framework Parallel rifiuta di farmi eseguire più di 5 lavori in una volta (anche se ho impostato un grado più alto); Non sono sicuro di come costringerlo a correre di più. – Dusda

+0

Puoi semplicemente generare molti thread come questo: http://stackoverflow.com/questions/5041153/how-to-create-multiple-threads-in-windows-azure-worker-role, dici 1000 per istanza di lavoro e poi far girare qualche dozzina di ruoli dei lavoratori? –

risposta

1

Questo è un po 'di un colpo lungo, ma ho avuto un problema simile con memorizzazione delle tabelle per cui piccole richieste (che penso BeginStartCopyFromBlob dovrebbe essere) avviato con estrema lentezza. È un problema con Nagle's Algorithm e delayed TCP acks, due ottimizzazioni per il traffico di rete. Vedere MSDN o this guy per ulteriori dettagli.

Upshot - disattivare l'algoritmo di Nagle - chiamare il seguente prima di eseguendo qualsiasi operazione di archiviazione di Azure.

ServicePointManager.UseNagleAlgorithm = false; 

o solo per blob:

var storageAccount = CloudStorageAccount.Parse(connectionString); 
ServicePoint blobServicePoint = ServicePointManager.FindServicePoint(account.BlobEndpoint); 
blobServicePoint.UseNagleAlgorithm = false; 

sarebbe bello sapere se questo è il tuo problema!

+0

Provare questo; sembra aver dato un colpo di adrenalina finora :) – Dusda

+0

Ricorda che l'operazione di copia non trasferisce i dati tra la memoria e l'istanza di calcolo; questo è storage-to-storage, copia asincrona. L'unico miglioramento che vedrai, disattivando Nagle in questo caso, è la velocità con cui ogni singolo comando di copia viene inviato/completato. Questo dovrebbe consentire di inviare comandi più rapidamente. –

+0

Sì, va bene. Il problema iniziale era capire perché ci fosse voluto così tanto tempo per inviare anche le richieste. Sapresti per quanto tempo occorrerà che Azure esegua effettivamente le copie BLOB? Dì, un gruppo di 1.000 BLOB? – Dusda

2

L'operazione di copia blob asincrona sarà molto veloce all'interno dello stesso centro dati (recentemente ho copiato un VHD da 30 GB in un altro BLOB in circa 1-2 secondi). Attraverso i data center, l'operazione viene messa in coda e avviene attraverso capacità di riserva senza SLA (vedi this article che lo chiama in modo specifico)

Per mettere questo in prospettiva: ho copiato lo stesso VHD da 30 GB tra i data center e ci sono voluti circa 1 ora.

Non conosco le dimensioni dell'immagine, ma supponendo una dimensione media dell'immagine di 500 K, si osservano circa 2000 GB. Nel mio esempio, ho visto un throughput di 30 GB in circa un'ora. Estrapolando, stimerei i tuoi 2000 GB di dati in circa (2000/30) = 60 ore. Di nuovo, niente SLA. Solo una supposizione

Qualcun altro ha suggerito di disabilitare l'algoritmo di Nagle. Questo dovrebbe aiutare a spingere i 4 milioni di comandi di copia più velocemente e farli accodare più velocemente. Non penso che avrà alcun effetto sul tempo di copia.