Thursday, August 9th, 2007...9:52 pm

System.DirectoryServices i connection pooling

Jump to Comments

Connection pooling (napewno jest na to jakieÅ› polskie okreÅ›lenie – muszÄ™ sprawdzić) to w skrócie mechanizm pozwalajÄ…cy na ponowne wykorzystywanie przez aplikacjÄ™ raz nawiÄ…zanych poÅ‚Ä…czeÅ„ do systemu, z którym siÄ™ ona komunikuje. ProgramiÅ›ci .NET (i pewnie w innych jÄ™zykach też) pracujÄ…cy z SQL Server powinni być raczej zaznajomieni z tym mechanizmem, jako że w .NET, w przypadku nawiÄ…zywania poÅ‚Ä…czenia do serwera SQL używany jest wÅ‚aÅ›nie ten mechanizm, aby zminimalizować liczbÄ™ nawiÄ…zywanych poÅ‚Ä…czeÅ„.

Dlaczego? Ano dlatego, że nawiÄ…zanie poÅ‚Ä…czenia sieciowego w obecnym Å›wiecie systemów jest stosunkowo drogÄ… operacjÄ… – dlatego warto jej unikać jeżeli jest to możliwe. Zyskuje na tym wydajność aplikacji.

Ostatnio poprawiaÅ‚em maÅ‚y fragment wiÄ™kszego kodu korzystajÄ…cego z S.DS, a którego zadaniem jest enumeracja atrybutów dla dużej liczby użytkowników Active Directory. Po pewnych zmianach okazaÅ‚o siÄ™, że przy dużej liczbie obiektów serwer AD w pewnym momencie przestaje odpowiadać. Po krótkim Å›ledztwie okazaÅ‚a siÄ™, że przyczynÄ… jest duża liczba poÅ‚Ä…czeÅ„ nawiÄ…zywanych przez aplikacjÄ™ co prowadziÅ‚o do wyczerpania domyÅ›lnej liczby 5000 poÅ‚Ä…czeÅ„ z systemu. ZwiÄ™kszenie tej wartoÅ›ci rozwiÄ…zaÅ‚o problem … ale to nie byÅ‚o rozwiÄ…zanie. Kod wyglÄ…daÅ‚ mniej wiÄ™cej tak:

using (DirectoryEntry member = new DirectoryEntry())
{
member.Username = userName;
member.Password = userPwd;
member.AuthenticationType = AuthenticationTypes.Secure;

foreach (string dn in dns)
{
member.Path = “LDAP://” + ldapHostName”/” + dn;
Guid guid = new Guid((byte[])member.Properties[“objectGUID”].Value);
Console.WriteLine(guid.ToString(“B”));
}
}

Nic wielkiego … lista DN i enumeracja atrybutu dla każdego obiektu z listy.

Przyznam się że chwilę zajęło mi dojście dlaczego tak się dzieje, ponieważ z mojego puntku widzenia i wiedzy wynikało, że to powinno działać. S.DS powinno używać ponownie tego samego połączenia tak długo jak:

  • poÅ‚Ä…czenie jest wykonywane w kontekÅ›cie zabezpieczeÅ„ tego samego użytkownika
  • poÅ‚Ä…czenie jest wykonywane z użyciem tego samego typu uwierzytelnienia.

Jak dla mnie wszystko wyglÄ…daÅ‚o OK. OczywiÅ›cie okazaÅ‚o siÄ™ że nie byÅ‚o. S.DS bÄ™dzie używaÅ‚o tego samego poÅ‚Ä…czenia tak dÅ‚ugo, jak bÄ™dzie istniaÅ‚ conajmniej jeden obiekt korzystajÄ…cy z tego poÅ‚Ä…czenia – na przykÅ‚ad DirectoryEntry z poÅ‚Ä…czeniem do rootDSE. MaÅ‚a modyfikacja kodu i wszystko zadziaÅ‚aÅ‚o tak jak należy:

using(DirectoryEntry rootEntry = new DirectoryEntry(

“LDAP://” + ldapHostName/rootDSE”,
userName,
userPwd,
AuthenticationTypes.Secure))
{
rootEntry.RefreshCache();
using (DirectoryEntry member = new DirectoryEntry())
{
member.Username = userName;
member.Password = userPwd;
member.AuthenticationType = AuthenticationTypes.Secure;

foreach (string dn in dns)
{
member.Path = “LDAP://w2k.pl/” + dn;
Guid guid = new Guid((byte[])member.Properties[“objectGUID”].Value);
Console.WriteLine(guid.ToString(“B”));
}
}
}

Pamiętać należy tutaj jeszcze tylko o tym, że DirectoryEntry używa lazy bind więc po utworzeniu obiektu należy wykonać odwołanie do tego obiektu, na przykład używając RefreshCache.

Jak to wpÅ‚ywa na wydajność … przykÅ‚ad z życia wziÄ™ty (czyli z moich testów). Operacja wykonywana przez mojÄ… aplikacje (w Å›rodowisku maszyny wirtualnej na laptopie, z 384MB RAM) dla 80k obiektów w “bÅ‚Ä™dnym” przypadku zajmowaÅ‚a 2h 48m . Po wykonaniu opisanej zmiany ta sama operacja wykonana zostaÅ‚a w 56m,

Tak wiÄ™c … warto unikać nawiÄ…zywania poÅ‚Ä…czeÅ„ kiedy tylko jest to możliwe.

Brak doÅ›wiadczenia developerskiego czasami daje znać o sobie :), ale staram siÄ™ … staram :).

Leave a Reply