C# İle Özel Bir Dağıtık İşlem Takip Modülü Nasıl Yapılır?

C# İle Özel Bir Dağıtık İşlem Takip Modülü Nasıl Yapılır?
C# İle Özel Bir Dağıtık İşlem Takip Modülü Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu projeyi hayata geçirmek için geliştirme ortamınızda aşağıdaki araçların ve kütüphanelerin yüklü olması gerekmektedir. Dağıtık işlem takibi, yüksek eşzamanlılık (concurrency) gerektirdiği için performanslı bir veritabanı altyapısı şarttır.

  • .NET 9 SDK: En güncel performans iyileştirmelerini kullanmak için gereklidir.
  • Redis veya PostgreSQL: İşlem loglarını tutmak için hızlı bir yazma kapasitesine sahip olmalıdır.
  • Serilog: Dağıtık izleme verilerini yapılandırılmış loglar (structured logging) halinde tutmak için önerilir.
  • MediatR: Servis içi olayları yönetmek için kullanılacaktır.

Adım 1: İşlem Kimliği (Correlation ID) Oluşturma

Dağıtık bir sistemde, bir isteğin hangi servislerden geçtiğini anlamanın tek yolu, tüm sürece tek bir benzersiz kimlik atamaktır. İlk adımda, gelen her HTTP isteği için bir Correlation ID oluşturacak bir Middleware (ara yazılım) yazacağız.

public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;
    private const string CorrelationIdHeader = "X-Correlation-ID";

    public CorrelationIdMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Request.Headers.TryGetValue(CorrelationIdHeader, out var correlationId))
        {
            correlationId = Guid.NewGuid().ToString();
        }

        context.Items["CorrelationId"] = correlationId;
        context.Response.Headers[CorrelationIdHeader] = correlationId;

        await _next(context);
    }
}

Bu kod, gelen istekte bir ID yoksa otomatik oluşturur ve yanıt başlığına ekler. Böylece istemci tarafı da hata durumunda hangi işlemle ilgili sorun yaşadığını kolayca raporlayabilir.

Adım 2: Dağıtık İşlem Modeli Tasarımı

İşlem takip modülünüzün veritabanında nasıl görüneceğini tanımlamanız gerekir. Bu model, işlemin durumunu (Başarılı, Devam Ediyor, Hata) ve hangi aşamada olduğunu tutmalıdır.

public class DistributedTransaction
{
    public Guid Id { get; set; }
    public string CorrelationId { get; set; }
    public string ServiceName { get; set; }
    public string Status { get; set; } // Started, Completed, Failed
    public DateTime Timestamp { get; set; }
    public string Details { get; set; }
}

Bu model, veritabanına kaydedilecek temel şemayı temsil eder. Details alanı, hata mesajlarını veya işlemle ilgili meta verileri JSON formatında saklamak için kullanılmalıdır.

Adım 3: İşlem Durumunu Kaydetme Servisi

Her servisin kendi işlem durumunu merkezi bir yere bildirmesi gerekir. Bunun için bir ITransactionLogger arayüzü oluşturup, bunu bir arka plan kuyruğu veya doğrudan veritabanı erişimiyle yapılandıracağız.

public interface ITransactionLogger
{
    Task LogAsync(string correlationId, string status, string details);
}

public class TransactionLogger : ITransactionLogger
{
    private readonly DbContext _context;
    public TransactionLogger(DbContext context) => _context = context;

    public async Task LogAsync(string correlationId, string status, string details)
    {
        var log = new DistributedTransaction { 
            CorrelationId = correlationId, 
            Status = status, 
            Details = details,
            Timestamp = DateTime.UtcNow 
        };
        _context.Transactions.Add(log);
        await _context.SaveChangesAsync();
    }
}

Burada dikkat edilmesi gereken nokta, veritabanı işlemlerinin ana iş akışını yavaşlatmamasıdır. Büyük ölçekli sistemlerde, bu loglama işlemini Channel veya RabbitMQ gibi bir mesaj kuyruğu üzerinden asenkron yapmanız önerilir.

Adım 4: Dağıtık İşlem Takip Yöntemleri Karşılaştırması

Farklı takip yaklaşımlarının avantaj ve dezavantajlarını anlamak, projenizin ölçeklenebilirliği için kritiktir.

Yöntem Avantaj Dezavantaj
Veritabanı Odaklı Basit kurulum, ACID uyumu Yüksek trafik altında darboğaz
Mesaj Kuyruğu (Event-Driven) Yüksek performans, ölçeklenebilir Karmaşık altyapı yönetimi
Distributed Tracing (OpenTelemetry) Standart, görselleştirme araçları Öğrenme eğrisi yüksek

Adım 5: Hata Yönetimi ve Güvenlik Uyarıları

Dağıtık sistemlerde hata yönetimi, sistemin güvenliği ile doğrudan ilişkilidir. Hata detaylarını loglarken kişisel verilerin (PII) sızmamasına dikkat etmelisiniz.

Kritik Güvenlik Uyarısı: Loglama sırasında asla kullanıcı şifreleri, kredi kartı numaraları veya kişisel kimlik verilerini ham metin olarak kaydetmeyin. Veritabanına yazmadan önce hassas verileri maskeleyen bir "Data Masking" katmanı kullanın. SQL Injection riskine karşı her zaman Entity Framework Core'un sağladığı parametreli sorguları kullanın.
// Hassas veriyi maskeleme örneği
private string MaskSensitiveData(string input)
{
    if (string.IsNullOrEmpty(input)) return string.Empty;
    return input.Length > 4 ? "****" + input.Substring(input.Length - 4) : "****";
}

Adım 6: Test ve Doğrulama

Modülünüzü test etmek için XUnit kullanarak bir entegrasyon testi yazmalısınız. İşlemin servisler arası geçişini simüle eden bir test senaryosu oluşturun.

[Fact]
public async Task Should_Log_Transaction_Correctly()
{
    var logger = new TransactionLogger(mockContext);
    var correlationId = Guid.NewGuid().ToString();

    await logger.LogAsync(correlationId, "Started", "İşlem başladı");

    var log = await mockContext.Transactions.FirstOrDefaultAsync(x => x.CorrelationId == correlationId);
    Assert.NotNull(log);
    Assert.Equal("Started", log.Status);
}

Sıkça Sorulan Sorular

Dağıtık işlem takibi neden gereklidir?

Dağıtık sistemlerde bir isteğin birden fazla servise uğraması durumunda, hata kaynağını bulmak imkansız hale gelir. Takip modülü, isteğin izini sürmenizi sağlar.

Performans kaybını nasıl önlerim?

Loglama işlemlerini ana iş akışından ayırarak, logları bir mesaj kuyruğuna (RabbitMQ, Kafka) gönderip arka planda işleyerek performansı koruyabilirsiniz.

Correlation ID her serviste nasıl taşınır?

HTTP başlıklarında (Header) taşıyarak veya bir mesaj kuyruğu kullanıyorsanız, mesajın "Metadata" kısmına ekleyerek taşıyabilirsiniz.

Hangi veritabanı tercih edilmelidir?

Yüksek yazma hızı gerektirdiği için Redis veya loglama odaklı veritabanları (Elasticsearch gibi) genellikle tercih edilir.

Bu yapı mikroservisler için uygun mu?

Evet, bu yapı tam olarak mikroservis mimarileri için tasarlanmıştır ve servisler arası bağımlılığı minimize eder.

İleri Seviye İpuçları: Dağıtık İzlemede Performans Optimizasyonu

Dağıtık işlem takibi, sisteminize ek bir yük getirebilir. Özellikle yüksek trafikli mikroservis mimarilerinde, her adımın günlüğe kaydedilmesi ağ trafiğini ve veritabanı I/O işlemlerini olumsuz etkileyebilir. Bu durumu optimize etmek için aşağıdaki stratejileri uygulayabilirsiniz:

Örnekleme (Sampling) Stratejisi

Tüm istekleri takip etmek yerine, belirli bir yüzdeyi veya sadece hata alan işlemleri takip etmek performans kaybını minimize eder. Aşağıdaki kod bloğu, belirli bir olasılıkla izleme verisi oluşturan basit bir mantığı göstermektedir:

public bool ShouldTrace(double samplingRate)
{
    var random = new Random();
    return random.NextDouble() < samplingRate;
}

// Kullanım: %10 oranında izleme yap
if (ShouldTrace(0.1))
{
    // İşlem takibini başlat
    _logger.LogInformation("İşlem izleniyor: {CorrelationId}", correlationId);
}

Asenkron Günlükleme (Asynchronous Logging)

İşlem durumlarını veritabanına yazarken ana iş akışını bekletmemek (blocking) kritik öneme sahiptir. Channel veya Buffer yapılarını kullanarak loglama işlemlerini arka plana atabilirsiniz.

public class AsyncTraceBuffer
{
    private readonly Channel _channel = Channel.CreateUnbounded();

    public async Task EnqueueTrace(TraceData data)
    {
        await _channel.Writer.WriteAsync(data);
    }

    public async Task ProcessTracesAsync(CancellationToken ct)
    {
        await foreach (var trace in _channel.Reader.ReadAllAsync(ct))
        {
            // Veritabanına toplu (bulk) yazma işlemi burada yapılır
            await SaveToDatabase(trace);
        }
    }
}

Dağıtık Sistemlerde Hata Ayıklama (Debugging) Senaryosu

Dağıtık bir sistemde hata ayıklarken, hatanın hangi serviste başladığını bulmak "samanlıkta iğne aramaya" benzer. Aşağıdaki tablo, hata ayıklama sürecinde Correlation ID kullanımının sağladığı avantajları özetlemektedir:

Senaryo Geleneksel Yöntem Dağıtık İzleme Yöntemi
Servisler arası kopukluk Tüm logları manuel birleştirme Correlation ID ile tek sorguda liste
Gecikme (Latency) Analizi Tahmin yürütme Her adımın süresini görme
Kısmi Başarısızlık Hatalı servisi bulamama Hatanın kaynağını anında tespit

İpucu: Hata ayıklama sırasında, sadece CorrelationId değil, aynı zamanda ParentSpanId gibi hiyerarşik veriler de tutarak işlemin hangi servisten hangi servise tetiklendiğini (call stack benzeri) görselleştirebilirsiniz.

Dağıtık İzlemede Alternatif Kütüphaneler

Kendi modülünüzü yazmak öğretici olsa da, üretim ortamlarında standartlara uyum sağlamak adına aşağıdaki kütüphaneleri incelemeniz önerilir:

  • OpenTelemetry .NET: Endüstri standardı haline gelmiş, tüm izleme araçlarıyla uyumlu kütüphane.
  • Serilog.Enrichers.CorrelationId: Loglara otomatik olarak Correlation ID eklemek için kullanılan popüler bir eklenti.
  • MassTransit: Eğer servisler arası iletişimde mesaj kuyrukları (RabbitMQ, Azure Service Bus) kullanıyorsanız, MassTransit'in yerleşik "Diagnostic Context" özellikleri işinizi büyük oranda kolaylaştıracaktır.

Sonuç

C# ile dağıtık işlem takip modülü geliştirmek, sisteminizin gözlemlenebilirliğini (observability) artırır ve üretim ortamındaki hataları tespit etme sürenizi ciddi oranda düşürür. Bu rehberde temel bir yapı kurduk; bir sonraki adım olarak bu yapıya OpenTelemetry entegrasyonu ekleyerek, verilerinizi Jaeger veya Grafana gibi araçlarla görselleştirmeyi deneyebilirsiniz. Yazılım geliştirme süreçlerinizde her zaman "Hata oluştuğunda neyi görebiliyorum?" sorusunu kendinize sormanız, sizi daha iyi bir mühendis yapacaktır.

Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında kullanmadan önce güvenlik denetimlerinden geçirmeli ve sisteminize özel hata toleransı mekanizmaları (circuit breaker, retry policy) eklemelisiniz.
Bu yazıya tepkinizi paylaşın:
Emre Güneş

Teknik çözümler ve ev gereçleri kullanımı konusunda deneyimli bir editörüm. Kullanıcı hatalarını minimize eden, yalın ve çözüm odaklı rehberler hazırlıyorum.

Yorumlar (0)

Yorum Yaz