作者:伊克巴尔汗
随着极高事务 Web 应用程序、SOA、网格计算和其他服务器应用程序的爆炸式增长,数据存储无法跟上。 原因是数据存储不能不断添加更多服务器来横向扩展,这与高度可扩展的应用程序架构不同。
在这些情况下,内存中分布式缓存为数据存储瓶颈提供了出色的解决方案。 它跨越多个服务器(称为集群)以将它们的内存集中在一起并保持所有缓存在服务器之间同步。 而且,它可以像应用服务器一样不断地增长这个缓存集群。 这减少了数据存储的压力,使其不再是可扩展性瓶颈。
人们使用分布式缓存有两种主要方式:
Cache-aside 是一种非常强大的技术,它允许您发出涉及连接和嵌套查询的复杂数据库查询,并以您想要的任何方式操作数据。 尽管那样, 通读 / 直写 与 cache-aside 相比具有多种优势,如下所述:
Read-through/Write-through 并不打算用于应用程序中的所有数据访问。 它最适合您从数据库中读取单个行或读取可以直接映射到单个缓存项的数据的情况。 它也非常适合用于保存在缓存中以供频繁读取的参考数据,即使这些数据会定期更改。
通读处理程序向缓存服务器注册,并允许缓存直接从数据库中读取数据。 这 NCache server 提供了一个需要实现的 Read-through 处理程序接口。 这使 NCache 调用您的通读处理程序。
public class SqlReadThruProvider : IReadThruProvider
{
private SqlConnection _connection;
// Called upon startup to initialize connection
public void Init(IDictionary parameters, string cacheId)
{
_connection = new SqlConnection(parameters["connstring"]);
_connection.Open();
}
// Called at the end to close connection
public void Dispose()
{
_connection.Close();
}
// Responsible for loading object from external data source
public ProviderCacheItem LoadFromSource(string key)
{
string sql = "SELECT * FROM Customers WHERE ";
sql += "CustomerID = @ID";
SqlCommand cmd = new SqlCommand(sql, _connection);
cmd.Parameters.Add("@ID", System.Data.SqlDbType.VarChar);
// Let's extract actual customerID from "key"
int keyFormatLen = "Customers:CustomerID:".Length;
string custId = key.Substring(keyFormatLen,
key.Length - keyFormatLen);
cmd.Parameters["@ID"].Value = custId;
// fetch the row in the table
SqlDataReader reader = cmd.ExecuteReader();
Customers customer = new Customers();
// copy data from "reader" to "cust" object
FillCustomers(reader, customer);
ProviderCacheItem cacheItem = new ProviderCacheItem(customer);
// specify a SqlCacheDependency for this object
CacheDependency dep = new SqlCacheDependency(_connection.ToString(), cmd.ToString());
cacheItem.Dependency = dep;
return cacheItem;
}
Init()
执行某些资源分配任务,例如建立与主数据源的连接,而 Dispose()
旨在重置所有此类分配。 LoadFromSource()
是缓存调用以读取对象的内容。
当缓存更新时缓存需要写入数据库时,将调用直写处理程序。 通常,应用程序通过添加、插入或删除向缓存发出更新。
public class SqlWriteThruProvider : IWriteThruProvider
{
private SqlConnection _connection;
// Called upon startup to initialize connection
public void Init(IDictionary parameters, string cacheId)
{
_connection = new SqlConnection((string)parameters["connstring"]);
_connection.Open();
}
// Called at the end to close connection
public void Dispose()
{
_connection.Close();
}
public OperationResult WriteToDataSource(WriteOperation operation)
{
int rowsChanged = 0;
OperationResult result = new OperationResult(operation, OperationResult.Status.Failure);
ProviderCacheItem cacheItem = operation.ProviderItem;
Customers cust = cacheItem.GetValue<Customers>();
string[] customer = {cust.Id,cust.ContactName,cust.CompanyName,
cust.Address,cust.City, cust.Country,cust.PostalCode,
cust.Phone,cust.Fax};
SqlCommand cmd = _connection.CreateCommand();
cmd.CommandText = String.Format(CultureInfo.InvariantCulture,
"Update dbo.Customers " + "Set CustomerID='{0}'," +
"ContactName='{1}',CompanyName='{2}'," +
"Address='{3}',City='{4}'," +
"Country='{5}',PostalCode='{6}'," +
"Phone='{7}',Fax='{8}'" +
"Where CustomerID = '{0}'", customer);
rowsChanged = cmd.ExecuteNonQuery();
if (rowsChanged > 0)
{
result.OperationStatus = OperationResult.Status.Success;
return result;
}
return result;
}
}
Init()
执行资源分配任务,例如建立与数据源的连接,而 Dispose()
旨在重置所有此类分配。 Save 是缓存调用直写对象的方法。
下面的示例代码展示了如何在一个简单的 Windows 应用程序中使用缓存的读取/写入功能
using Alachisoft.NCache.Client;
...
internal class MainForm : System.Windows.Forms.Form
{
/// Fetches record from the cache, which internally accesses the
/// datasource using read-thru provider
private void OnClickFind(object sender, System.EventArgs e)
{
Customer customer;
Cache cache = NCache.Caches[CacheName];
string key = cboCustomerID.Text.Trim();
string providerName = cboReadThruProvider.Text;
customer = (Customer) cache.Get(key,
providerName,
DSReadOption.ReadThru);
...
}
/// Updates the record using the cache, which internally accesses
/// the datasource using write-thru provider
private void OnClickUpdate(object sender, System.EventArgs e)
{
Cache cache = NCache.Caches[CacheName];
Customer customer = new Customer();
...
string key = customer.CustomerID;
string providerName = cboWriteThruProvider.Text;
cache.Insert(key, new CacheItem(customer), DSWriteOption.WriteThru, providerName, null);
...
}
}