Dağıtık Sistemler & Zaman Yönetimi 6 dk okuma 1 okunma

Dağıtık Sistemlerde Clock Skew ve Monotonik Saatler

Dağıtık sistemlerde fiziksel saatler NTP ile senkronize edilse bile düğümler arasında kayabilir; buna clock skew denir. Bu kayma sıralama, timeout ve dağıtık kilitlerde ciddi sorunlara yol açar. Monotonik saatler (Stopwatch, TimeProvider.GetTimestamp) yalnızca ileri gider ve süre ölçümü için güvenlidir; mutlak zaman için duvar saati kullanılmalıdır. Lamport, Vector ve Hybrid Logical Clocks ise nedensel sıralamayı sağlar.

Dağıtık Sistemlerde Clock Skew ve Monotonik Saatler

Dağıtık Sistemlerde Clock Skew ve Monotonik Saatler

Dağıtık sistemlerde zaman, göründüğü kadar basit değildir. Her düğümün kendi fiziksel saati vardır ve bu saatler NTP ile senkronize edilse bile mükemmel değildir. İki düğüm arasındaki saat farkına clock skew (saat kayması) denir. Bu kayma; sıralama (ordering), timeout, dağıtık kilitleme ve event sıralaması gibi kritik işlemlerde ciddi sorunlara yol açar.


1. Fiziksel Saatler Neden Güvenilmez?

Her bilgisayarın donanımında bir gerçek zamanlı saat (RTC) bulunur. Bu saat, bir kuvars osilatörüne dayanır ve şu nedenlerle kayabilir:

  • Sıcaklık değişimleri: Osilatörün frekansı sıcaklıkla değişir.

  • Donanım yaşı: Osilatör zamanla yaşlanır.

  • NTP senkronizasyonu: Saati periyodik düzeltir, ancak ani sıçramalara (clock jump) yol açabilir.

  • Sanallaştırma: VM'lerde saat, hipervizör tarafından yönetilir; ek gecikmeler oluşabilir.

Tipik Clock Skew Değerleri:

  • İyi senkronize edilmiş bir cluster'da: 1-10 milisaniye

  • NTP olmadan: saniyeler, dakikalar hatta saatler


2. Clock Skew'in Yol Açtığı Sorunlar

A. Sıralama (Ordering) Sorunu
İki düğümde meydana gelen olayların sırasını belirlemek istediğinizde, saatler kaymışsa yanlış sıralama yaparsınız. Sistem, gerçekte sonra olan bir olayı önce sanabilir.

B. Timeout ve Distributed Locking Sorunu
Dağıtık kilitleme sistemlerinde kilit süresi (TTL) yerel saate göre hesaplanır. İki düğümün saati farklıysa, kilit süresi doldu sanılabilir ama aslında dolmamıştır. Bu, çit sorunu (fencing problem) olarak bilinir.

C. Event Sourcing ve Audit Log Sorunu
Event'lerin zaman damgalarına göre sıralandığı sistemlerde clock skew yanlış sıralamaya yol açar.

D. Last-Write-Wins (LWW) Çakışma Çözümü
Saatler kaymışsa, "en son" yanlış belirlenir ve veri kaybı olur.


3. Monotonik Saatler (Monotonic Clocks)

Monotonik saat, duvar saatinden bağımsız olarak yalnızca ileriye doğru ilerleyen bir saattir. Sistem saati NTP ile geriye alınsa bile monotonik saat etkilenmez.

Özellikler:

  • Her Zaman İleri: Asla geriye gitmez.

  • Süre Ölçümü İçin İdeal: İki olay arasındaki süreyi doğru ölçer.

  • Mutlak Zaman Değil: "Saat kaç?" değil, "ne kadar süre geçti?" sorusunu yanıtlar.

.NET'te Monotonik Saat:

csharp

// Stopwatch - monotonik saat
var stopwatch = Stopwatch.StartNew();
await DoWorkAsync();
stopwatch.Stop();
Console.WriteLine($"İşlem süresi: {stopwatch.ElapsedMilliseconds}ms");

// Environment.TickCount64 - monotonik (64-bit)
var start = Environment.TickCount64;
await DoWorkAsync();
var elapsed = Environment.TickCount64 - start;

// .NET 8+ TimeProvider ile
var timeProvider = TimeProvider.System;
var timestamp = timeProvider.GetTimestamp();
await DoWorkAsync();
var elapsed = timeProvider.GetElapsedTime(timestamp);

Ne Zaman Monotonik Saat Kullanılmalı?

  • Timeout ölçümü

  • Performans ölçümü (benchmark)

  • Retry backoff hesaplaması

  • Circuit breaker süreleri

  • Cache TTL (yerel)

Ne Zaman Duvar Saati Kullanılmalı?

  • Kullanıcıya gösterilecek zaman damgaları

  • Audit log (mutlak zaman gerekli)

  • Veritabanı kayıt zamanı (created_at)

  • Cron job zamanlaması


4. Lamport Saatleri (Mantıksal Saatler)

Fiziksel saatler güvenilmez olduğunda, mantıksal saatler devreye girer. Lamport saati, olayların nedensel sırasını (causal ordering) belirlemek için kullanılan bir sayaçtır.

Kurallar:

  1. Her düğümün bir sayacı vardır (başlangıçta 0).

  2. Her yerel olayda sayaç 1 artırılır.

  3. Mesaj gönderirken, gönderen sayaç değerini mesaja ekler.

  4. Mesaj alındığında, alıcı sayacını max(kendi_sayacı, gelen_sayac) + 1 olarak günceller.

Sınırı: Lamport(A) < Lamport(B) ise A'nın B'den önce olduğu kesin değildir (eşzamanlı olabilirler).


5. Vector Clocks (Vektör Saatleri)

Vector clocks, Lamport saatlerinin sınırını aşarak eşzamanlılık (concurrency) tespiti yapar. Her düğüm, tüm düğümlerin sayaçlarını içeren bir vektör tutar.

Karşılaştırma:

  • V1 < V2 ise: V1, V2'den önce.

  • V1 > V2 ise: V1, V2'den sonra.

  • Aksi halde: Eşzamanlı (concurrent) — çakışma var!

Vector clocks, DynamoDB ve Riak gibi sistemlerde çakışma tespiti için kullanılır.


6. Hybrid Logical Clocks (HLC)

HLC, fiziksel saatin yakınlığını ve mantıksal saatin nedensel sıralamasını birleştirir. CockroachDB, MongoDB ve YugabyteDB gibi modern dağıtık veritabanları HLC kullanır.

Çalışma Prensibi:

  • HLC, bir (physical_time, logical_counter) çiftidir.

  • Fiziksel saat ilerledikçe HLC de ilerler.

  • Aynı fiziksel zaman içinde birden fazla olay olursa, logical counter artırılır.

  • Bir düğümün saati gerideyse, diğer düğümün HLC'sini alarak senkronize olur.

Avantajları: Fiziksel saate yakın (okunabilir zaman damgaları), nedensel sıralama garantisi, clock skew'e karşı dayanıklılık.


7. .NET'te Zaman Yönetimi En İyi Pratikleri

A. TimeProvider (.NET 8+) Kullanın

TimeProvider, test edilebilir zaman soyutlamasıdır.

csharp

public class OrderService
{
    private readonly TimeProvider _timeProvider;

    public OrderService(TimeProvider timeProvider)
    {
        _timeProvider = timeProvider;
    }

    public async Task<Order> CreateOrderAsync(CreateOrderCommand command)
    {
        var now = _timeProvider.GetUtcNow();          // Test edilebilir
        var timestamp = _timeProvider.GetTimestamp(); // Monotonik

        var order = new Order { CreatedAt = now, ... };
        await SaveAsync(order);

        var elapsed = _timeProvider.GetElapsedTime(timestamp);
        _logger.LogInformation("Sipariş oluşturma süresi: {Elapsed}", elapsed);

        return order;
    }
}

// Test'te FakeTimeProvider kullanımı
var fakeTime = new FakeTimeProvider();
fakeTime.SetUtcNow(new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero));
var service = new OrderService(fakeTime);

B. Timeout için Stopwatch Kullanın

csharp

// ❌ YANLIŞ - Duvar saati kullanımı
var start = DateTime.UtcNow;
await DoWorkAsync();
if (DateTime.UtcNow - start > TimeSpan.FromSeconds(5))
    throw new TimeoutException();

// ✅ DOĞRU - Monotonik saat kullanımı
var stopwatch = Stopwatch.StartNew();
await DoWorkAsync();
if (stopwatch.Elapsed > TimeSpan.FromSeconds(5))
    throw new TimeoutException();

C. Distributed Locking'de Fencing Token

csharp

var lockHandle = await _distributedLock.AcquireAsync("resource");
var fencingToken = lockHandle.FencingToken; // Monotonik

await _resource.WriteAsync(data, fencingToken);
// Kaynak, daha düşük token'lı istekleri reddeder

D. Event Sourcing'de Zaman Damgaları

csharp

public record OrderCreatedEvent(
    Guid OrderId,
    DateTimeOffset OccurredAt,   // Duvar saati (audit)
    long SequenceNumber,          // Monotonik sıra numarası
    string CorrelationId
);

Event'lerin sıralaması için sequence number kullanın, zaman damgasına güvenmeyin.


8. En İyi Pratikler

Pratik Açıklama
Süre ölçümü için monotonik saat kullanın Stopwatch, Environment.TickCount64, TimeProvider.GetTimestamp()
Mutlak zaman için duvar saati kullanın Audit log, kullanıcıya gösterilecek zaman damgaları
Sıralama için mantıksal saat kullanın Lamport, Vector Clock veya HLC
NTP ile saatleri senkronize edin Tüm düğümlerde NTP aktif olsun
Zaman damgalarını UTC saklayın Yerel saat dilimleri karışıklık yaratır
Sequence number kullanın Event sıralaması için zaman damgasına güvenmeyin
Fencing token kullanın Distributed locking'de clock skew'e karşı koruma
TimeProvider ile test edilebilir olun Zaman bağımlı kodları test edilebilir hale getirin
Clock skew'i izleyin Düğümler arası saat farkını metrik olarak izleyin

9. Gerçek Dünya Senaryosu: E-Ticaret Sipariş Sıralaması

Senaryo: Bir e-ticaret uygulamasında, sipariş event'leri 3 servis tarafından üretiliyor: Order Service, Payment Service ve Shipment Service. Event'ler bir Kafka topic'ine yazılıyor ve sıralı olarak işlenmesi gerekiyor.

Problem: Servislerin saatleri 50ms kaymış. Event'ler yanlış sırada işleniyor.

Çözüm: HLC (Hybrid Logical Clock) veya sequence number kullanın.

csharp

public class HybridLogicalClock
{
    private long _lastPhysicalTime;
    private int _logicalCounter;
    private readonly object _lock = new();

    public (long PhysicalTime, int Counter) Now()
    {
        lock (_lock)
        {
            var physicalNow = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            
            if (physicalNow > _lastPhysicalTime)
            {
                _lastPhysicalTime = physicalNow;
                _logicalCounter = 0;
            }
            else
            {
                _logicalCounter++;
            }

            return (_lastPhysicalTime, _logicalCounter);
        }
    }

    public void Update((long PhysicalTime, int Counter) received)
    {
        lock (_lock)
        {
            var physicalNow = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            var maxPhysical = Math.Max(physicalNow, Math.Max(_lastPhysicalTime, received.PhysicalTime));

            if (maxPhysical == _lastPhysicalTime && maxPhysical == received.PhysicalTime)
                _logicalCounter = Math.Max(_logicalCounter, received.Counter) + 1;
            else if (maxPhysical == _lastPhysicalTime)
                _logicalCounter++;
            else if (maxPhysical == received.PhysicalTime)
                _logicalCounter = received.Counter + 1;
            else
                _logicalCounter = 0;

            _lastPhysicalTime = maxPhysical;
        }
    }
}

Bu sayede, event'ler doğru sırada işlenir; clock skew sorun olmaktan çıkar.


Sonuç

Dağıtık sistemlerde zaman, göründüğü kadar basit değildir. Clock skew, fiziksel saatlerin doğal bir sonucudur ve sıralama, timeout, locking gibi kritik işlemlerde ciddi sorunlara yol açar. Monotonik saatler, süre ölçümü için güvenli tek seçenektir; asla geriye gitmez. Lamport saatleri, Vector Clocks ve Hybrid Logical Clocks, nedensel sıralamayı fiziksel saatlerden bağımsız olarak sağlar. .NET'te Stopwatch, Environment.TickCount64 ve TimeProvider ile monotonik saatleri kullanabilir; TimeProvider ile test edilebilir zaman yönetimi yapabilirsiniz. Unutmayın: Dağıtık sistemlerde "şu an" kavramı, her düğümde farklıdır. Güvenilir sistemler, zamanı bir gerçek olarak değil, bir "tahmin" olarak ele alır ve gerekli önlemleri alır.

Tüm yazılar Soru ya da yorumun mu var? Yaz