Active Directory’de B-tree İndeks Türleri ve Kullanımı

Active Directory ortamlarında yönettiğiniz kullanıcı sayısı birkaç bini geçtiğinde, sorgu performansı can sıkıcı bir sorun haline gelmeye başlar. LDAP sorgularınız yavaşlar, Group Policy uygulamaları gecikir, kullanıcı kimlik doğrulama süreleri uzar. Peki bu sorunların arkasında ne yatar? Büyük ölçüde, Active Directory’nin altında yatan veritabanı motorunun, yani Extensible Storage Engine (ESE)‘nin index yapılarını nasıl kullandığını anlamak gerekir. Bu yazıda B-tree index türünü derinlemesine inceleyeceğiz ve bunu doğrudan Active Directory yönetimiyle ilişkilendireceğiz.

B-tree Nedir ve Neden Active Directory İçin Önemlidir

B-tree, “Balanced Tree” yani dengelenmiş ağaç anlamına gelir. 1970’lerde Rudolf Bayer ve Ed McCreight tarafından geliştirilen bu veri yapısı, büyük veri kümelerinde hızlı arama, ekleme ve silme işlemleri için optimize edilmiştir. Active Directory, arka planda ntds.dit adlı bir ESE (Extensible Storage Engine) veritabanı kullanır. ESE, Microsoft’un kendi geliştirdiği bir veritabanı motorudur ve B-tree index yapısını temel alır.

Neden bu kadar önemli? Çünkü bir Active Directory ortamında on binlerce kullanıcı objesi, binlerce grup, yüzlerce OU ve sayısız attribute bulunabilir. Kullanıcı adı, e-posta adresi veya SID gibi bir attribute üzerinde arama yapıldığında, B-tree index sayesinde bu işlem milisaniyeler içinde tamamlanabilir. Index olmadan yapılan bir arama ise tüm tabloyu baştan sona taramak zorunda kalır. Buna full table scan denir ve büyük ortamlarda felakete davet çıkarmak gibidir.

B-tree’nin İç Yapısı

B-tree yapısını anlamak için birkaç temel kavramı bilmemiz gerekiyor.

Düğüm Tipleri

  • Root Node (Kök Düğüm): Ağacın en üst noktasıdır. Her arama buradan başlar.
  • Internal Node (İç Düğüm): Kök ile yaprak arasındaki düğümlerdir. Yönlendirme bilgisi taşırlar.
  • Leaf Node (Yaprak Düğüm): Asıl veriyi veya veriye işaret eden pointer’ı barındıran en alt düğümlerdir.

Dengeleme Mekanizması

B-tree’nin “balanced” olması, her yaprak düğümün kökten eşit mesafede olduğu anlamına gelir. Bu, herhangi bir veriyi ararken geçilen adım sayısının her zaman aynı olmasını garanti eder. Örneğin 1 milyon kayıt içeren bir B-tree’de herhangi bir kayda ulaşmak için sadece 20 adım yeterli olabilir. Bu özellik, Active Directory gibi sürekli güncellenen ve sorgulanan ortamlar için kritik bir avantajdır.

ESE’nin kullandığı B-tree varyantı aslında B+ tree‘dir. B+ tree’de şu fark bulunur: tüm veri yaprak düğümlerde tutulur, iç düğümler sadece yönlendirme anahtarlarını barındırır. Ayrıca yaprak düğümler birbirine bağlı liste (linked list) şeklinde organize edilmiştir, bu da range sorgularını son derece verimli kılar.

Active Directory’de Index Yapısı: ntds.dit Derinlemesine

Active Directory veritabanı olan ntds.dit, varsayılan olarak şu konumda bulunur:

C:WindowsNTDSntds.dit

Bu veritabanı içinde birden fazla tablo yer alır. En kritik olanları şunlardır:

  • datatable: Tüm AD objelerini ve attribute’larını barındıran ana tablo
  • link_table: Grup üyelikleri gibi ilişkisel verileri tutar
  • sd_table: Security Descriptor bilgilerini saklar

Her attribute için B-tree index oluşturulup oluşturulmadığı, o attribute’ün schema tanımında isMemberOfPartialAttributeSet ve searchFlags değerleriyle belirlenir. searchFlags değerinde ilk bit (0x1) set edilmişse, o attribute için index oluşturulur.

AD schema üzerinde hangi attribute’ların indexlendiğini görmek için PowerShell kullanabilirsiniz:

# Indexlenmiş attribute'ları listele
Get-ADObject -SearchBase "CN=Schema,CN=Configuration,DC=domain,DC=com" `
  -LDAPFilter "(searchFlags:1.2.840.113556.1.4.803:=1)" `
  -Properties lDAPDisplayName, searchFlags | `
  Select-Object lDAPDisplayName, searchFlags | `
  Sort-Object lDAPDisplayName

Bu komut çalıştırıldığında, varsayılan AD kurulumunda yaklaşık 50-70 indexlenmiş attribute göreceksiniz. sAMAccountName, objectSid, mail, userPrincipalName bunların en kritikleridir.

Varsayılan Index’ler ve Performans Üzerindeki Etkisi

Active Directory kurulumunda bazı attribute’lar varsayılan olarak indexlenir. Bunlar özellikle kimlik doğrulama ve arama senaryolarında kullanılan kritik attribute’lardır.

Yaygın olarak indexlenen attribute’lar:

  • sAMAccountName: NetBIOS tabanlı logon ismi
  • objectSid: Güvenlik tanımlayıcısı
  • objectGUID: Global benzersiz tanımlayıcı
  • mail: E-posta adresi
  • userPrincipalName: UPN formatında kullanıcı adı
  • cn (Common Name): Obje ortak adı
  • displayName: Görüntüleme adı
  • givenName: Ad
  • sn (Surname): Soyad

Bu attribute’lar üzerinden yapılan sorgular, B-tree index sayesinde son derece hızlı çalışır. Ancak description, comment veya özel attribute’lar gibi indexlenmemiş alanlar üzerinde yapılan aramalar tam tablo taramasına yol açar.

Gerçek dünya senaryosu olarak şunu düşünün: 50.000 kullanıcılı bir ortamda description alanına göre arama yapan bir script çalıştırıyorsunuz. Bu arama, indexlenmiş bir attribute üzerindeki aynı arama ile karşılaştırıldığında 100 kat daha yavaş olabilir.

Index Oluşturma: Özel Attribute’lar için B-tree Index Nasıl Eklenir

Özel bir attribute oluşturduğunuzda veya mevcut bir attribute’ü indexlemek istediğinizde, schema üzerinde değişiklik yapmanız gerekir. Bu işlem dikkatli yapılmalıdır çünkü her yeni index ntds.dit boyutunu artırır ve DC üzerinde belirli bir CPU ve disk yükü getirir.

Mevcut bir attribute için searchFlags değerini güncellemek:

# Schema Master'ı bul
netdom query fsmo

# Schema üzerinde değişiklik için Schema Admin grubuna üye olmanız gerekir
# searchFlags değerini 1 olarak set et (index ekle)
Set-ADObject -Identity "CN=department,CN=Schema,CN=Configuration,DC=domain,DC=com" `
  -Replace @{searchFlags=1}

Yeni bir attribute oluşturup index eklemek:

# Yeni attribute schema'ya ekle
$schemaPath = "CN=Schema,CN=Configuration,DC=domain,DC=com"
$newAttr = @{
    lDAPDisplayName = "employeeLocation"
    adminDescription = "Custom employee location attribute"
    attributeSyntax = "2.5.5.12"
    isSingleValued = $true
    searchFlags = 1
    oMSyntax = 64
}

New-ADObject -Name "employeeLocation" `
  -Type attributeSchema `
  -Path $schemaPath `
  -OtherAttributes $newAttr

Index oluşturma işlemi schema değişikliğinin ardından hemen gerçekleşmez. ESE, arka planda index build işlemini yürütür. Büyük bir veritabanında bu işlem saatler alabilir. Bu süreçte DC performansı etkilenebilir, bu yüzden bu tür değişiklikleri bakım pencerelerinde yapmayı alışkanlık haline getirin.

B-tree Index Bakımı: Fragmantasyon ve Defragmentasyon

B-tree index’leri, sürekli ekleme, silme ve güncelleme işlemleri sonucunda fragmente olabilir. Bu durum, sorgu performansını zamanla düşürür. Active Directory’de iki tip defragmentasyon söz konusudur.

Online Defragmentasyon

Active Directory, varsayılan olarak her gece garbage collection işlemi sırasında otomatik online defragmentasyon yapar. Bu işlem, boş alanları birleştirir ancak ntds.dit dosyasının boyutunu küçültmez. Online defragmentasyon, DC’nin çalışmasını durdurmadan arka planda gerçekleşir.

Online defragmentasyon ayarlarını kontrol etmek için:

# NTDS servis parametrelerini kontrol et
reg query "HKLMSYSTEMCurrentControlSetServicesNTDSParameters"

# Garbage collection intervali (dakika cinsinden, varsayılan 720 = 12 saat)
reg query "HKLMSYSTEMCurrentControlSetServicesNTDSParameters" /v "Garbage Collection Interval"

Offline Defragmentasyon

Ntds.dit dosyasının boyutunu gerçekten küçültmek ve derin fragmantasyonu gidermek için offline defragmentasyon gerekir. Bu işlem için DC’yi DSRM (Directory Services Restore Mode) moduna almak gerekir.

# Offline defragmentasyon komutu (DSRM modunda çalıştırılır)
ntdsutil "activate instance ntds" files "compact to C:tempntds_compact" quit quit

# Orijinal dosyayı yedekle, compacted versiyonu yerine koy
copy C:WindowsNTDSntds.dit C:Backupntds.dit.bak
copy C:tempntds_compactntds.dit C:WindowsNTDSntds.dit

# Integrity check yap
ntdsutil "activate instance ntds" files integrity quit quit

Gerçek dünyada offline defragmentasyon ne zaman yapılır? Büyük miktarda obje silindikten sonra (örneğin 10.000 kullanıcı hesabı bir anda disabled/deleted yapıldığında) ntds.dit dosyasının boyutu azalmaz. Offline defragmentasyon bu durumda disk alanını geri kazandırır.

LDAP Sorgu Optimizasyonu: Index’lerden Maksimum Yararlanma

B-tree index’lerinin gerçek faydası, LDAP sorgularınızı doğru yazdığınızda ortaya çıkar. Yanlış yazılmış bir LDAP filtresi, index olsa bile full table scan tetikleyebilir.

Index’i Kullanan Sorgular

# Verimli sorgu: indexlenmiş attribute önde
(&(objectClass=user)(sAMAccountName=jsmith))

# PowerShell ile verimli LDAP sorgusu
Get-ADUser -LDAPFilter "(&(objectClass=user)(mail=*@company.com))" `
  -Properties mail, department | Select-Object Name, mail, department

Index’i Kullanmayan Sorgular

# Verimsiz sorgu: wildcard başta kullanmak index bypass'ına yol açar
Get-ADUser -LDAPFilter "(sAMAccountName=*smith)" `
  -Properties * | Select-Object Name

# Bu daha iyi ama yine de dikkatli kullanılmalı
Get-ADUser -LDAPFilter "(sAMAccountName=smith*)" `
  -Properties * | Select-Object Name

Başında wildcard olan aramalar B-tree index’ini kullanamaz çünkü B-tree prefix-based bir yapıya sahiptir. “smith” ile başlayan değerleri hızlıca bulabilir, ancak “smith” ile biten değerleri bulmak için tüm index’i taramak zorunda kalır.

LDAP Sorgu Performansını Test Etme

# ldp.exe ile sorgu süresi ölçümü
# Windows'ta çalıştır
ldp.exe

# Alternatif olarak PowerShell ile süre ölçümü
$start = Get-Date
$result = Get-ADUser -LDAPFilter "(&(objectClass=user)(department=IT))" -Properties department
$end = Get-Date
Write-Host "Sorgu süresi: $(($end - $start).TotalMilliseconds) ms"
Write-Host "Bulunan kayıt sayısı: $($result.Count)"

ESE Database Engine Diagnostics ile Index Analizi

Active Directory’de hangi sorguların index kullanıp hangilerinin kullanmadığını görmek için ESE diagnostics özelliğini etkinleştirebilirsiniz. Bu, performans sorunlarını analiz ederken son derece değerlidir.

# NTDS diagnostics logging seviyesini artır
reg add "HKLMSYSTEMCurrentControlSetServicesNTDSDiagnostics" `
  /v "4 MAPI Interface" /t REG_DWORD /d 2 /f

# Field Engineering logging aktifleştir
reg add "HKLMSYSTEMCurrentControlSetServicesNTDSDiagnostics" `
  /v "15 Field Engineering" /t REG_DWORD /d 5 /f

# Slow query logging için eşik değeri ayarla (ms cinsinden, varsayılan 30000)
reg add "HKLMSYSTEMCurrentControlSetServicesNTDSParameters" `
  /v "Expensive Search Results Threshold" /t REG_DWORD /d 10000 /f

reg add "HKLMSYSTEMCurrentControlSetServicesNTDSParameters" `
  /v "Inefficient Search Results Threshold" /t REG_DWORD /d 1000 /f

Bu ayarları yaptıktan sonra, “Directory Services” event log’unda 1644 event ID’li kayıtları takip edin. Bu event, yavaş veya verimsiz LDAP sorgularını raporlar. Sorgunun hangi attribute’ü kullandığını, kaç kayıt taradığını ve ne kadar sürdüğünü gösterir.

Logları incelemek için:

# Event 1644 kayıtlarını filtrele
Get-WinEvent -LogName "Directory Service" | `
  Where-Object {$_.Id -eq 1644} | `
  Select-Object TimeCreated, Message | `
  Format-List

Tuple Index: B-tree’nin Özel Bir Varyantı

Active Directory’de standart B-tree index’inin yanı sıra Tuple Index adı verilen özel bir index türü daha bulunur. Tuple index, substring aramalarını (ortada wildcard olan aramalar) hızlandırmak için tasarlanmıştır. Örneğin (cn=müller) gibi bir sorgu yaparken tuple index devreye girer.

Bir attribute için tuple index etkinleştirmek:

# searchFlags değerinde 32 (0x20) bitini set et (tuple index ekle)
# Mevcut searchFlags değerine 32 ekle
$currentFlags = (Get-ADObject -SearchBase "CN=Schema,CN=Configuration,DC=domain,DC=com" `
  -LDAPFilter "(lDAPDisplayName=displayName)" `
  -Properties searchFlags).searchFlags

$newFlags = $currentFlags -bor 32
Set-ADObject -Identity "CN=Display-Name,CN=Schema,CN=Configuration,DC=domain,DC=com" `
  -Replace @{searchFlags=$newFlags}

Tuple index, normal B-tree index’e kıyasla daha fazla disk alanı tüketir ve index build süresi daha uzundur. Bu yüzden sadece gerçekten substring aramalarına ihtiyaç duyulan attribute’lar için kullanın.

Gerçek Dünya Senaryosu: 30.000 Kullanıcılı Ortamda Index Optimizasyonu

Bir müşteri projesinde, 30.000 kullanıcılı bir AD ortamında HR uygulamasının LDAP sorgularının son derece yavaş çalıştığını tespit ettik. Uygulama, kullanıcıları costCenter attribute’üne göre filtreliyordu. Bu attribute, şirketin custom schema extension’ı ile eklenmiş ancak indexlenmemişti.

Sorun tespiti:

# 1644 event'lerini kontrol et
Get-WinEvent -LogName "Directory Service" -FilterHashtable @{Id=1644} | `
  Select-Object -First 10 | Format-List TimeCreated, Message

# costCenter attribute'ünün searchFlags değerini kontrol et
Get-ADObject -SearchBase "CN=Schema,CN=Configuration,DC=domain,DC=com" `
  -LDAPFilter "(lDAPDisplayName=costCenter)" `
  -Properties searchFlags, lDAPDisplayName

Tespit ettiğimizde searchFlags değeri 0 idi, yani index yoktu. Bakım penceresinde index ekledik ve ertesi sabah sorgu süresi 8 saniyeden 40 milisaniyeye düştü. Kulağa dramatik gelebilir ama bu tür vaka gerçekten yaşanır ve çözümü son derece basittir.

Index Sayısını Kontrol Altında Tutmak

Her attribute’ü indekslemek cazip gelebilir ancak bu yaklaşım ciddi sorunlara yol açar.

Her yeni index şunları etkiler:

  • ntds.dit boyutu: Her index için ek disk alanı gerekir
  • Yazma performansı: Her veri değişikliğinde tüm indexlerin güncellenmesi gerekir
  • Replication trafiği: Schema değişiklikleri tüm DC’lere replike edilir
  • DC restart süresi: Çok fazla index, DC başlangıç süresini uzatabilir

Genel kural olarak şunu söyleyebiliriz: Bir attribute’ü sadece sorgularınızda filtre olarak kullandığınızda index ekleyin. Salt gösterme amaçlı attribute’lar için index gerekmez.

Mevcut index kullanımını değerlendirmek için:

# Tüm indexlenmiş attribute'ları ve searchFlags değerlerini listele
Get-ADObject -SearchBase "CN=Schema,CN=Configuration,DC=domain,DC=com" `
  -LDAPFilter "(&(objectClass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))" `
  -Properties lDAPDisplayName, searchFlags, adminDescription | `
  Select-Object lDAPDisplayName, searchFlags, adminDescription | `
  Sort-Object lDAPDisplayName | `
  Export-Csv -Path "C:TempAD_Indexed_Attributes.csv" -Encoding UTF8 -NoTypeInformation

Sonuç

B-tree index, Active Directory’nin performans mimarisinin bel kemiğidir. ntds.dit’in altında çalışan ESE motoru, bu yapı sayesinde on binlerce obje arasından milisaniyeler içinde doğru kaydı bulabilir. Bir sysadmin olarak bu mekanizmayı anlamak, hem günlük performans sorunlarını çözmede hem de uzun vadeli kapasite planlaması yaparken size büyük avantaj sağlar.

Öne çıkan pratik çıkarımlar:

  • Event ID 1644‘ü düzenli takip edin, yavaş LDAP sorgularını erkenden yakalayın
  • Özel attribute’larınızda searchFlags değerini kontrol edin, gerektiğinde index ekleyin
  • Substring aramalar için tuple index seçeneğini değerlendirin
  • Online defragmentasyon otomatik çalışır ancak büyük silme işlemlerinin ardından offline defragmentasyon planlayın
  • LDAP filtrelerinizde başta wildcard kullanmaktan kaçının, bu index’i devre dışı bırakır
  • Her schema değişikliğini bakım penceresinde yapın ve öncesinde tam yedek alın

Active Directory yönetiminde performans sorunlarının büyük çoğunluğu, aslında index mekanizmasının doğru anlaşılıp kullanılmamasından kaynaklanır. Bu yazıda anlattıklarımı kendi ortamınıza uyguladığınızda, farkın ne kadar belirgin olduğunu göreceksiniz.

Yorum yapın