アイテムの排他的ロック(悲観的ロック)
NCache キャッシュされたデータを排他的にロックする悲観的ロック メカニズムを提供します。このメカニズムは、ロック ハンドルを使用してアイテムをロックします。これにより、他のすべてのユーザーはそのキャッシュ アイテムに対する書き込み操作を実行できなくなります。あ LockHandle
キャッシュ内のすべてのロックされたアイテムに関連付けられており、ロック API によって返されます。
Note
この機能は以下でも利用できます NCache Professional.
ロックされた項目は、そのロック ハンドルが API レベルで提供されている場合にのみ、フェッチ/更新またはロック解除できます。 ただし、データの整合性の問題を避けるために、これを慎重に行う必要があります。 達成すべき目標がデータの一貫性である場合、悲観的ロックは非常に優れたアプローチです。
を使用してロックを取得したら LockHandle
、それを解放するためのXNUMXつのメカニズムがあります。 これらのメカニズムの両方を以下に説明します。
時間ベースのロックの解放: キャッシュされたアイテムをロックするときに、ロック タイムアウトを指定することもできます。 ロック タイムアウトは、タイムアウト間隔中にロックを解放するための明示的な呼び出しが行われなかった場合に、ロックが自動的に解放されるまでの時間間隔です。 これにより、データが無制限にロックされることがなくなります。
ロックの強制解除: 分散環境では、キャッシュ項目のロックを取得したアプリケーションが突然終了したり、アプリケーションがロックされたデータの処理を終了したりする場合に状況が発生する可能性があります。 このような状況では、そのようなアプリケーションによって取得されたすべてのロックを解放する必要があります。 NCache キャッシュ項目のロックを強制的に解除するロック解除APIを提供します。
Note
条件が満たされた後にアイテムのロックが解除され、リソースが最小限の時間取得されたままになるように、時間ベースのロック メカニズムを使用することをお勧めします。
悲観的ロックを使用する場合
前の章で説明した例を考えてみましょう。 更新操作のために同じインスタンスで XNUMX 人の異なるユーザーが同じ銀行口座にアクセスすると、競合が発生してデータの不整合が生じる可能性があります。
このシナリオでの悲観的ロックにより、一度に XNUMX 人のユーザーがアカウントにアクセスできるようになります。 正常に動作すると、ユーザーはアイテムのロックを解除し、コントロールが解放されます。これは、XNUMX 番目のユーザーがアカウントにアクセスして、それに応じて修正できることを意味します。
このアプローチを使用すると、データの一貫性が維持され、競合は発生しません。
A LockHandle
キャッシュ全体で特定のアイテムにアクセスできないようにするために、アイテムに関連付けられています。
NCache は、ロック専用に呼び出すメソッドと、ロック メカニズムを操作する多数のオーバーロードを提供します。
前提条件
アイテムを明示的にロックする
操作を実行する前に項目を明示的にロックできます。 この方法には、 TimeSpan
指定した時間アイテムをロックします。 ただし、取得したロックを期限切れにしたくない場合は、次のように指定します TimeSpan.Zero
。 いいえを指定する TimeSpan
アイテムを無期限にロックします。
Lock
この例で使用されるメソッドは、 LockHandle
鍵付き。 シングルであることを確認してください。 LockHandle
単一のキーに関連付けられています。 ハンドルを再使用する前にロックを解除してください。 そうしないと、動作の不一致が生じる可能性があります。
項目がすでにロックされている場合は false 値が返されますが、更新された値が得られます。 LockHandle
.
警告
最低限のアイテムをロックする TimeSpan
デッドロックや飢餓状態を避けるため。
次の例では、 LockHandle
キーでアイテムをロックします Product:1001
これは、アイテムが 10 秒後に自動的にロック解除されることを意味します。
// Preconditions: Cache is already connected
// Item is already added in the cache
// Specify the key of the item
string key = $"Product:1001";
//Create a new LockHandle
LockHandle lockHandle = null;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = TimeSpan.FromSeconds(10);
// Lock the item for a time span of 10 seconds
bool lockAcquired = cache.Lock(key, lockSpan, out lockHandle);
// Verify if the item is locked successfully
if (lockAcquired == true)
{
// Item has been successfully locked
}
else
{
// Key does not exist
// Item is already locked with a different LockHandle
}
// Precondition: Cache is already connected
// Item is already added in the cache
// Specify the key of the item
String key = "Product:1001";
//Create a new LockHandle
LockHandle lockHandle = new LockHandle();
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = new TimeSpan(0, 0, 10);
// Lock the item for a time span of 10 seconds
boolean lockAcquired = cache.lock(key, lockSpan, lockHandle);
// Verify if the item is locked successfully
if (lockAcquired == true)
{
// Item has been successfully locked
}
else
{
// Key does not exist
// Item is already locked with a different LockHandle
}
// This is an async method
// Precondition: Cache is already connected
// Item is already added in the cache
// Specify the key of the item
var key = "Product:1001";
//Create a new LockHandle
var lockHandle = new ncache.LockHandle();
// Specify time span of 10 seconds for which the item remains locked
var lockSpan = new ncache.TimeSpan(None,0,0,10);
// Lock the item for a time span of 10 seconds
var lockAcquired = await this.cache.lock(key, lockSpan, lockHandle);
// Verify if the item is locked successfully
if (lockAcquired == true)
{
// Item has been successfully locked
}
else
{
// Key does not exist
// Item is already locked with a different LockHandle
}
# Precondtion: Cache is already connected
# Item is already added in the cache
# Specify the key of the item
key = "Product:1001"
# Create a new LockHandle
lock_handle = ncache.LockHandle()
# Specify time span of 10 seconds for which the item remains locked
lock_span = ncache.TimeSpan(None,0,0,10)
# Lock the item for a time span of 10 seconds
lock_acquired = cache.lock(key, lock_span, lock_handle)
# Verify if the item is locked successfully
if lock_acquired:
# Item has been successfully locked
print("Lock successful")
else:
# Key does not exist
# Item is already locked with a different LockHandle
print("Lock failed")
Note
操作がフェイルセーフであることを保証するために、で説明されているように、アプリケーション内の潜在的な例外を処理することをお勧めします。 失敗の処理.
Get操作中にアイテムをロックする
項目は、キャッシュからの取得中にロックされることがあります。 これは、あなたが解放しない限り、そのアイテムに他の人がアクセスできないことを意味します。 キーが一致しない場合は、null 値が返されます。
アイテムがロックされておらず、 acquirelock
が true に設定されている場合、LockHandle とともにアイテムを取得します。
アイテムがロックされている場合 acquirelock
が false に設定されており、誤ったまたは新しい空の LockHandle を渡すと、 null
value が返されますが、以前にアイテムをロックするために使用された LockHandle を取得します。
アイテムがロックされている場合 acquirelock
が false に設定され、以前にアイテムをロックするために使用された正しい LockHandle が渡された場合、値が取得されます。
警告
デッドロックやスレッドの枯渇を避けるために、最小 TimeSpan の間項目をロックします。
この例では、キーと LockHandle
キャッシュされたオブジェクトをフェッチしてロックするように指定されます。 ロックを取得する必要がある場合は true を指定する必要があります。 ここでは、アイテムは 10 秒の有効期限でロックされています。これは、アイテムが 10 秒後に自動的にロック解除されることを意味します。
// Specify the key of the item
string key = $"Product:1001";
// Set acquireLock flag as true
bool acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = TimeSpan.FromSeconds(10);
//Create a new LockHandle
LockHandle lockHandle = null;
// Lock the item for a time span of 10 seconds
var result = cache.Get<Product>(key, acquireLock, lockSpan, ref lockHandle);
// Verify if the item is locked successfully
if (result != null)
{
// Item has been successfully locked
}
else
{
// Key does not exist
// Item is already locked with a different LockHandle
}
// Specify the key of the item
String key = "Product:1001";
// Set acquireLock flag as true
boolean acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = new TimeSpan(0, 0, 10);
//Create a new LockHandle
LockHandle lockHandle = new LockHandle();
// Lock the item for a time span of 10 seconds
Object result = cache.get(key, acquireLock, lockSpan, lockHandle, Object.class);
// Verify if the item is locked successfully
if (result != null)
{
// Item has been successfully locked
}
else
{
// Key does not exist
// Item is already locked with a different LockHandle
}
// Specify the key of the item
var key = "Product:1001";
// Set acquireLock flag as true
var acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
var lockSpan = new ncache.TimeSpan(None,0,0,10);
//Create a new LockHandle
var lockHandle = new ncache.LockHandle();
// Lock the item for a time span of 10 seconds
//CacheItemVersion set to null and Readthrough Options set to null
var result = await this.cache.getCacheItem(key,null,null, acquireLock, lockSpan, lockHandle);
// Verify if the item is locked successfully
if (result != null)
{
// Item has been successfully locked
}
else
{
// Key does not exist
// Item is already locked with a different LockHandle
}
# Specify the key of the item
key = "Product:1001"
# Set acquireLock flag as true
acquire_lock = True
# Specify time span of 10 seconds for which the item remains locked
lock_span = ncache.TimeSpan(None,0,0,10)
# Create a new LockHandle
lock_handle = ncache.LockHandle()
# Lock the item for a time span of 10 seconds
result = cache.get_cacheitem(key, acquirelock=acquire_lock, locktimeout=lock_span, lockhandle=lock_handle)
# Verify if the item is locked successfully
if result is not None:
# Item has been successfully locked
print("Lock successful")
else:
# Key does not exist
# Item is already locked with a different LockHandle
print("Lock failed")
更新操作でロックを解除
アイテムの更新中にロックを解除し、他のユーザーがキャッシュされたデータを使用できるようにすることができます。 ロックされたアイテムを正常に解放するには、 LockHandle
最初はアイテムをロックするために使用されました。
LockHandle
最初に項目をロックするために使用したものと同じである必要があります。そうでない場合は、「項目はロックされています」という例外メッセージが表示されます。
If releaseLock
false に設定されている場合でも、正しい値を渡す必要があります Lockhandle
アイテムを更新します。
アイテムがロックされていない場合、 LockHandle
および releaseLock
役に立たず、無視されます。
次の例では、キャッシュ内の項目をロックし、次のメソッドを使用して項目を取得します。 LockHandle
。 その後、アイテムは更新され、次のメソッドを使用してキャッシュに再挿入されます。 インセット APIです。
// Specify the key of the item
string key = $"Product:1001";
// Set acquireLock flag as true
bool acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = new TimeSpan(0, 0, 10);
// Initialize the lockHandle
LockHandle lockHandle = null;
CacheItem item = cache.GetCacheItem(key, acquireLock, lockSpan, ref lockHandle);
var product = new Product();
product = item.GetValue<Product>();
// Update the unitsinstock for the product
product.UnitsInStock = 200;
bool releaseLock = true;
// Item is already locked with a LockHandle
// Update the item and release the lock as well since releaseLock is set true
// Make sure that the LockHandle matches with the already added LockHandle
cache.Insert(key, item, null, lockHandle, releaseLock);
// Specify the key of the item
String key = "Product:1001";
// Set acquireLock flag as true
boolean acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = new TimeSpan(0, 0, 10);
// Initialize the lockHandle
LockHandle lockHandle = new LockHandle();
CacheItem item = cache.getCacheItem(key, acquireLock, lockSpan, lockHandle);
// Update the value of item
product = item.getValue(Product.class);
product.setUnitsInStock(200);
boolean releaseLock = true;
// Item is already locked with a LockHandle
// Update the item and release the lock as well since releaseLock is set true
// Make sure that the LockHandle matches with the already added LockHandle
// writeThruOptions set to null
cache.insert(key, item, null, lockHandle,releaseLock);
// This is an async method
// Specify the key of the item
var key = "Product:1001";
// Set acquireLock flag as true
var acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
var lockSpan = new ncache.TimeSpan(None,0,0,10);
// Initialize the lockHandle
var lockHandle = new ncache.LockHandle();
// cacheItemVersion set to null and readThruOptions set to null;
var item = await this.cache.getCacheItem(key,null,null, acquireLock, lockSpan, lockHandle);
// Update the value of item
var product = item.getValue(ncache.JsonDataType.Object);
product.unitsInStock = 200;
var releaseLock = true;
// Item is already locked with a LockHandle
// Update the item and release the lock as well since releaseLock is set true
// Make sure that the LockHandle matches with the already added LockHandle
// writeThruOptions set to null
await this.cache.insert(key, item, null, lockHandle, releaseLock);
# Specify the key of the item
key = "Product:1001"
# Set acquireLock flag as true
acquire_lock = True
# Specify time span of 10 seconds for which the item remains locked
lock_span = ncache.TimeSpan(None,0,0,10)
# Create a new LockHandle
lock_handle = ncache.LockHandle()
# Lock the item for a time span of 10 seconds
item = cache.get_cacheitem(key, acquirelock=acquire_lock, locktimeout=lock_span, lockhandle=lock_handle)
# Update the value of item
product = item.get_value(Product)
product.set_units_in_stock(20)
release_lock = True
# Item is already locked with a LockHandle
# Update the item and release the lock as well since release_lock is set true
# Make sure that the LockHandle matches with the already added LockHandle
cache.insert(key, item, lockhandle=lock_handle, releaselock=release_lock)
ロックを明示的に解放する
以前にロックされたキャッシュされたアイテムのロックを明示的に解放するには。 を指定する必要があります LockHandle
最初はアイテムをロックするために使用されました。
Status LockHandle
保存されない場合は、別のオーバーロードを使用することもできます Unlock
アイテムのロックを解除するためのキーのみを取得します。
Note
無効の場合 LockHandle
が渡された場合、例外はスローされませんが、項目はロックされたままになります。
次の例では、を使用してすでにロックされているアイテムを取得します LockHandle
次に、を使用してロックを解除します Unlock
を使用するAPI Lockhandle
以前に保存されました。
// Specify the key of the item
string key = $"Product:1001";
// Set acquireLock flag as true
bool acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = TimeSpan.FromSeconds(10);
//Create a new LockHandle
LockHandle lockHandle = null;
Product result = cache.Get<Product>(key, acquireLock, lockSpan, ref lockHandle);
// Make sure that the item is already locked and the saved LockHandle is used
// Unlock locked item using saved LockHandle
cache.Unlock(key, lockHandle);
// Specify the key of the item
String key = "Product:1001";
// Set acquireLock flag as true
boolean acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = new TimeSpan(0, 0, 10);
//Create a new LockHandle
LockHandle lockHandle = new LockHandle();
Object result = cache.get(key, acquireLock, lockSpan, lockHandle, Object.class);
// Make sure that the item is already locked and the saved LockHandle is used
// Unlock locked item using saved LockHandle
cache.unlock(key, lockHandle);
// This is an async method
// Specify the key of the item
var key = "Product:1001";
// Set acquireLock flag as true
var acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
var lockSpan = new ncache.TimeSpan(None,0,0,10);
//Create a new LockHandle
var lockHandle = new ncache.LockHandle();
// cacheItemVersion set to null and readThruOptions set to null;
var result = await this.cache.getCacheItem(key,null,null,acquireLock,lockSpan,lockHandle);
// Make sure that the item is already locked and the saved LockHandle is used
// Unlock locked item using saved LockHandle
await this.cache.unlock(key, lockHandle);
# Specify the key of the item
key = "Product:1001"
# Set acquireLock flag as true
acquire_lock = True
# Specify time span of 10 seconds for which the item remains locked
lock_span = ncache.TimeSpan(None,0,0,10)
# Create a new LockHandle
lock_handle = ncache.LockHandle()
result = cache.get_cacheitem(key, acquirelock=acquire_lock, locktimeout=lock_span, lockhandle=lock_handle)
# Make sure that the item is already locked and the saved LockHandle is used
# Unlock locked item using saved LockHandle
cache.unlock(key, lock_handle)
警告
NCache 他の過負荷の場合、ロックを無視します Get
, Insert
, Remove
取得または使用しないメソッドが呼び出されます LockHandle
.
LockHandleでアイテムを削除する
Remove メソッドは、キャッシュからキーを削除し、削除されたオブジェクトをクライアントに返す基本的なメソッドです。 カスタム オブジェクトがキャッシュに追加される場合、remove メソッドは Object を返します。
次の例では、以前にロックされている項目を、 LockHandle
保存したもので削除します LockHandle
を使用してキャッシュから 削除します APIです。
// Specify the key of the item
string key = $"Product:1001";
// Initialize the lockHandle
LockHandle lockHandle = null;
// Set acquireLock flag as true
bool acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = TimeSpan.FromSeconds(10);
// Get the item using the lockHandle
Product result = cache.Get<Product>(key, acquireLock, lockSpan, ref lockHandle);
// Removing locked item using saved lockHandle.
cache.Remove(key, lockHandle);
// Check if item is successfully removed
if (result != null)
{
if (result is Product)
{
Product product = (Product)result;
}
}
// Specify the key of the item
String key = "Product:1001";
// Set acquireLock flag as true
boolean acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
TimeSpan lockSpan = new TimeSpan(0, 0, 10);
//Create a new LockHandle
LockHandle lockHandle = new LockHandle();
Object result = cache.get(key, acquireLock, lockSpan, lockHandle, Object.class);
// Removing locked item using saved lockHandle.
//cacheItemVersion and writeThruOptions set to null
cache.remove(key, lockHandle, null, null, Object.class);
Object test = cache.get(key, Object.class);
// check if item has been removed
if (test != null)
{
//Item has not been removed
}
else
{
// Item has been removed
}
// This is an async method
// Specify the key of the item
var key = "Product:1001";
// Set acquireLock flag as true
var acquireLock = true;
// Specify time span of 10 seconds for which the item remains locked
var lockSpan = new ncache.TimeSpan(None,0,0,10);
//Create a new LockHandle
var lockHandle = new ncache.LockHandle();
// CacheItemVersion and ReadThruOptions set to null
var result = await this.cache.getCacheItem(key,null,null, acquireLock, lockSpan, lockHandle, ncache.JsonDataType.Object);
// Removing locked item using saved lockHandle.
//cacheItemVersion and writeThruOptions set to null
await this.cache.remove(key,ncache.JsonDataType.Object, lockHandle, null, null);
var test = await this.cache.getCacheItem(key);
// check if item has been removed
if (test != null)
{
// Item has not been removed
}
else
{
// Item has been removed
}
# Specify the key of the item
key = "Product:1001"
# Set acquireLock flag as true
acquire_lock = True
# Specify time span of 10 seconds for which the item remains locked
lock_span = ncache.TimeSpan(None,0,0,10)
# Create a new LockHandle
lock_handle = ncache.LockHandle()
result = cache.get_cacheitem(key, acquirelock=acquire_lock, locktimeout=lock_span, lockhandle=lock_handle)
# Removing locked item using saved lock_handle.
cache.remove(key, Product, lockhandle=lock_handle)
test = cache.get_cacheitem(key)
# Check if item has been removed
if test is not None:
# Item has not been removed
print("Remove with lock failed")
else:
# Item has been removed
print("Remove with lock successful")
APIロックを使用する際の特別な考慮事項
NCache ありとなしのAPIのセットを提供します LockHandle
キャッシュ項目を取得/更新します。 のない API LockHandle
アイテムのロックを無視します。 したがって、データ操作にはすべてのロック API を使用する必要があります。 たとえば、アイテムがロックされているときに、 LockHandle
入力パラメータとして入力すると、そのアイテムはロック状態に関係なくキャッシュ内で更新されます。
重要
ロック機能を使用する場合は、次のような API 呼び出しのみを使用する必要があります。 LockHandle
パラメータとして。 ロック ハンドルを使用しない API も使用できますが、データの整合性に影響を与えないよう十分に注意して使用する必要があります。
Note
立ち退き/期限切れの場合、 NCache ロックを無視します。これは、ロックされたアイテムが期限切れまたは削除の結果として削除される可能性があることを意味します。
トポロジーの賢明な振る舞い
鏡 トポロジ。すべてのロック操作について、ロックはアクティブ ノードで取得され、同じ LockHandle
次に、パッシブ ノードにレプリケートされるため、パッシブがアクティブになったときに項目はロックされたままになります。 同様に、ロック解除呼び出しもパッシブ ノードに複製され、パッシブ ノードからアイテムのロックが解除されます。
複製 トポロジでは、クライアントは XNUMX つのノードに接続されており、すべてのロック操作に対して LockHandle
クライアントのロック操作を受け取るものが生成され、その後同じ LockHandle
データの一貫性を保つために、他のすべてのノードに複製されます。 同様に、ロック解除操作も他のすべてのノードに複製されます。
- パーティショントポロジおよびパーティションレプリカトポロジ
パーティション化 トポロジー、 LockHandle
状態転送中に、アイテムを含む同じノード上に生成および存在します。 LockHandle
アイテムが別のノードに移動した場合に備えて、情報もアイテムとともに転送されます。
In パーティション-レプリカ トポロジー、 LockHandle
アイテムを含むアクティブなノード上で生成され、同じ LockHandle
その後、データの一貫性と状態の転送中にそのレプリカに複製されます。 LockHandle
アイテムが別のノードに移動した場合に備えて、情報もアイテムと一緒に転送されます。
クライアントキャッシュ、すべてのロックベースの操作はクラスター化されたキャッシュで直接実行されます。つまり、 LockHandle
生成され、クラスター化されたキャッシュに保存されます。 ロック関連の情報はクライアント キャッシュには保持されません。
その他のリソース
NCache アイテムロックオンのサンプルアプリケーションを提供します GitHubの.
も参照してください
。ネット: Alachisoft.NCache.ランタイム.キャッシュ 名前空間
Java: comの。alachisoft.ncache.ランタイムキャッシュ 名前空間
Node.js: キャッシュ とに提供されます。
Python: ncache.ランタイムキャッシュ とに提供されます。