Anomaly Detection ile Otomatik Hata Tespiti¶
Anomaly detection, normal davranış kalıplarından sapmaları otomatik tespit eder; sabit eşikli uyarılar dinamik sistemlerde yetersiz kalır ve sorunların geç fark edilmesine yol açar.
1. Sabit Eşik ile Alert Tanımlamak¶
❌ Yanlış Kullanım: Statik threshold ile çalışmak.
# alert_rules.yml
- alert: HighLatency
expr: http_request_duration_seconds > 0.5
# Gece 03:00'te 0.3s normal, öğlen 12:00'de 0.5s normal
# Sabit eşik her iki durumda da yanlış sonuç verir
✅ İdeal Kullanım: Dinamik baseline ile anomali tespiti yapın.
# Prometheus alert - son 7 günlük ortalamaya göre
- alert: LatencyAnomaly
expr: >
http_request_duration_seconds:p95
> avg_over_time(http_request_duration_seconds:p95[7d]) * 2
and
http_request_duration_seconds:p95
> avg_over_time(http_request_duration_seconds:p95[7d]) + 2 *
stddev_over_time(http_request_duration_seconds:p95[7d])
for: 10m
labels:
severity: warning
annotations:
summary: "Latency anomalisi: P95 normal aralığın dışında"
2. Sadece Teknik Metrikleri İzlemek¶
❌ Yanlış Kullanım: İş metriklerinde anomali aramamak.
// CPU, Memory, HTTP 500 izleniyor ama:
// - Sipariş sayısı anormal düştüğünde fark edilmiyor
// - Ödeme başarı oranı değiştiğinde alarm yok
// - Kayıt oranı sıfıra düştüğünde kimse bilmiyor
✅ İdeal Kullanım: İş metriklerinde de anomali tespiti yapın.
public class BusinessAnomalyDetector : BackgroundService
{
private readonly IMetricsService _metrics;
private readonly IAlertService _alertService;
protected override async Task ExecuteAsync(CancellationToken ct)
{
var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (await timer.WaitForNextTickAsync(ct))
{
await CheckOrderAnomalyAsync(ct);
await CheckPaymentAnomalyAsync(ct);
}
}
private async Task CheckOrderAnomalyAsync(CancellationToken ct)
{
var currentRate = await _metrics.GetOrderRateAsync(TimeSpan.FromMinutes(15));
var historicalAvg = await _metrics.GetOrderRateAsync(TimeSpan.FromDays(7));
var stdDev = await _metrics.GetOrderRateStdDevAsync(TimeSpan.FromDays(7));
// Z-score hesapla
var zScore = (currentRate - historicalAvg) / stdDev;
if (zScore < -2.5) // Normalden çok düşük
{
await _alertService.SendAsync(new Alert
{
Severity = AlertSeverity.Warning,
Title = "Sipariş oranı anomalisi",
Message = $"Mevcut: {currentRate:F1}/dk, Beklenen: {historicalAvg:F1}/dk (z={zScore:F2})"
});
}
}
}
3. Error Rate Spike Tespiti Yapmamak¶
❌ Yanlış Kullanım: Toplam hata sayısına bakmak.
- alert: TooManyErrors
expr: http_server_errors_total > 100
# Yoğun saatte 100 hata normal olabilir, gece 10 hata bile sorun olabilir
✅ İdeal Kullanım: Hata oranı değişimini (spike) tespit edin.
public class ErrorRateSpikeDetector
{
public bool IsSpike(double currentErrorRate, double[] recentRates)
{
if (recentRates.Length < 10) return false;
var mean = recentRates.Average();
var stdDev = Math.Sqrt(recentRates.Average(r => Math.Pow(r - mean, 2)));
// Modified Z-Score (outlier'lara dayanıklı)
var median = GetMedian(recentRates);
var mad = GetMedian(recentRates.Select(r => Math.Abs(r - median)).ToArray());
var modifiedZScore = 0.6745 * (currentErrorRate - median) / mad;
return modifiedZScore > 3.5;
}
private static double GetMedian(double[] values)
{
var sorted = values.OrderBy(v => v).ToArray();
var mid = sorted.Length / 2;
return sorted.Length % 2 == 0
? (sorted[mid - 1] + sorted[mid]) / 2.0
: sorted[mid];
}
}
4. Seasonality’yi Hesaba Katmamak¶
❌ Yanlış Kullanım: Gün içi ve haftalık örüntüleri görmezden gelmek.
// Pazar günü trafik %60 düşer ama alarm tetiklenir
// Gece 03:00 trafiği düşük ama "trafik azaldı" uyarısı gelir
✅ İdeal Kullanım: Zaman bazlı karşılaştırma yapın.
public class SeasonalAnomalyDetector
{
public async Task<AnomalyResult> DetectAsync(string metricName, double currentValue)
{
// Aynı saatte, aynı günde geçmiş hafta verileri
var historicalValues = await _metricsStore.GetHistoricalAsync(
metricName,
dayOfWeek: DateTime.UtcNow.DayOfWeek,
hourOfDay: DateTime.UtcNow.Hour,
weeksBack: 4);
var mean = historicalValues.Average();
var stdDev = CalculateStdDev(historicalValues);
var zScore = stdDev > 0 ? (currentValue - mean) / stdDev : 0;
return new AnomalyResult
{
IsAnomaly = Math.Abs(zScore) > 2.5,
ZScore = zScore,
ExpectedValue = mean,
ActualValue = currentValue,
Direction = zScore > 0 ? "above" : "below"
};
}
}
// Kullanım
var result = await _detector.DetectAsync("orders_per_minute", currentOrderRate);
if (result.IsAnomaly)
_logger.LogWarning("Anomali: {Metric} beklenen {Expected:F1}, gerçek {Actual:F1} (z={ZScore:F2})",
"orders_per_minute", result.ExpectedValue, result.ActualValue, result.ZScore);
5. Anomali Sonrası Otomatik Aksiyon Almamak¶
❌ Yanlış Kullanım: Anomali tespitinden sonra sadece alert göndermek.
if (isAnomaly)
await _slack.SendAsync("Anomali tespit edildi!");
// İnsan müdahalesi beklenecek, gece yarısı ise geç kalınabilir
✅ İdeal Kullanım: Anomali tipine göre otomatik aksiyon alın.
public class AnomalyResponseService
{
public async Task HandleAnomalyAsync(AnomalyResult anomaly)
{
switch (anomaly.Type)
{
case AnomalyType.HighErrorRate:
// Circuit breaker'ı aç
await _circuitBreaker.OpenAsync(anomaly.AffectedService);
// Fallback'e yönlendir
await _featureFlags.EnableAsync("UseFallbackService");
await _alertService.SendAsync(AlertSeverity.Critical, anomaly);
break;
case AnomalyType.HighLatency:
// Cache TTL'i uzat (DB yükünü azalt)
await _cacheConfig.ExtendTtlAsync(TimeSpan.FromMinutes(30));
// Non-critical background job'ları duraklat
await _jobScheduler.PauseNonCriticalAsync();
await _alertService.SendAsync(AlertSeverity.Warning, anomaly);
break;
case AnomalyType.TrafficSpike:
// Rate limiter'ı sıkılaştır
await _rateLimiter.ReduceLimitAsync(0.5);
// Auto-scale tetikle
await _scaler.ScaleUpAsync(anomaly.AffectedService, 2);
await _alertService.SendAsync(AlertSeverity.Warning, anomaly);
break;
}
}
}