Le aziende oggi stanno sviluppando applicazioni Web ASP.NET ad alto traffico che servono decine di migliaia di utenti simultanei. Più client hanno accesso ai dati nella cache in un ambiente cluster in cui i server delle applicazioni vengono distribuiti in un ambiente con bilanciamento del carico. In tali condizioni parallele, diversi utenti tentano spesso di accedere e modificare gli stessi dati e attivare una race condition.
Una race condition è quando due o più utenti tentano di accedere e modificare gli stessi dati condivisi contemporaneamente ma finiscono per farlo nell'ordine sbagliato. Questa situazione comporta un rischio elevato di perdita dell'integrità e della coerenza dei dati. Con l'avvento di soluzioni di caching in memoria scalabili come NCache fornendo meccanismi di blocco distribuito, le aziende possono ottenere una consistenza dei dati notevolmente migliorata.
NCache Dettagli Blocco e controllo dei documenti NCache Docs
Blocco distribuito per la coerenza dei dati
NCache fornisce un meccanismo di distribuzione bloccaggio in .NET che consente di bloccare elementi della cache specifici durante gli aggiornamenti simultanei. Per mantenere la coerenza dei dati in questi casi, NCache funge da gestore di blocco distribuito e fornisce due tipi di blocco:
Ne parleremo in dettaglio più avanti nel blog. Per ora, considera lo scenario seguente per capire come senza un servizio di blocco distribuito si verifica una violazione dell'integrità dei dati.
Due utenti accedono allo stesso Conto Bancario contemporaneamente con un saldo di 30,000. Un utente preleva 15,000, mentre l'altro utente ne deposita 5,000. Se fatto correttamente, il saldo finale dovrebbe essere 20,000. Al contrario, se emerge una condizione di razza che non viene curata, il conto in banca sarebbe 15,000 o 35,000, come puoi vedere sopra.
Ecco come si verifica questa condizione di razza:
- Tempo t1: L'utente 1 recupera il conto bancario con saldo = 30,000
- Tempo t2: L'utente 2 recupera il conto bancario con saldo = 30,000
- Tempo t3: L'utente 1 preleva 15,000 e aggiorna il saldo del conto bancario = 15,000
- Tempo t4: L'utente 2 deposita 5,000 e aggiorna il saldo del conto bancario = 35,000
In entrambi i casi, un blocco di codice che non soddisfa la gestione dei thread potrebbe essere disastroso per la banca. Quindi, nelle sezioni successive, vediamo come NCache fornisce meccanismi di blocco per garantire che la logica dell'applicazione sia thread-safe.
NCache Dettagli Blocco pessimistico Blocco ottimistico
Blocco ottimistico (versioni articolo)
In chiusura ottimistica, NCache usa versione degli elementi della cache. Sul lato server, a ogni oggetto memorizzato nella cache è associato un numero di versione che viene incrementato ad ogni aggiornamento dell'elemento della cache. NCache quindi controlla se stai lavorando sull'ultima versione. In caso contrario, rifiuta l'aggiornamento della cache. In questo modo, solo un utente può eseguire l'aggiornamento e gli altri aggiornamenti utente non riescono.
Puoi aggiungere un elemento nella cache usando entrambi Aggiungi or inserire metodi.
- Il metodo Aggiungi aggiunge un nuovo elemento nella cache e salva la versione dell'elemento per la prima volta.
- Il metodo insert sovrascrive il valore di un elemento esistente e ne aggiorna la versione.
Dai un'occhiata al seguente esempio di codice.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// Pre-condition: 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(); prod.UnitsInStock++; // Create a new cacheItem with updated value var updateItem = new CacheItem(prod); CacheItemVersion 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 } |
Nell'esempio precedente, due diverse applicazioni utilizzano un'unica cache contenente i dati dei prodotti. CacheItem viene aggiunto alla cache. Entrambe le applicazioni recuperano l'elemento con la versione corrente, diciamo versione. L'applicazione1 modifica il nome del prodotto e quindi reinserisce l'elemento nella cache a cui aggiorna la sua versione dell'elemento nuova versione. Application2 ha ancora l'elemento con versione. Se l'applicazione2 aggiorna le unità dell'articolo in magazzino e reinserisce l'articolo nella cache, l'inserimento dell'articolo avrà esito negativo. Application2 dovrà quindi recuperare la versione aggiornata per operare su quel cacheItem.
NCache Dettagli Blocco ottimistico Controllo delle versioni degli elementi della cache
Tuttavia, se desideri recuperare un elemento esistente che potrebbe avere una versione più recente disponibile nella cache, NCache fornisce un OttieniSeNewer metodo. Se si specifica la versione corrente come argomento della chiamata al metodo, la cache restituisce un risultato appropriato. Se la versione specifica è inferiore a quella nella cache, il metodo restituisce un nuovo Item, altrimenti restituirà null.
Diamo un'occhiata al codice qui sotto.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Get object from cache var result = cache.GetIfNewer(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 } |
L'esempio precedente aggiunge un elemento nella cache con la chiave Product:1001 e la versione dell'oggetto. Se è disponibile una versione più recente dell'articolo, OttieniSeNewer il metodo recupera l'elemento utilizzando la versione dell'elemento della cache.
Con un bloccaggio ottimistico, NCache assicura che ogni scrittura nella cache distribuita sia coerente con la versione di ciascuna applicazione. Si prega di fare riferimento al nostro ufficiale NCache Documentazione per un esempio di codice completo.
NCache Dettagli OttieniSeNewer CacheItemVersioning
Blocco pessimistico (blocco esclusivo)
L'altro modo per garantire la coerenza dei dati consiste nell'acquisire un blocco esclusivo sui dati memorizzati nella cache. Questo meccanismo è chiamato Blocco pessimistico . Blocca l'elemento utilizzando l'handle di blocco, impedendo a tutti gli altri utenti di eseguire qualsiasi operazione di scrittura su quell'elemento della cache. UN Maniglia di blocco è un handle associato a ogni elemento bloccato nella cache restituito dall'API di blocco.
L'esempio seguente crea un LockHandle e quindi blocca un elemento con la chiave Product:1001 per un intervallo di tempo di 10 secondi in modo che l'elemento venga sbloccato automaticamente dopo 10 secondi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// Pre-Requisite: 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 } |
Dopo aver acquisito correttamente il blocco durante il recupero dell'elemento, l'applicazione ora può eseguire operazioni in sicurezza, sapendo che nessun'altra applicazione può ottenere o aggiornare questo elemento finché si dispone di questo blocco. Chiameremo l'API di inserimento con lo stesso handle di blocco per aggiornare i dati e rilasciare il blocco. In questo modo inserirai i dati nella cache e rilascerà il blocco, tutto in un'unica chiamata, consentendo ai dati memorizzati nella cache di essere disponibili per tutte le altre applicazioni.
Ricorda solo che dovresti acquisire tutti i blocchi con un timeout. Per impostazione predefinita, se il timeout non è specificato, NCache bloccherà l'oggetto per un periodo di tempo indefinito, periodo.zero. Potrebbe verificarsi un caso in cui l'elemento può rimanere bloccato per sempre se l'applicazione si arresta in modo anomalo senza rilasciare il blocco. Per una soluzione alternativa, potresti rilasciare con forza esso, ma questa pratica è sconsiderata. Pertanto, bloccare un elemento per il TimeSpan minimo per evitare deadlock o fame di thread.
NCache Dettagli Blocco pessimistico Blog sull'utilizzo del blocco con i dati memorizzati nella cache
Supporto per il failover nel blocco distribuito
Dal NCache è una memoria, cache distribuita, fornisce anche un supporto completo per il failover in modo che non vi sia alcuna perdita di dati ed è altamente disponibile. In caso di guasto del server, le applicazioni client continuano a funzionare senza problemi. Allo stesso modo, anche i tuoi blocchi nel sistema distribuito vengono replicati e gestiti dai nodi di replica. Se un nodo si guasta mentre una delle tue applicazioni acquisisce un blocco, verrà propagato automaticamente a un nuovo nodo con le sue proprietà specificate, ad esempio, Scadenza del blocco.
Conclusione
Quindi, quale meccanismo di blocco è il migliore per te, ottimista o pessimista? Bene, dipende dal tuo caso d'uso e da cosa vuoi ottenere. Il blocco ottimistico offre un miglioramento delle prestazioni rispetto al blocco pessimistico, soprattutto quando le applicazioni richiedono un uso intensivo della lettura. Considerando che il blocco pessimistico è più sicuro dal punto di vista della coerenza dei dati. Pertanto, scegli con attenzione il tuo meccanismo di chiusura. Per maggiori dettagli, vai su sito web. In caso di domande, CONTATTACI e fatti aiutare dai nostri esperti!