Eşik Değerleri ve Konfigürasyon
Özet
Ingest Servis'in karar vermesi gereken eşikler (duplicate repeat counters, rate limits, interval thresholds, timeout değerleri vb.) hardcoded değerler değildir. Bunlar deployment-specific ortam değişkenlerinden (environment variables) okunmalı, farklı ortamlar (dev, staging, prod) için farklı threshold'lar kullanılabilmelidir.
Bu sayfa:
- Environment variable tanımını
- Ortam-spesifik profilleri
- Configuration loading pattern'ini
- Validation rules'i
- Değerlendirme kılavuzuna
açıklar.
Önerilen Environment Variables
9 temel konfigürasyon değişkeni aşağıdadır:
| Variable | Default | Açıklama |
|---|---|---|
INGEST_DUPLICATE_REPEAT_SUSPICIOUS_THRESHOLD | 3 | Duplicate tekrar sayısı (suspicious olarak işaretlenene kadar) |
INGEST_DUPLICATE_REPEAT_STUCK_THRESHOLD | 10 | Duplicate tekrar sayısı (stuck olarak işaretlenene kadar) |
INGEST_RATE_SUSPICIOUS_PER_MINUTE | 12 | Dakikada paket sayısı (warning flag set) |
INGEST_RATE_FLOOD_PER_MINUTE | 30 | Dakikada paket sayısı (flood event üretilir) |
INGEST_INTERVAL_SUSPICIOUS_DIVISOR | 4 | Beklenen aralığın böleni (suspicious: interval < expected/4) |
INGEST_INTERVAL_FLOOD_DIVISOR | 10 | Beklenen aralığın böleni (flood: interval < expected/10) |
INGEST_MAX_PAYLOAD_SIZE_BYTES | 16384 | Maksimum HTTP payload boyutu (edge limiteri) |
INGEST_REQUEST_TIMEOUT_MS | 5000 | İstek timeout süresi (milisaniye) |
INGEST_REDIS_DEVICE_BUFFER_TTL_SECONDS | 86400 | Redis device_buffer TTL (default: 24 saat) |
Environment Profilleri
Development Profile
İlk geliştirme ve local testing için uygun:
# Duplicate Detection Thresholds
INGEST_DUPLICATE_REPEAT_SUSPICIOUS_THRESHOLD=3
INGEST_DUPLICATE_REPEAT_STUCK_THRESHOLD=10
# Rate Limiting (packets per minute)
INGEST_RATE_SUSPICIOUS_PER_MINUTE=12
INGEST_RATE_FLOOD_PER_MINUTE=30
# Interval Analysis (divisors of expected interval)
INGEST_INTERVAL_SUSPICIOUS_DIVISOR=4
INGEST_INTERVAL_FLOOD_DIVISOR=10
# Payload & Request Limits
INGEST_MAX_PAYLOAD_SIZE_BYTES=16384
INGEST_REQUEST_TIMEOUT_MS=5000
# Redis Configuration
INGEST_REDIS_DEVICE_BUFFER_TTL_SECONDS=86400
Özellikler:
- Tolerant threshold'lar (false positive'i minimize eder)
- Yavaş timeout (debugging için)
- Büyük payload limiti (test case'leri için)
Staging Profile
Production'a yakın ama test-friendly:
# Duplicate Detection - Prod'a yakın
INGEST_DUPLICATE_REPEAT_SUSPICIOUS_THRESHOLD=2
INGEST_DUPLICATE_REPEAT_STUCK_THRESHOLD=8
# Rate Limiting - Biraz gevşek
INGEST_RATE_SUSPICIOUS_PER_MINUTE=10
INGEST_RATE_FLOOD_PER_MINUTE=25
# Interval Analysis - Prod'a yakın
INGEST_INTERVAL_SUSPICIOUS_DIVISOR=4
INGEST_INTERVAL_FLOOD_DIVISOR=10
# Payload Limits - Testing için daha geniş
INGEST_MAX_PAYLOAD_SIZE_BYTES=32768
INGEST_REQUEST_TIMEOUT_MS=5000
# Redis - Prod'a yakın
INGEST_REDIS_DEVICE_BUFFER_TTL_SECONDS=86400
Özellikler:
- Production davranışına yakın
- Load testing için uygun tolerans
- Monitoring setup'ı test etmek için hazır
Production Profile
Canlı trafik için optimized:
# Duplicate Detection - Sıkı
INGEST_DUPLICATE_REPEAT_SUSPICIOUS_THRESHOLD=3
INGEST_DUPLICATE_REPEAT_STUCK_THRESHOLD=10
# Rate Limiting - Aynı default (dashboard alarmları tarafından kontrol edilir)
INGEST_RATE_SUSPICIOUS_PER_MINUTE=12
INGEST_RATE_FLOOD_PER_MINUTE=30
# Interval Analysis - Sıkı
INGEST_INTERVAL_SUSPICIOUS_DIVISOR=4
INGEST_INTERVAL_FLOOD_DIVISOR=10
# Payload Limits - Sıkı
INGEST_MAX_PAYLOAD_SIZE_BYTES=16384
# Request Timeout - Kısa (latency optimize)
INGEST_REQUEST_TIMEOUT_MS=3000
# Redis - 24 saat (retention policy)
INGEST_REDIS_DEVICE_BUFFER_TTL_SECONDS=86400
Özellikler:
- Kesin karar veriş (false negative risk mitigate edilir)
- Hızlı timeout (latency optimize)
- Standart payload boyutu
Configuration Loading
Application Startup
Uygulama başlangıcında ortam değişkenlerini okumalı ve default values ile fallback yapmalıdır:
// Pseudocode örneği (TypeScript/Node.js)
interface IngestConfig {
duplicate: {
suspiciousThreshold: number;
stuckThreshold: number;
};
rate: {
suspiciousPerMinute: number;
floodPerMinute: number;
};
interval: {
suspiciousDivisor: number;
floodDivisor: number;
};
http: {
maxPayloadSize: number;
requestTimeoutMs: number;
};
redis: {
deviceBufferTtlSeconds: number;
};
}
function loadConfig(): IngestConfig {
return {
duplicate: {
suspiciousThreshold: parseInt(
process.env.INGEST_DUPLICATE_REPEAT_SUSPICIOUS_THRESHOLD || '3'
),
stuckThreshold: parseInt(
process.env.INGEST_DUPLICATE_REPEAT_STUCK_THRESHOLD || '10'
),
},
rate: {
suspiciousPerMinute: parseInt(
process.env.INGEST_RATE_SUSPICIOUS_PER_MINUTE || '12'
),
floodPerMinute: parseInt(
process.env.INGEST_RATE_FLOOD_PER_MINUTE || '30'
),
},
interval: {
suspiciousDivisor: parseInt(
process.env.INGEST_INTERVAL_SUSPICIOUS_DIVISOR || '4'
),
floodDivisor: parseInt(
process.env.INGEST_INTERVAL_FLOOD_DIVISOR || '10'
),
},
http: {
maxPayloadSize: parseInt(
process.env.INGEST_MAX_PAYLOAD_SIZE_BYTES || '16384'
),
requestTimeoutMs: parseInt(
process.env.INGEST_REQUEST_TIMEOUT_MS || '5000'
),
},
redis: {
deviceBufferTtlSeconds: parseInt(
process.env.INGEST_REDIS_DEVICE_BUFFER_TTL_SECONDS || '86400'
),
},
};
}
const config = loadConfig();
Configuration Validation
Startup sırasında konfigürasyon mantıklılığını kontrol etmek gerekir (sanity checks).
Zorunlu Validasyon Kuralları
| Kural | Gerekçe | Örnek |
|---|---|---|
suspiciousThreshold < stuckThreshold | Suspicious → stuck sırası | 3 < 10 ✅ |
suspiciousPerMinute < floodPerMinute | Warning → flood sırası | 12 < 30 ✅ |
suspiciousDivisor > floodDivisor | 1/4 > 1/10 (interval eşikleri) | 4 > 10 ❌ |
maxPayloadSize > 100 | HTTP body minumum uygun | 16384 > 100 ✅ |
requestTimeoutMs > 100 | Timeout minumum makul | 5000 > 100 ✅ |
deviceBufferTtlSeconds > 60 | Redis key minimum hayatta kalış | 86400 > 60 ✅ |
Fail-Fast Strategy
Herhangi bir validation hatası bulunursa, uygulama startup başarısız olmalıdır:
function validateConfig(config: IngestConfig): void {
const errors: string[] = [];
if (config.duplicate.suspiciousThreshold >= config.duplicate.stuckThreshold) {
errors.push(
`suspiciousThreshold (${config.duplicate.suspiciousThreshold}) ` +
`must be < stuckThreshold (${config.duplicate.stuckThreshold})`
);
}
if (config.rate.suspiciousPerMinute >= config.rate.floodPerMinute) {
errors.push(
`suspiciousPerMinute (${config.rate.suspiciousPerMinute}) ` +
`must be < floodPerMinute (${config.rate.floodPerMinute})`
);
}
if (config.interval.suspiciousDivisor <= config.interval.floodDivisor) {
errors.push(
`suspiciousDivisor (${config.interval.suspiciousDivisor}) ` +
`must be > floodDivisor (${config.interval.floodDivisor})`
);
}
if (config.http.maxPayloadSize < 100) {
errors.push(`maxPayloadSize must be >= 100 bytes`);
}
if (config.http.requestTimeoutMs < 100) {
errors.push(`requestTimeoutMs must be >= 100ms`);
}
if (config.redis.deviceBufferTtlSeconds < 60) {
errors.push(`deviceBufferTtlSeconds must be >= 60`);
}
if (errors.length > 0) {
console.error('Configuration validation failed:');
errors.forEach((e) => console.error(` - ${e}`));
process.exit(1); // Fail fast
}
console.log('Configuration validated successfully');
}
Eşikleri Belirlemek için İzlenecek Yol
1. Default Values ile Başla
İlk deployment'ta example değerler kullan (yukarıda sağlanan dev/staging/prod profilleri).
2. Operasyonel Veri Topla
En az 1 hafta gerçek trafikten veri topla:
- Duplicate paket oranı
- Cihaz başına paket sıklığı
- Normal interval dağılımı
- Network retry pattern'leri
3. İstatistikleri Analiz Et
Örnek metrikler:
- 0.001% → 0.005%: Duplicate rate (legitimate network hataları için normal)
- p50: 0.5 paket/dakika, p95: 2 paket/dakika, p99: 5 paket/dakika
- NTP sync burst: Birkaç cihaz aynı anda hızlı paketler gönderiyor
- Firmware bug: Spesifik bir model 10+ tekrar duplicate gönderiyor
4. Threshold'ları Ayarla
- Suspicious: p95 + 20% margin
- Flood: p99 × 3-5 (gerçek flood vs noise diff)
- Stuck: Domain bilgisine göre (örn: device beklediğx max repeat = 7, threshold = 10)
5. False Positive Risk Değerlendir
Hangi threshold'da legitimate cihazlar yanlış olarak işaretlenecek?
- NTP sync event'i 12+ paket/dakika göndereceği biliniyor → min 15 olsun
- Tekil çipleme hatası 3 tekrar → suspicious threshold 2 yerine 3 olsun
6. Monitoring Dashboardı Kur
Threshold'ların gerçek dünyadaki etkisini izle:
- False positive rate (yanlışlıkla flagged cihazlar)
- Detection latency (sorun ile uyarı arasındaki zaman)
- Threshold utilization (kaç cihaz ne kadar yakın threshold'a)
7. Dinamik Ayarlamalar
İlk ay içinde gerekirse weekly reviews yaparak threshold'ları ince ayarla.
Özet: Değişim Yönetimi
| Durum | Yapılacak |
|---|---|
| Dev → Staging | .env.staging ile threshold'ları sertleştir |
| Staging → Prod | .env.production ile ultra-sıkı mode |
| Prod operasyonu | Threshold değişiklikleri için change request + gradual rollout |
| Emergency rollout | Hızlı threshold adjustment → monitoring + instant rollback ready |
Ortam değişkenlerini kullanmak sayesinde zero-downtime configuration updates mümkün olur (greenfield redeployment öncesinde tanımlı değerlerle başla).
Monitoring Örneği: Grafana Dashboard
Aşağıdaki JSON, 8 key metric'i gösteren bir Grafana dashboard panel örneğidir (Prometheus veri kaynağı ile):
{
"dashboard": {
"title": "Qapu Ingest Service Metrics",
"panels": [
{
"title": "Ingest Latency (p95)",
"targets": [
{
"expr": "histogram_quantile(0.95, ingest_process_duration_ms)"
}
],
"alert": {
"conditions": [{"operator": "gt", "query": "A", "reducer": "avg", "type": "query", "evaluator": {"params": [500], "type": "gt"}}],
"message": "p95 latency > 500ms"
}
},
{
"title": "Raw DB Write Errors",
"targets": [{"expr": "rate(raw_db_write_errors[1m])"}],
"alert": {"conditions": [{"evaluator": {"params": [10], "type": "gt"}}], "message": "errors > 10/min"}
},
{
"title": "Duplicate Rate",
"targets": [{"expr": "rate(duplicate_packets[1m]) / rate(total_packets[1m])"}],
"alert": {"conditions": [{"evaluator": {"params": [0.05], "type": "gt"}}], "message": "dup rate > 5%"}
},
{
"title": "Flood Detections/Hour",
"targets": [{"expr": "rate(flood_warnings[1h])"}],
"alert": {"conditions": [{"evaluator": {"params": [5], "type": "gt"}}], "message": "floods > 5/hr"}
},
{
"title": "Stuck Devices Count",
"targets": [{"expr": "count(stuck_cihazlar)"}],
"alert": {"conditions": [{"evaluator": {"params": [10], "type": "gt"}}], "message": "stuck > 10"}
},
{
"title": "Kafka Emit Success Rate",
"targets": [{"expr": "1 - (rate(kafka_emit_errors[1m]) / rate(kafka_emit_total[1m]))"}],
"alert": {"conditions": [{"evaluator": {"params": [0.99], "type": "lt"}}], "message": "success < 99%"}
},
{
"title": "Redis Availability",
"targets": [{"expr": "redis_up{instance=\"ingest\"}"}],
"alert": {"conditions": [{"evaluator": {"params": [1], "type": "ne"}}], "message": "redis down"}
},
{
"title": "Requests per Second",
"targets": [{"expr": "rate(http_requests_total[1m])"}],
"thresholds": {"mode": "percentage", "steps": [{"color": "yellow", "value": 50}, {"color": "red", "value": 150}]}
}
]
}
}
Import Adımları:
- Grafana Home → Create → Import
- Yukarıdaki JSON'ı paste et
- Prometheus datasource seç
- Dashboard save et
Custom Alerting: Her panel'in alert rule'ının bakılması önerilir — threshold'ları ortamınız için ince ayarla (production → daha sıkı, staging → daha tolerant).