After doing some research, I am still unsure how best to maintain a 'connection' to Azure Table Storage. Should CloudTableClient
or CloudTable
instances be reused across requests?
We are using Table Storage behind a public, high-traffic API. We require high read availability and performance. All queries are POINT queries (both partition key and row key are available) and the response payment is small in size (less than 1 kilobyte). Write performance is not a big concern. Each request on the API could read up to 10 point queries across a few partitions.
From my reading, I have understood the following:
CloudTableClient
is not thread-safe and should be created for every transaction. Apparently this shouldn't hamper performance when being recreated continuously.
A CloudTable
instance will thus also have to be created for each transaction.
Are these the correct assumptions to make?
I am thus reinitialising CloudTableClient
and CloudTable
for every request. It feels wasteful.
See implementation:
public class EntityStorageComponent : IEntityComponent
{
private CloudStorageAccount storageAccount;
public CloudTable Table
{
get
{
var tableClient = storageAccount.CreateCloudTableClient();
ServicePoint tableServicePoint = ServicePointManager.FindServicePoint(storageAccount.TableEndpoint);
tableServicePoint.UseNagleAlgorithm = false;
tableServicePoint.ConnectionLimit = 100;
var context = new OperationContext();
context.Retrying += (sender, args) =>
{
Debug.WriteLine("Retry policy activated");
};
// Attempt delays: ~200ms, ~200ms, ~200ms
var requestOptions = new TableRequestOptions
{
RetryPolicy = = new LinearRetry(TimeSpan.FromMilliseconds(200), 3),
MaximumExecutionTime = TimeSpan.FromSeconds(60)
};
var table = tableClient.GetTableReference("farematrix");
table.CreateIfNotExists(requestOptions, context);
return table;
}
}
public EntityStorageComponent(IOptions<ConfigurationOptions> options)
{
storageAccount = CloudStorageAccount.Parse(options.Value.TableStorageConnectionString);
}
public SomeEntity Find(Guid partitionKey, Guid rowKey)
{
var retrieveOperation = TableOperation.Retrieve<SomeEntity>(partitionKey, rowKey);
var retrievedResult = Table.Execute(retrieveOperation);
return retrievedResult.Result as SomeEntity;
}
}
An entity has a primary key and a set of properties. A property is a name, typed-value pair, similar to a column. The Table service does not enforce any schema for tables, so two entities in the same table may have different sets of properties.
An entity in Azure Storage can be up to 1MB in size. An entity in Azure Cosmos DB can be up to 2MB in size. Properties: A property is a name-value pair. Each entity can include up to 252 properties to store data.
Azure Table Storage supports a single region with an optional read-only secondary region for availability. Cosmos DB supports distribution from 1 to more than 30 regions with automatic failovers worldwide. You can easily manage this from the Azure portal and define the failover behavior.
A RowKey in Table Storage is a very simple thing: it's your “primary key” within a partition. PartitionKey + RowKey form the composite unique identifier for an entity. Within one PartitionKey, you can only have unique RowKeys. If you use multiple partitions, the same RowKey can be reused in every partition.
Apart from the usual overhead of creating an object, I don't see any issue in creating multiple instances of CloudTableClient
and CloudTable
objects. So if you're simply doing the following, I don't think you're going to get hit performance wise:
var tableClient = storageAccount.CreateCloudTableClient();
var table = tableClient.GetTableReference("farematrix");
However I do see an issue with the way you're creating CloudTable
in your code (Table
member). Essentially in your code, anytime you get the Table
property from EntityStorageComponent
, you're trying to create a table in your storage account.
var table = tableClient.GetTableReference("farematrix");
table.CreateIfNotExists(requestOptions, context);
This is a problem because table.CreateIfNotExists(requestOptions, context);
will make a network call and would slow down your system considerably. You may want to move out table.CreateIfNotExists(requestOptions, context);
code and put that in your startup code so that you're always sure (mostly) that the table is present.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With