16 Mart 2011 Çarşamba

[Rehber Makale] Distributed Transaction

Merhaba Arkadaşlar;

[Rehber Makale]'ler ile sizlere özel bir konu hakkında bilgi tekrarı olmadan, sizlere pratik tecrübelerimi aktardığım makaleler ulaştırmayı planlıyorum.

Nedir bu Distributed Transaction?

Bir uygulamada oluşan kayıtların birden fazla ve/veya birbirinden farklı markalardaki kayıtların tek bir transaction içerisinde işlem görmesidir. Bizim burada inceleyeceğimiz kısım; WCF üzerindeki uygulamalarıdır.

 

Başlangıç için okunması gereken makaleler:

1. WCF - Transaction Yonetimi (Transaction Management) – 1

2. WCF - Transaction Yonetimi (Transaction Management) – 2

3. 6 steps to enable transactions in WCF

Bu makaleler başlangıç için oldukça iyi fikir verecektir.

Önemli olan sadece bir kaç nokta vardır: WCF Binding Transaction ayarı; 1-2 attribute

Distributed Transaction Coordinator (MSDTC.exe)

Microsoft tarafında distributed transaction görevini üstlenen araçtır. Default olarak Windows sistemlerde kurulu bir servistir... Servislerde yukarıdaki isimlerle görüntüleyebilirsiniz. Com üzerinden iletişime geçilir. (Ki .Net ‘de arka planda Com üzerinden iletişime geçmektedir.) Yapı hakkında net bilgiler veremiyor olsam da şunu söyleyebilirim. WCF üzerinden bir Distributed Transaction(DT) isteğinde bulunduğunuzda(ki TransactionScope bunun için yeterlidir) MSDTC Database dahil tüm transaction işlemlerini kendisi yönetir. Sql Server ve Oracle kendi servisleri aracılığıyla; DTC için API’lar sağlamışlardır. (Oracle için Oracle Client’ın custom kurulumunda görebileceğiniz OracleMTSRecoveryService- MTS(Microsoft Transaction Server)) servisi ile gerçekleşir.

Oracle’ın işi tam olarak nasıl yürüttüğü ile ilgili Oracle® Services for Microsoft Transaction Server Developer's Guide adlı güzel bir kitabı var. Bu kitapta gördüğüm ve DTC’ye ait tek şema aşağıdaki resim bir çok konuda bilgi sahibi etmekte bizleri:

image

 

Sorun çözmek üzerine

MSDTC’nin en kötü yanlarından bir tanesi de sorunun ne olduğunu anlamanın zorluğu... MSDTC’nin çalışmasını gördüğümüz 2 yer var:

1- Component Services(Control Panel’a Administrative Tools) üzerinden

a. Computer - My Computer – Distributed Transaction C.. - Local DTC – Transaction Statistics bölümün de erişiebilirsiniz.

b. Tüm transactionları görebilmek için Local DTC’nin sağ tuş Properties – Trace sekmesinde “Trace All Transactions”ı seçmelisiniz.

c. Statistics ekranındaki verileri sıfırlamak için servisi restart etmeniz gerekli

2- Daha ayrıntılı bilgi için C:\Windows\System32\Msdtc\Trace altında bir log dosyası oluşturuyor.Bu dosyayı okumak için şu makaleyi kullanabilirsiniz. Kısa ayrıntılar aşağıda:

a. Tracemft dosyası için Windows XP Service pack 2 Support Tools’u adresinden indirebilirsiniz. WinRar gibi bir araçla açıp Tracefmt.exe ve traceprt.dll dosyalarını yukarıdaki belirtilen dosya yoluna atın.

b. Eski logları arşivlemek için Component Services’da Local DTC Prop’da Logging Options bölümünde Stop Session – New Session diyebilirsiniz. Eski loglar bir dosyaya atılır.

c. Yaptığınız işleme ait güncel logu dosyadan okuyabilmek için Local DTC’den ‘Flush’ diyerek buffer’dakilerin yazılmasını sağlayabilirsiniz.

d. msdtcvtr –tracelog dtctrace.log –o aa diyerek çalıştırabilir ve logları inceleyebilirsiniz.

3- Sql Server’da çalışıyorsanız; SQL Profiler’da trace etmek için Event’lar arasından (TransactionsàDTC Transactions)’ı seçerseniz DTC transaciton çağrılarını inceleyebilirsiniz.

C# tarafında yazdığınız kodlar üzerinde ise aşağıdaki yöntemleri kullanarak sorunu algılamaya çalışabilirsiniz.

1- Aldığınız hatanın Inner Exception’ında Com hata (hexadecimal)kodunu şuraya sorabilirsiniz.

2- TransactionScope içerisinde o anki transaction’a yakalamak için “Transaction.Current” demeniz yeterlidir.(System.Transactions.dll’i refere etmeniz gerekebilir.)

a. Altındaki TransactionInformation Distributed ID dahil olmak üzere yeterli bilgi vermektedir.

b. Transaction Status’une buradan bakabilirsiniz.

Önemli Not: Debug işlemi uzun sürerse Transaction TimeOut’a düşer.

 

Bilinen Hatalar

Aynı TransactionScope içerisinde hem başka bir WCF servisi çağrılır hemde DB’ye(OracleConnection ile) bağlanılmaya çalışılırsa; connection transaction commit edilmeden kapatılmaması gerekiyor. Aşağıdaki kod örneği bunu açıklıyor:

Bu hatayı temel olarak şu şekilde yakaladım:

1- Transaction.Current.TransactionInformation altındaki Status property’sine Watch ekledim. Kısa bir takip sonucu sorun; ortaya çıktı.

ImyServiceClient myClient = new ImyServiceClient();

using (TransactionScope TranScope = new TransactionScope(TransactionScopeOption.Required))
{
try
{
myClient.AddRecord();
Connection = new OracleConnection(ConnectionString);
Command = new OracleCommand(Query);
Connection.Open();
Command.ExecuteNonQuery();
//Yanlış yerde
//Connection.Close();
TranScope.Complete();
//Doğru yer.
Connection.Close();

}

catch (Exception)
{
TranScope.Dispose();
throw;
}
}


İp Ucu : Servis üzerinden çağrımlarda; Connection.Close() edilme komutu verilmiş olsa dahi; transaction’dan haber bekliyor. Ancak aynı yerde hem yeni bir servis çağrımı hem de direk connection açılması gerekiyorsa yukarıdaki gibi bir sorun ortaya çıkıyor.



İp Ucu: Transaction bittiğinde işlem yapmak istiyorsak; Transaction.Current.TransactionCompleted eventına register olmamız yeterli..

1 yorum: