著者:イクバルカーン
非常に高トランザクションの Web アプリ、SOA、グリッド コンピューティング、その他のサーバー アプリケーションが爆発的に増加しているため、データ ストレージが追いつきません。 その理由は、非常にスケーラブルなアプリケーション アーキテクチャとは異なり、データ ストレージではスケールアウトするためにサーバーを追加し続けることができないためです。
このような状況では、インメモリ分散キャッシュは、データ ストレージのボトルネックに対する優れた解決策を提供します。 複数のサーバー (クラスターと呼ばれます) にまたがってメモリをプールし、すべてのキャッシュをサーバー間で同期させます。 そして、アプリケーション サーバーと同様に、このキャッシュ クラスターを際限なく成長させ続けることができます。 これにより、データ ストレージへの負担が軽減され、スケーラビリティのボトルネックではなくなります。
分散キャッシュを使用する主な方法は XNUMX つあります。
キャッシュアサイドは非常に強力な手法であり、結合やネストされたクエリを含む複雑なデータベース クエリを発行し、任意の方法でデータを操作できるようになります。 それにもかかわらず、 リードスルー / ライトスルー 以下で説明するように、キャッシュアサイドに比べてさまざまな利点があります。
リードスルー/ライトスルーは、アプリケーション内のすべてのデータ アクセスに使用することを目的としたものではありません。 これは、データベースから個々の行を読み取る場合、または個々のキャッシュ項目に直接マップできるデータを読み取る場合に最適です。 また、データが定期的に変更される場合でも、頻繁な読み取りのためにキャッシュに保持される参照データにも最適です。
リードスルー ハンドラーはキャッシュ サーバーに登録されており、キャッシュがデータベースからデータを直接読み取ることができるようになります。 の NCache サーバーは、実装する必要があるリードスルー ハンドラー インターフェイスを提供します。 これにより、 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);
...
}
}