Author: Iqbal Khan
With the rapid growth of high-transaction web apps, service-oriented architecture (SOA), grid computing, and other server applications, traditional data storage often struggles to keep up. The reason is that data storage systems cannot scale out like application architectures that can scale out by adding more servers.
In these situations, in-memory distributed cache offers an excellent solution to data storage bottlenecks. It spans multiple servers in a cluster to pool their memory together and keep the cache synchronized across all nodes. This cluster can scale out indefinitely, just like the application servers. This reduces the load on the underlying data storage, eliminating it as a scalability bottleneck.
There are two main ways people use a distributed cache:
Cache-aside is a very powerful technique and allows you to issue complex database queries involving joins and nested queries, and manipulate data any way you want. Despite that, Read-through / Write-through has various advantages over cache-aside as mentioned below:
Read-through / Write-through is not intended to be used for all data access in your application. It is best suited for situations where you're either reading individual rows from the database or reading data that can directly map to an individual cache item. It is also ideal for reference data that is meant to be kept in the cache for frequent reads, even though this data changes periodically.
A Read-through provider in NCache is a custom class IReadThruProvider in .NET that fetches data from the source (e.g., SQL Server) when not found in cache. NCache calls LoadFromSource automatically. To use it, implement the provider, deploy it using the NCache Management Center or Command Line tool, and enable it in cache settings.
public class SampleReadThruProvider : IReadThruProvider
{
public void Init(IDictionary parameters, string cacheId)
{
// Initialize resources if needed
}
public ProviderCacheItem LoadFromSource(string key)
{
var value = Database.GetData(key);
return new ProviderCacheItem(value);
}
public IDictionary<string, ProviderCacheItem> LoadFromSource(ICollection<string> keys)
{
var result = new Dictionary<string, ProviderCacheItem>();
foreach (string key in keys)
{
result[key] = new ProviderCacheItem(Database.GetData(key));
}
return result;
}
public ProviderDataTypeItem<IEnumerable> LoadDataTypeFromSource(string key, DistributedDataType dataType)
{
ProviderDataTypeItem<IEnumerable> dataTypeItem = null;
switch (dataType)
{
case DistributedDataType.List:
dataTypeItem = new ProviderDataTypeItem<IEnumerable>(
new List<object> { Database.GetData(key) });
break;
case DistributedDataType.Dictionary:
dataTypeItem = new ProviderDataTypeItem<IEnumerable>(
new Dictionary<string, object> { { key, Database.GetData(key) } });
break;
case DistributedDataType.Counter:
dataTypeItem = new ProviderDataTypeItem<IEnumerable>(1000);
break;
}
return dataTypeItem;
}
public void Dispose()
{
// Clean up resources if needed
}
}
Init()
performs certain resource allocation tasks like establishing connections to the main data source, whereas Dispose()
is meant to reset all such allocations.
A Write-Through provider in NCache is a custom class that implements IWriteThruProvider to persist cache updates (add, update, remove) directly to the database whenever the cache is updated.
To use it, implement the interface, deploy it using the provider in NCache Management Center, and enable it in the cache configuration.
public class SampleWriteThruProvider : IWriteThruProvider
{
public void Init(IDictionary parameters, string cacheId)
{
// Initialize resources if needed
}
public void Dispose()
{
// Clean up resources if needed
}
public OperationResult WriteToDataSource(WriteOperation operation)
{
var product = operation.ProviderItem.GetValue<Product>();
switch (operation.OperationType)
{
case WriteOperationType.Add:
// Add product to data source
break;
case WriteOperationType.Update:
// Update product in data source
break;
case WriteOperationType.Delete:
// Delete product from data source
break;
}
return new OperationResult(operation, OperationResult.Status.Success);
}
public ICollection<OperationResult> WriteToDataSource(ICollection<WriteOperation> operations)
{
var results = new List<OperationResult>();
foreach (var op in operations)
results.Add(WriteToDataSource(op));
return results;
}
public ICollection<OperationResult> WriteToDataSource(ICollection<DataTypeWriteOperation> operations)
{
var results = new List<OperationResult>();
foreach (var op in operations)
{
// Handle Create/Add/Delete/Update for data structures
results.Add(new OperationResult(op, OperationResult.Status.Success));
}
return results;
}
}
To learn more about Read-through and Write-through caching, please see the following blogs:
© Copyright Alachisoft 2002 - . All rights reserved. NCache is a registered trademark of Diyatech Corp.