Performing Transactions
Belirli bir cache için transaction desteği etkinleştirilmesi için, cache yapılandırmasında atomicityMode
parametresi TRANSACTIONAL
olarak ayarlanabilir. Detaylı bilgi için Atomicity Modes bölümüne bakabilirsiniz.
Transactionlar, bir veya daha fazla key’deki birden çok cache işlemini tek bir atomik işlemde gruplandırmaya olanak tanır. Bu işlemler, belirtilen keylerde başka serpiştirilmiş işlemler olmadan yürütülür ve ya tümü başarılı olur ya da tümü başarısız olur. İşlemlerin parçalı olarak yürütülmesi söz konusu değildir.
Cache yapılandırmasında belirli bir önbellek için transactionlar etkinleştirilebilir;
- ⌨️ XML Config
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="transactionConfiguration">
<bean class="org.apache.ignite.configuration.TransactionConfiguration">
<!--Set the timeout to 20 seconds-->
<property name="TxTimeoutOnPartitionMapExchange" value="20000"/>
</bean>
</property>
</bean> - ⌨️ .NET Config
var cfg = new IgniteConfiguration
{
CacheConfiguration = new[]
{
new CacheConfiguration("txCache")
{
AtomicityMode = CacheAtomicityMode.Transactional
}
},
TransactionConfiguration = new TransactionConfiguration
{
DefaultTransactionConcurrency = TransactionConcurrency.Optimistic
}
};
Executing Transactions
Key/Value API'si, transactionları başlatma ve tamamlamanın yanı sıra transaction ile ilgili metrikleri almak için bir interface sağlar. Interface, bir Ignite nesnesinden elde edilebilir.
- ⌨️ .NET Sample
var cfg = new IgniteConfiguration
{
DiscoverySpi = new TcpDiscoverySpi
{
LocalPort = 48500,
LocalPortRange = 20,
IpFinder = new TcpDiscoveryStaticIpFinder
{
Endpoints = new[]
{
"127.0.0.1:48500..48520"
}
}
},
CacheConfiguration = new[]
{
new CacheConfiguration
{
Name = "cacheName",
AtomicityMode = CacheAtomicityMode.Transactional
}
},
TransactionConfiguration = new TransactionConfiguration
{
DefaultTimeoutOnPartitionMapExchange = TimeSpan.FromSeconds(20)
}
};
var ignite = Ignition.Start(cfg);
var cache = ignite.GetCache<string, int>("cacheName");
cache.Put("Hello", 1);
var transactions = ignite.GetTransactions();
using (var tx = transactions.TxStart())
{
int hello = cache.Get("Hello");
if (hello == 1)
{
cache.Put("Hello", 11);
}
cache.Put("World", 22);
tx.Commit();
}
Concurrency Modes and Isolation Levels
TRANSACTIONAL
atomicity moduna sahip cacheler, transactionlar için hem OPTIMISTIC
hem de PESSIMISTIC
eşzamanlılık(concurrency) modlarını destekler. Eşzamanlılık modu, giriş düzeyinde bir transaction kilidinin ne zaman alınacağını belirler: veri erişimi sırasında veya hazırlık aşamasında. Kilitleme, bir nesneye eşzamanlı erişimi engeller. Örneğin, pessimistic kilitleme ile bir ToDo list öğesini güncellemeye çalıştığınızda, siz transaction’u commitleyene veya rollback yapana kadar sunucu nesneye bir kilit yerleştirir ve başka hiçbir işlem veya işlemin aynı girişi güncellemesine izin verilmez. Bir transactionda kullanılan eşzamanlılık modundan bağımsız olarak, transactionda listelenen tüm girişlerin committen önce kilitlendiği bir an vardır.
Izolasyon(isolation) düzeyi, eşzamanlı transactionların aynı keyler üzerindeki işlemleri nasıl 'gördüğünü' ve ele aldığını tanımlar. Ignite, READ_COMMITTED
, REPEATABLE_READ
ve SERIALIZABLE
izolasyon seviyelerini destekler.
Eşzamanlılık modlarının ve izolasyon düzeylerinin tüm kombinasyonlarına izin verilir. Aşağıda, sistem davranışının açıklaması ve her bir eşzamanlılık-izolasyon kombinasyonu tarafından sağlanan garantiler yer almaktadır.
Pessimistic Transactions
PESSIMISTIC
transactionlarda kilitler, ilk okuma veya yazma erişimi sırasında (izolasyon seviyesine bağlı olarak) alınır ve commit edilene veya rollback olana kadar transaction tarafından tutulur. Bu modda, kilitler önce birincil node’larda alınır ve ardından hazırlık aşaması sırasında yedek node’lara yükseltilir. Aşağıdaki izolasyon seviyeleri, PESSIMISTIC
eşzamanlılık modu ile yapılandırılabilir:
READ_COMMITTED →
Veriler kilitlenmeden okunur ve hiçbir zaman transaction’ın kendisinde cache’e alınmaz. Cache yapılandırmasında buna izin veriliyorsa, veriler bir yedekleme node’undan okunabilir. Bu izolasyon modunda, Tekrarlanamayan Okumalara sahip olabilirsiniz çünkü eşzamanlı bir transaction, transactionunuzda verileri iki kez okurken verileri değiştirebilir. Kilit, yalnızca ilk yazma erişimi sırasında alınır (bu,EntryProcessor
çağrısını içerir). Bu, transaction sırasında okunan bir girişin, transaction’ın gerçekleştirildiği zamana kadar farklı bir değere sahip olabileceği anlamına gelir. Bu durumda herhangi bir hata oluşmaz.REPEATABLE_READ →
Giriş kilidi alınır ve veriler ilk okuma veya yazma erişimindeki birincil node’dan alınır ve yerel transaction haritasında(local transaction map) depolanır. Aynı verilere ardışık tüm erişimler yereldir ve son okunan veya güncellenen transaction değerini döndürür. Bu, başka hiçbir eşzamanlı transaction’ın kilitli verilerde değişiklik yapamayacağı ve transactionınız için Tekrarlanabilir Okumalar alacağınız anlamına gelir.SERIALIZABLE →
PESSIMISTIC
modunda, bu izolasyon seviyesiREPEATABLE_READ
ile aynı şekilde çalışır.
PESSIMISTIC
modunda kilitleme sırasının önemli olduğunu unutmayın. Ayrıca kilitler sırayla ve tam olarak belirtilen sırada alınır.
En az bir
PESSIMISTIC
transaction kilidi elde edilirse, transaction commitlenene veya rollback olana kadar cache topolojisini değiştirmenin imkansız olduğunu unutmayın. Bu nedenle, transaction kilitlerini uzun süre tutmaktan kaçınmalısınız.
Optimistic Transactions
OPTIMISTIC
transactionlarda, 2PC'nin ilk aşamasında, hazırlık adımında birincil node’larda giriş kilitleri alınır ve ardından yedek nodelara yükseltilir ve transaction tamamlandıktan sonra serbest bırakılır. Transaction’ı geri alırsanız ve hiçbir commit girişiminde bulunulmazsa kilitler asla alınmaz. OPTIMISTIC
eşzamanlılık modu ile aşağıdaki izolasyon seviyeleri yapılandırılabilir:
READ_COMMITTED →
Cache’e uygulanması gereken değişiklikler kaynak node’da toplanır ve transaction commitinde uygulanır. Transaction verileri kilitlenmeden okunur ve transactionda asla cache’e alınmaz. Cache yapılandırmasında buna izin veriliyorsa, veriler bir yedekleme node’undan okunabilir. Bu izolasyonda, Tekrarlanamayan Okumalara sahip olabilirsiniz çünkü eşzamanlı bir transaction, transactionınınızda verileri iki kez okurken verileri değiştirebilir. Bu mod kombinasyonu, giriş değerinin ilk okuma veya yazma erişiminden bu yana değiştirilip değiştirilmediğini kontrol etmez ve asla optimistic bir hata oluşturmaz.
REPEATABLE_READ →
Bu yalıtım düzeyindeki transactionlar, tek bir farkla OPTIMISTIC
READ_COMMITTED
işlemlerine benzer şekilde çalışır: okuma değerleri kaynak node’da cache’e alınır ve sonraki tüm okumaların yerel olması garanti edilir. Bu mod kombinasyonu, giriş değerinin ilk okuma veya yazma erişiminden bu yana değiştirilip değiştirilmediğini kontrol etmez ve asla optimistic bir hata oluşturmaz.
SERIALIZABLE →
İlk okuma erişimi üzerine bir giriş sürümünü saklar. Ignite motoru, başlatılan transaction’ın bir parçası olarak kullanılan girdilerden en az birinin değiştirildiğini algılarsa, Ignite işlemi tamamlama aşamasında başarısız olur. Kısacası, bu, Ignite'ın bir transaction’ın commit aşamasında bir çakışma olduğunu tespit etmesi durumunda, transaction’ı başarısız kılarak TransactionOptimisticException
'ı atması ve yapılan değişiklikleri geri alması anlamına gelir. Bu hatayı handle ettiğinizden emin olun ve transaction’ı yeniden deneyin.
- ⌨️ .NET Sample
var cfg = new IgniteConfiguration
{
DiscoverySpi = new TcpDiscoverySpi
{
LocalPort = 48500,
LocalPortRange = 20,
IpFinder = new TcpDiscoveryStaticIpFinder
{
Endpoints = new[]
{
"127.0.0.1:48500..48520"
}
}
},
CacheConfiguration = new[]
{
new CacheConfiguration
{
Name = "cacheName",
AtomicityMode = CacheAtomicityMode.Transactional
}
},
TransactionConfiguration = new TransactionConfiguration
{
DefaultTimeoutOnPartitionMapExchange = TimeSpan.FromSeconds(20)
}
};
var ignite = Ignition.Start(cfg);
// Re-try the transaction a limited number of times
var retryCount = 10;
var retries = 0;
// Start a transaction in the optimistic mode with the serializable isolation level
while (retries < retryCount)
{
retries++;
try
{
using (var tx = ignite.GetTransactions().TxStart(TransactionConcurrency.Optimistic,
TransactionIsolation.Serializable))
{
// modify cache entries as part of this transaction.
// commit the transaction
tx.Commit();
// the transaction succeeded. Leave the while loop.
break;
}
}
catch (TransactionOptimisticException)
{
// Transaction has failed. Retry.
}
}
Burada dikkat edilmesi gereken bir diğer önemli nokta, bir giriş değiştirilmeden okunsa bile (cache.put(…)
) bir işlemin başarısız olmasıdır, çünkü girişin değeri başlatılan transaction içindeki mantık için önemli olabilir.
READ_COMMITTED
ve REPEATABLE_READ
transactionları için key sırasının önemli olduğunu unutmayın, çünkü bu modlarda kilitler yine sıralı olarak alınır.
Read Consistency
PESSIMISTIC modunda tam okuma tutarlılığı elde etmek için okuma kilitlerinin edinilmesi gerekir. Bu, PESSIMISTIC modundaki okumalar arasındaki tam tutarlılığın yalnızca PESSIMISTIC REPEATABLE_READ (veya SERIALIZABLE) transactionlarıyla sağlanabileceği anlamına gelir.
OPTIMISTIC transactionları kullanılırken, okumalar arasındaki olası çakışmalara izin verilmeyerek tam okuma tutarlılığı sağlanabilir. Bu davranış OPTIMISTIC SERIALIZABLE modu tarafından sağlanır. Ancak, commit gerçekleşene kadar parçalı bir transaction durumunu hala okuyabileceğinizi, bu nedenle transaction mantığının buna karşı koruma sağlaması gerektiğini unutmayın. Yalnızca commit aşamasında, herhangi bir çakışma durumunda, transaction’ı yeniden denemenizi sağlayan bir TransactionOptimisticException
atılır.
PESSIMISTIC REPEATABLE_READ veya SERIALIZABLE transactionları veya OPTIMISTIC SERIALIZABLE transactionları kullanmıyorsanız parçalı transaction durumu görmeniz mümkündür. Bu, bir transaction A ve B nesnelerini güncellerse, başka bir transaction’un A için yeni değeri ve B için eski değeri görebileceği anlamına gelir.
Deadlock Detection
Dağıtık transactionlarda çalışırken bilmeniz gereken önemli bir kural, bir transactiona katılan keylerin kilitlerinin aynı sırada alınması gerektiğidir. Bu kuralı ihlal etmek, dağıtık bir deadlock’a yol açabilir.
Ignite, dağıtık deadlocklardan kaçınmaz, bunun yerine bu tür durumlarda hata ayıklamayı ve düzeltmeyi kolaylaştıran built-in işlevselliğe sahiptir.
Aşağıdaki kod parçacığında, zaman aşımı ile bir transaction başlatıldı. Zaman aşımı sona ererse, deadlock algılama prosedürü, zaman aşımına neden olabilecek olası bir deadlock bulmaya çalışır. Zaman aşımı süresi dolduğunda, deadlocktan bağımsız olarak CacheException
'ın nedeni olarak TransactionTimeoutException
oluşturulur ve fırlatılır. Bununla birlikte, bir deadlock algılanırsa, döndürülen TransactionTimeoutException
'ın nedeni TransactionDeadlockException
olacaktır (deadlock’a dahil olan en az bir transaction için).
- ⌨️ .NET Sample