0
votes

We are migrating a transaction-processing service which was processing messages from MSMQ and storing transacitons in a SQLServer Database to use the Azure Storage Queue (to store the id's of the messages and placing the actual messages in the Azure Storage Blob).

We should at least be able to process 200.000 messages per hour, but at the moment we barely reach 50.000 messages per hour.

Our application requests batches of 250 messages from the Queue (which now takes about 2 seconds to get the id's from the azure queue and about 5 seconds to get the actual data from the azure blob storage) and we're storing this data in one time into the database using a stored procedure accepting a datatable. Our service also resides in Azure on a virtual machine, and we use the nuget-libraries Azure.Storage.Queues and Azure.Storage.Blobs suggested by Microsoft to access the Azure Storage queue and blob storage.

Does anyone have suggestions how to improve the speed of reading messages from the Azure Queue and then retrieving the data from the Azure Blob?

            var managedIdentity = new ManagedIdentityCredential();

            UriBuilder fullUri = new UriBuilder()
            {
                Scheme = "https",
                Host = string.Format("{0}.queue.core.windows.net",appSettings.StorageAccount),
                Path = string.Format("{0}", appSettings.QueueName),
            };
            queue = new QueueClient(fullUri.Uri, managedIdentity);
            queue.CreateIfNotExists();
            ...
            var result = await queue.ReceiveMessagesAsync(1);
            ...
            UriBuilder fullUri = new UriBuilder()
            {
                Scheme = "https",
                Host =  string.Format("{0}.blob.core.windows.net", storageAccount),
                Path = string.Format("{0}", containerName),
            };

            _blobContainerClient = new BlobContainerClient(fullUri.Uri, managedIdentity);
            _blobContainerClient.CreateIfNotExists();
            ...


        public async Task<BlobMessage> GetBlobByNameAsync(string blobName)
        {
            Ensure.That(blobName).IsNotNullOrEmpty();

            var blobClient = _blobContainerClient.GetBlobClient(blobName);
            if (!blobClient.Exists())
            {
                _log.Error($"Blob {blobName} not found.");
                throw new InfrastructureException($"Blob {blobName} not found.");
            }

            BlobDownloadInfo download = await blobClient.DownloadAsync();
            return new BlobMessage
                {
                    BlobName = blobClient.Name,
                    BaseStream = download.Content,
                    Content = await GetBlobContentAsync(download)
                };
        }

Thanks,

Vincent.

1
Provided some suggestions based on the code you shared. HTH.Gaurav Mantri

1 Answers

0
votes

Based on the code you posted, I can suggest two improvements:

  1. Receive 32 messages at a time instead of 1: Currently you're getting just one message at a time (var result = await queue.ReceiveMessagesAsync(1);). You can receive a maximum of 32 messages from the top of the queue. Just change the code to var result = await queue.ReceiveMessagesAsync(32); to get 32 messages. This will save you 31 trips to storage service and that should lead to some performance improvements.

  2. Don't try to create blob container every time: Currently you're trying to create a blob container every time you process a message (_blobContainerClient.CreateIfNotExists();). It is really unnecessary. With fetching 32 messages, you're reducing this method call by 31 times however you can just move this code to your application startup so that you only call it once during your application lifecycle.