分散キャッシュでのリードスルーとライトスルーの使用

著者:イクバルカーン

非常に高トランザクションの Web アプリ、SOA、グリッド コンピューティング、その他のサーバー アプリケーションが爆発的に増加しているため、データ ストレージが追いつきません。 その理由は、非常にスケーラブルなアプリケーション アーキテクチャとは異なり、データ ストレージではスケールアウトするためにサーバーを追加し続けることができないためです。

このような状況では、インメモリ分散キャッシュは、データ ストレージのボトルネックに対する優れた解決策を提供します。 複数のサーバー (クラスターと呼ばれます) にまたがってメモリをプールし、すべてのキャッシュをサーバー間で同期させます。 そして、アプリケーション サーバーと同様に、このキャッシュ クラスターを際限なく成長させ続けることができます。 これにより、データ ストレージへの負担が軽減され、スケーラビリティのボトルネックではなくなります。

分散キャッシュを使用する主な方法は XNUMX つあります。

  • キャッシュアサイド: ここでは、アプリケーションがデータベースの読み取りと書き込みを担当し、キャッシュはデータベースとまったく対話しません。 キャッシュは、より高速でスケーラブルなメモリ内データ ストアとして「保管」されます。 アプリケーションはデータベースから何かを読み取る前にキャッシュをチェックします。 また、アプリケーションはデータベースを更新した後にキャッシュを更新します。 このようにして、アプリケーションは次のことを保証します。 キャッシュはデータベースと同期されます。.
  • リードスルー/ライトスルー (RT/WT): ここで、アプリケーションはキャッシュをメイン データ ストアとして扱い、 そこからデータを読み取り、そこにデータを書き込みます。 キャッシュは、このデータをデータベースに読み書きする責任を負い、それによってアプリケーションがこの責任を軽減します。
リードスルー/ライトスルー キャッシング アーキテクチャ
図 1: リードスルー/ライトスルー キャッシュ アーキテクチャ

キャッシュアサイドに対するリードスルーとライトスルーの利点

キャッシュアサイドは非常に強力な手法であり、結合やネストされたクエリを含む複雑なデータベース クエリを発行し、任意の方法でデータを操作できるようになります。 それにもかかわらず、 リードスルー / ライトスルー 以下で説明するように、キャッシュアサイドに比べてさまざまな利点があります。

  • アプリケーションコードを簡素化します。 キャッシュ アサイド アプローチでは、アプリケーション コードは引き続き複雑になり、データベースに直接依存し、複数のアプリケーションが同じデータを処理する場合はコードが重複することもあります。 リードスルー/ライトスルーは、データ アクセス コードの一部をアプリケーションからキャッシュ層に移動します。 これにより、アプリケーションが大幅に簡素化され、データベースがさらに明確に抽象化されます。
  • リードスルーによる読み取りのスケーラビリティの向上: という状況がたくさんあります。 キャッシュアイテムの有効期限が切れます そして複数の並列ユーザー スレッドがデータベースにアクセスすることになります。 これに数百万のキャッシュされたアイテムと数千の並列ユーザー リクエストを掛け合わせると、データベースの負荷は著しく高くなります。 ただし、リードスルーは、データベースから最新のコピーをフェッチしている間、cache-item をキャッシュ内に保持します。 次に、キャッシュ項目を更新します。 その結果、アプリケーションはこれらのキャッシュ項目を求めてデータベースにアクセスすることがなくなり、データベースの負荷が最小限に抑えられます。
  • ライトビハインドによる書き込みパフォーマンスの向上: キャッシュアサイドでは、アプリケーションはデータベースを直接同期的に更新します。一方、 後書き これにより、アプリケーションはキャッシュを迅速に更新して復帰できるようになります。 次に、キャッシュがバックグラウンドでデータベースを更新できるようにします。
  • ライトビハインドによるデータベースのスケーラビリティの向上: ライトビハインドを使用すると、データベースの書き込みがキャッシュの更新ほど速く実行されないようにスロットル制限を指定できるため、データベースへの負担が少なくなります。 さらに、負荷を最小限に抑えるために、オフピーク時間帯にデータベースへの書き込みが行われるようにスケジュールすることもできます。
  • 期限切れ時にキャッシュを自動更新: リードスルー 有効期限が切れたときに、キャッシュがデータベースからオブジェクトを自動的に再ロードできるようにします。 これは、最新のデータが常にキャッシュ内にあるため、アプリケーションがピーク時にデータベースにアクセスする必要がないことを意味します。
  • データベース変更時のキャッシュの自動更新: リードスルーを使用すると、データベース内の対応するデータが変更されたときに、キャッシュがデータベースからオブジェクトを自動的に再ロードできます。 これは、キャッシュが常に最新であり、最新のデータが常にキャッシュ内にあるため、アプリケーションがピーク時にデータベースにアクセスする必要がないことを意味します。

リードスルー/ライトスルーは、アプリケーション内のすべてのデータ アクセスに使用することを目的としたものではありません。 これは、データベースから個々の行を読み取る場合、または個々のキャッシュ項目に直接マップできるデータを読み取る場合に最適です。 また、データが定期的に変更される場合でも、頻繁な読み取りのためにキャッシュに保持される参照データにも最適です。

リードスルーハンドラーの開発

リードスルー ハンドラーはキャッシュ サーバーに登録されており、キャッシュがデータベースからデータを直接読み取ることができるようになります。 の 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);
        
        ...
    }
}

次はどうする?

お問い合わせ(英語)

電話
©著作権 Alachisoft 2002 - . All rights reserved. NCache はダイヤテック株式会社の登録商標です。