Skip to content

Instantly share code, notes, and snippets.

@joelverhagen
Last active October 17, 2023 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelverhagen/8394b3eaa276f4baa07806867b5caa37 to your computer and use it in GitHub Desktop.
Save joelverhagen/8394b3eaa276f4baa07806867b5caa37 to your computer and use it in GitHub Desktop.
Performance test for in-memory Azurite
Method Mean Error StdDev
InMemory_Blob 1,860.0 us 25.45 us 21.25 us
InMemory_Queue 1,562.3 us 26.89 us 25.15 us
InMemory_Table 975.7 us 8.65 us 7.23 us
Disk_Blob 5,505.8 us 91.37 us 89.74 us
Disk_Queue 5,327.1 us 104.47 us 111.78 us
Disk_Table 963.6 us 11.34 us 9.47 us
using Azure.Data.Tables;
using Azure.Storage.Blobs;
using Azure.Storage.Queues;
using Azure.Storage.Queues.Models;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Extensions;
using System.Diagnostics;
using System.Net;
using System.Text;
// var summary = BenchmarkRunner.Run<AzuriteInMemoryVsDisk>();
var test = new AzuriteInMemoryVsDisk();
await test.InMemory_Setup();
var blobData = new byte[64 * 1024 * 1024]; // 64 MiB
try
{
var blobServiceClient = new BlobServiceClient("UseDevelopmentStorage=true");
var blobContainer = blobServiceClient.GetBlobContainerClient("testcontainer");
await blobContainer.CreateIfNotExistsAsync();
using var process = Process.GetProcessesByName("node").OrderByDescending(x => x.StartTime).First();
var instanceName = GetProcessInstanceName(process.Id);
using var counter = new PerformanceCounter("Process", "Working Set - Private", instanceName);
var i = 0;
long total = 0;
while (true)
{
var blob = blobContainer.GetBlobClient($"blob{i:D6}.dat");
total += blobData.Length;
Console.Write($"Uploading 64 MiB to {blob.Name}...");
var sw = Stopwatch.StartNew();
await blob.UploadAsync(new MemoryStream(blobData));
sw.Stop();
var memory = Convert.ToInt64(counter.NextValue());
Console.WriteLine($" done in {sw.ElapsedMilliseconds}ms. [node process: {memory / (1024.0 * 1024 * 1024):0.00} GiB, uploaded: {total / (1024.0 * 1024 * 1024):0.00} GiB]");
i++;
}
}
finally
{
test.InMemory_Cleanup();
}
// Source: https://stackoverflow.com/a/9115662
static string GetProcessInstanceName(int pid)
{
PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
string[] instances = cat.GetInstanceNames();
foreach (string instance in instances)
{
using (PerformanceCounter cnt = new PerformanceCounter("Process",
"ID Process", instance, true))
{
int val = (int)cnt.RawValue;
if (val == pid)
{
return instance;
}
}
}
throw new Exception("Could not find performance counter " +
"instance name for current process. This is truly strange ...");
}
public class AzuriteInMemoryVsDisk
{
private static readonly byte[] Data = Encoding.UTF8.GetBytes(new string('a', 8 * 1024));
private Process? _azuriteProcess;
private BlobServiceClient? _blobServiceClient;
private BlobContainerClient? _blobContainer;
private QueueServiceClient? _queueServiceClient;
private QueueClient? _queue;
private TableServiceClient? _tableServiceClient;
private TableClient? _table;
private async Task InitializeAzuriteAsync(string[] arguments)
{
await StartAzuriteAsync(arguments);
await InitializeClientsAsync();
}
private async Task InitializeClientsAsync()
{
var connectionString = "UseDevelopmentStorage=true";
_blobServiceClient = new BlobServiceClient(connectionString);
_blobContainer = _blobServiceClient.GetBlobContainerClient("testcontainer");
await _blobContainer.CreateIfNotExistsAsync();
_queueServiceClient = new QueueServiceClient(connectionString);
_queue = _queueServiceClient.GetQueueClient("testqueue");
await _queue.CreateIfNotExistsAsync();
_tableServiceClient = new TableServiceClient(connectionString);
_table = _tableServiceClient.GetTableClient("testtable");
await _table.CreateIfNotExistsAsync();
}
private async Task StartAzuriteAsync(string[] arguments)
{
try
{
_azuriteProcess = new Process
{
StartInfo =
{
WorkingDirectory = @"C:\z\Git\joelverhagen\Azurite\",
FileName = "npm",
ArgumentList = { "run", "azurite", "--" },
UseShellExecute = true,
},
};
foreach (var arg in arguments)
{
_azuriteProcess.StartInfo.ArgumentList.Add(arg);
}
Console.WriteLine("Starting Azurite...");
_azuriteProcess.Start();
var sw = Stopwatch.StartNew();
using var httpClient = new HttpClient();
while (sw.Elapsed < TimeSpan.FromSeconds(30))
{
await Task.Delay(TimeSpan.FromSeconds(1));
var ready = true;
foreach (var port in Enumerable.Range(10000, 3))
{
using var request = new HttpRequestMessage(HttpMethod.Head, $"http://127.0.0.1:{port}/");
try
{
using var response = await httpClient.SendAsync(request);
if (response.StatusCode != HttpStatusCode.BadRequest)
{
response.EnsureSuccessStatusCode();
}
Console.WriteLine($"Port {port} is ready.");
}
catch
{
Console.WriteLine($"Port {port} is not ready yet.");
ready = false;
break;
}
}
if (ready)
{
break;
}
}
}
catch
{
try
{
_azuriteProcess?.Kill(entireProcessTree: true);
}
catch
{
// best effort
}
throw;
}
}
private void CleanupAzurite()
{
_azuriteProcess?.KillTree();
}
[GlobalSetup(Targets = new[] { nameof(InMemory_Blob), nameof(InMemory_Queue), nameof(InMemory_Table) })]
public async Task InMemory_Setup()
{
var arguments = new[] { "--inMemoryPersistence", "--silent" };
await InitializeAzuriteAsync(arguments);
}
[GlobalCleanup(Targets = new[] { nameof(InMemory_Blob), nameof(InMemory_Queue), nameof(InMemory_Table) })]
public void InMemory_Cleanup()
{
CleanupAzurite();
}
[GlobalSetup(Targets = new[] { nameof(Disk_Blob), nameof(Disk_Queue), nameof(Disk_Table) })]
public async Task Disk_Setup()
{
var arguments = new[] { "--silent" };
await InitializeAzuriteAsync(arguments);
}
[GlobalCleanup(Targets = new[] { nameof(Disk_Blob), nameof(Disk_Queue), nameof(Disk_Table) })]
public void Disk_Cleanup()
{
CleanupAzurite();
}
[Benchmark]
public async Task InMemory_Blob()
{
await Blob();
}
[Benchmark]
public async Task InMemory_Queue()
{
await Queue();
}
[Benchmark]
public async Task InMemory_Table()
{
await Table();
}
[Benchmark]
public async Task Disk_Blob()
{
await Blob();
}
[Benchmark]
public async Task Disk_Queue()
{
await Queue();
}
[Benchmark]
public async Task Disk_Table()
{
await Table();
}
private async Task Blob()
{
var blob = _blobContainer!.GetBlobClient("testblob");
await blob.UploadAsync(new BinaryData(Data), overwrite: true);
await blob.SetMetadataAsync(new Dictionary<string, string> { { "foo", "bar" } });
await blob.DeleteAsync();
}
private async Task Queue()
{
await _queue!.SendMessageAsync(new BinaryData(Data));
QueueMessage message = await _queue.ReceiveMessageAsync();
await _queue.DeleteMessageAsync(message.MessageId, message.PopReceipt);
}
private async Task Table()
{
var entity = new TableEntity("pk", "rk");
entity["Data"] = Data;
await _table!.UpsertEntityAsync(entity);
var results = _table.QueryAsync<TableEntity>(x => x.PartitionKey == "pk");
await foreach (var x in results)
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment