キャッシュ項目のバージョン管理によるロック (楽観的ロック)
一方、 悲観的なロック これは非常に役立つアプローチですが、その使用には制限があり、アイテムに対して少なくとも XNUMX つの操作が完全に実行されない限り、アイテムは使用できません。 これは、アイテムに対して XNUMX つのタスクが完全に実行されるまで、アイテムはロックされたままになることを意味します。 これにより、項目が長時間ロックされたままになると、スレッドの枯渇が発生する可能性があります。
Note
この機能は以下でも利用できます NCache Professional.
ここで楽観的ロックが役に立ちます。 NCache キャッシュアイテムのバージョン管理を使用します。 CacheItemVersion
は、すべてのキャッシュ項目に関連付けられたプロパティです。 これはキャッシュされた項目のバージョンを表す数値であり、項目が更新されるたびに XNUMX ずつ増加します。 このプロパティを使用すると、項目に変更が発生したかどうかを追跡できます。 キャッシュから項目をフェッチすると、キャッシュ内のその現在のバージョンもフェッチされます。
読み取り中心のアプリケーションの場合は、悲観的ロックよりも楽観的ロックが優先されます。
オプティミスティックロックを使用する場合
前の例では、2 人のユーザーが同時に 1 つの銀行口座を使用していました。 ユーザーの 1 人が銀行口座で入金トランザクションを実行するためにロックを取得したとします。 User2 は、UserXNUMX が出金トランザクションを行うためにロックを解放するのを待っています。 ロックを解除しないと、ネットワーク接続の問題により UserXNUMX が不安定な状態になると考えてください。 ユーザー XNUMX は、接続の問題を何も知らずにロックが解除されるのを待ち続けるため、最初のユーザーがロックを解除するまで飢餓状態になります。
この種の問題を回避するには、オプティミスティック ロックが便利な解決策です。 この種類のロックを使用すると、User1 がアカウントを更新したい場合、ロックせずにアカウントを更新でき、それに応じてアイテムのバージョンが更新されます。 これで、User2 がデータを更新したい場合、アイテムのバージョンに基づいて更新されたバージョンが取得されるため、データの整合性の問題は発生しません。 ユーザーが古いアイテム バージョンのデータを操作すると、アイテムのバージョンが古いとみなされ、操作は失敗します。
CacheItemVersion
を使用してアプリケーションの開発にさらなる次元を追加します。 NCache。 オプティミスティックな同時実行性は、次のようにしてアプリケーションで実現できます。 NCache アイテムのバージョン管理。
アイテムがキャッシュに追加されると、キャッシュ アイテムのバージョンがキャッシュ クライアントに返されます。 この値は、特定のデータに対して実行された更新の数を示します。 更新するたびに、アイテムのバージョンの値が増加します。
前提条件
アイテムのバージョンを取得してアイテムを更新する
An Add 操作は CacheItemVersion
。 項目が初めて追加される場合、その作成時のタイムスタンプを含む長い値が返されます。 今後このキーに対して操作を実行すると、このバージョンは「1」ずつ増加します。
楽観的ロックにより、ユーザーは常にキャッシュからアイテムの最新のコピーを取得できます。 ユーザーが古いバージョンで機能を実行し続けると、 NCache ユーザーがキャッシュから更新されたアイテムを取得できるように、例外をスローします。
以下の例では、キャッシュは複数のアプリケーションによって使用されています。 キャッシュには製品のデータが含まれています。 A CacheItem
キャッシュに追加されます。 どちらのアプリケーションも、現在のバージョン、つまりバージョンで項目を取得します。 Application1 は、 商品名 次に、アイテムをキャッシュに再挿入します。これにより、アイテムのアイテム バージョンが新しいバージョンに更新されます。 アプリケーション 2 にはバージョンの項目がまだあります。 Application2 が品目の在庫単位を更新し、その品目をキャッシュに再挿入すると、挿入は失敗します。 Application2 は、操作を実行するために更新されたバージョンをフェッチする必要があります。 CacheItem
.
Note
両方を使用してキャッシュにアイテムを追加できます Add or インセット 方法。
-
Add
このメソッドは、新しいアイテムをキャッシュに追加し、アイテムのバージョンを初めて保存します。
-
Insert
メソッドは、アイテムがまだ存在しない場合はキャッシュに追加しますが、既存の時間の値を上書きし、アイテムのバージョンを更新します。
次のコードセクションでは、アプリケーションによって実行される操作について説明します。
// Precondition: Cache is already connected
// An item is added in the cache with itemVersion
// Specify the key of the cacheItem
string key = "Product:1001";
// Initialize the cacheItemVersion
CacheItemVersion version = null;
// Get the cacheItem previously added in the cache with the version
CacheItem cacheItem = cache.GetCacheItem(key, ref version);
// If result is not null
if (cacheitem != null)
{
// CacheItem is retrieved successfully with the version
// If result is Product type
var prod = new Product();
prod = cacheItem.GetValue<Product>();
prod.UnitsInStock++;
// Create a new cacheItem with updated value
var updateItem = new CacheItem(prod);
//Set the itemversion. This version will be used to compare the
// item version of cached item
updateItem.Version = version;
cache.Insert(key, updateItem);
// If it matches, the insert will be successful, otherwise it will fail
}
else
{
// Item could not be retrieved due to outdated CacheItemVersion
}
// Precondition: Cache is already connected
// An item is added in the cache with itemVersion
// Specify the key of the cacheItem
String key = "Product:1001";
// Initialize the cacheItemVersion
CacheItemVersion version = new CacheItemVersion();
// readThruOptions set to null
CacheItem cacheItem = cache.getCacheItem(key, version, null);
// If result is not null
if (cacheItem != null)
{
var prod = new Product();
prod = cacheItem.getValue(Product.Class);
prod.unitsInStock++;
// Update the retrieved cacheitem according to requirement
// Create a new cacheItem with updated value
CacheItem updatedItem = new CacheItem(prod);
// Set the itemversion. This version will be used to compare the
// item version of cached item
updatedItem.setCacheItemVersion(version);
cache.insert(key, updatedItem);
// If it matches, the insert will be successful, otherwise it will fail
}
// This is an async method
// Precondition: Cache is already connected
// An item is added in the cache with itemVersion
// Specify the key of the cacheItem
var key = "Product:1001";
// Initialize the cacheItemVersion
var version = new ncache.CacheItemVersion();
// readThruOptions set to null
var cacheItem = await this.cache.getCacheItem(key, null, version);
// If result is not null
if (cacheItem != null)
{
var prod = new Product();
prod = cacheItem.getValue(ncache.JsonDataType.Object);
prod.unitsInStock++;
// Update the retrieved cacheitem according to requirement
// Create a new cacheItem with updated value
// You also need to specify the FQN(Fully Qualified Name) of the class
var updatedItem = new ncache.CacheItem(prod,"FQN.Product");
// Set the itemversion. This version will be used to compare the
// item version of cached item
updatedItem.setCacheItemVersion(version);
await this.cache.insert(key, updatedItem);
// If it matches, the insert will be successful, otherwise it will fail
}
# Precondition: Cache is already connected
# An item is added in the cache with ItemVersion
# Specify the key of the cacheItem
key = "Product:1001"
# Initialize the cacheItemVersion
version = ncache.CacheItemVersion(0)
cache_item = cache.get_cacheitem(key, cacheitemversion=version)
# If result is not None
if cache_item is not None:
prod = cache_item.get_value(Product)
prod.set_units_in_stock(20)
# Update the retrieved cacheitem according to requirement
# Create a new CacheItem with updated value
updated_item = ncache.CacheItem(prod)
# Set the item_version. This version will be used to compare the
# item version of cached item
updated_item.set_cache_item_version(version)
cache.insert(key, updated_item)
# If it matches, the insert will be successful, otherwise it will fail
Note
操作がフェイルセーフであることを保証するために、で説明されているように、アプリケーション内の潜在的な例外を処理することをお勧めします。 失敗の処理.
新しいバージョンがキャッシュに存在する場合にアイテムを取得する
GetIfNewer
新しいバージョンがキャッシュ内にある場合は、メソッドを使用して既存の項目をフェッチできます。 現在のバージョンをメソッド呼び出しの引数として指定すると、キャッシュは適切な結果を返します。
指定されたバージョンがキャッシュ内のバージョンよりも古い場合にのみ、メソッドは新しいアイテムを返します。それ以外の場合は、 ヌル 返されます。
次の例では、キーを使用してキャッシュにアイテムを追加します Product:1001
とアイテムのバージョンを取得し、新しいバージョンが利用可能な場合は、 GetIfNewer
キャッシュアイテムバージョンを使用してアイテムをフェッチするメソッド。
// Get updated product from database against given product ID
Product product = FetchProductByProductID(1001);
// Generate a unique key for this item
string key = $"Product:{product.ProductID}";
// Create a new CacheItem
var item = new CacheItem(product);
// Add CacheItem to cache with new itemversion
CacheItemVersion version = cache.Insert(key, item);
// Get object from cache
var result = cache.GetIfNewer<Product>(key, ref version);
// Check if updated item is available
if (result != null)
{
// An item with newer version is available
if (result is Product)
{
// Perform operations according to business logic
}
}
else
{
// No new itemVersion is available
}
// Pre-condition: Cache is already connected
// Get updated product from database against given product ID
Product product = fetchProductByProductID(1001);
// Generate a unique key for this item
String key = "Product:" + product.getProductID();
// Create a new CacheItem
CacheItem item = new CacheItem(product);
// Add CacheItem to cache with new itemversion
CacheItemVersion version = cache.insert(key, item);
// Get object from cache
Object result = cache.getIfNewer(key,version,Object.class);
// Check if updated item is available
if (result != null)
{
// Perform operations according to business logic
}
else
{
// No new itemVersion is available
}
// This is an async method
// Pre-condition: Cache is already connected
// Get updated product from database against given product ID
var product = this.fetchProductByProductID(1001);
// Generate a unique key for this item
var key = "Product:" + product.getProductID();
// Create a new CacheItem
// You also need to specifyt the FQN(Fully Qualified Name) of the class
var item = new ncache.CacheItem(product,"FQN.Product");
// Add CacheItem to cache with new itemversion
var version = await this.cache.insert(key, item);
// Get object from cache
var result = await this.cache.getIfNewer(key, ncache.JsonDataType.Object, version);
// Check if updated item is available
if (result != null)
{
// Perform operations according to business logic
}
else
{
// No new itemVersion is available
}
# Pre-condition: Cache is already connected
# Get updated product from database against given product ID
product = fetch_product_from_db(1001)
# Generate a unique key for this item
key = "Product:" + product.get_product_id()
# Create a new CacheItem
item = ncache.CacheItem(product)
# Add CacheItem to cache with new itemversion
version = cache.insert(key, item)
# Get object from cache
result = cache.get_if_newer(key, cacheitemversion=version, objtype=Product)
# Check if updated item is available
if result is not None:
# Perform operations according to business logic
print("New version is available")
else:
# No new ItemVersion is available
print("New version is not available")
アイテムバージョンでアイテムを削除
項目は、オーバーロードを使用してキャッシュから削除できます。 削除します、アイテムのバージョンに基づきます。 ただし、アイテムのバージョンがキャッシュ内のものと異なる場合は、そのように指定された例外が発生します。
次の例は、アイテム バージョンを指定してキャッシュからアイテムを削除する方法を示しています。 削除します 方法。
// Get updated product from database against given product ID
Product product = FetchProductByProductID(1001);
// Cache key remains the same for this product
string key = $"Product:{product.ProductID}";
// Create a new CacheItem
var item = new CacheItem(product);
// Insert CacheItem to cache with new itemversion
CacheItemVersion version = cache.Insert(key, item);
// Remove the item from the cache using the itemVersion
cache.Remove(key, null, version);
// Pre-condition: Cache is already connected
// Get updated product from database against given product ID
Product product = fetchProductByProductID(1001);
// Cache key remains the same for this product
String key = "Product:" + product.getProductID();
// Create a new CacheItem
CacheItem item = new CacheItem(product);
// Add CacheItem to cache with new itemversion
CacheItemVersion version = cache.insert(key, item);
// Remove the item from the cache using the itemVersion
//lockHandle and writeThruOptions set to null
cache.remove(key,null,version,null,Object.class);
Object value = cache.get(key,Object.class);
// Checking if item still exists in cache or not
if(value == null)
{
// Item has been removed from the cache
}
else
{
// Item is still in Cache
}
// Pre-condition: Cache is already connected
// Get updated product from database against given product ID
var product = this.fetchProductByProductID(1001);
// Cache key remains the same for this product
var key = "Product:" + product.getProductID();
// Create a new CacheItem
// You also need to specify the FQN(Fully Qualified Name) of the class
var item = new ncache.CacheItem(product,"FQN.Product");
// Add CacheItem to cache with new itemversion
var version = await this.cache.insert(key, item);
// Remove the item from the cache using the itemVersion
// lockHandle and writeThruOptions set to null
await this.cache.remove(key, ncache.JsonDataType.Object, null, version, null);
var value = await this.cache.get(key, ncache.JsonDataType.Object);
if (value == null)
{
// Item has been removed from cache
}
else
{
// Item is still in cache
}
# Pre-condition: Cache is already connected
# Get updated product from database against given product ID
product = fetch_product_from_db(1001)
# Cache key remains the same for this product
key = "Product:" + product.get_product_id()
# Create a new CacheItem
item = ncache.CacheItem(product)
# Add CacheItem to cache with new itemversion
version = cache.insert(key, item)
# Remove the item from the cache using the ItemVersion
cache.remove(key, version=version, objtype=Product)
value = cache.get(key, Product)
if value is None:
# Item has been removed from cache
print("Remove successful")
else:
# Item is still in cache
print("Remove failed")
トポロジーの賢明な振る舞い
鏡 トポロジでは、アイテムが追加または更新されると、そのバージョンがアクティブ ノードで生成され、同じバージョンがアイテムとともにパッシブ ノードにレプリケートされるため、アクティブ ノードがパッシブになってもアイテムのバージョンは同じままになります。
複製 トポロジでは、クライアントは XNUMX つのノードに接続され、アイテムのバージョンはクライアントの更新/追加操作を受け取るノードで生成され、データの一貫性を保つために同じアイテムのバージョンがアイテムとともに他のすべてのノードにレプリケートされます。
- パーティション化キャッシュおよびパーティション レプリカ キャッシュの場合
パーティション化 トポロジでは、アイテムのバージョンが生成され、そのアイテムを含む同じノード上に存在します。また、状態転送中に、アイテムが別のノードに移動する場合に備えて、バージョンもアイテムとともに転送されます。
パーティション-レプリカ トポロジでは、バージョンはアイテムを含むアクティブ ノード上で生成され、その後、データの一貫性のためにアイテムとともに同じバージョンがそのレプリカに複製され、状態転送中に、アイテムが別のノードに移動する場合に備えて、バージョンもアイテムとともに転送されます。ノード。
クライアントキャッシュ、すべてのバージョン関連情報はクラスター化キャッシュで維持され、バージョン関連 API が呼び出されるたびに、ユーザーはクラスター化キャッシュからバージョンを取得します。
その他のリソース
NCache アイテムロックオンのサンプルアプリケーションを提供します GitHubの.
も参照してください
。ネット: Alachisoft.NCache.ランタイム.キャッシュ 名前空間
Java: comの。alachisoft.ncache.ランタイムキャッシュ 名前空間
Node.js: キャッシュ とに提供されます。
Python: ncache.ランタイムキャッシュ とに提供されます。