Tüm Yazılar
KategoriiOS
Okuma Süresi
12 dk
Yayın Tarihi
2026-05-13
Kelime Sayısı
687kelime

Kahveni hazırla - bu içerikli bir makale!

TahminApp Mimarisi: Realtime Push, Sharded Firestore ve Uptime Hedefleri

Özet

Kendi yan projem TahminApp'in mimari tasarım notları: gerçek zamanlı tahmin bildirimi + ölçeklenebilir veri akışı. Firestore + Cloud Messaging + Cloudflare Workers ile 500K MAU ve p99 180ms latency hedefi — ve asıl darboğazın neden beklenen yerde olmadığı.

  • Tasarım hedefleri: 500K MAU, p99 latency 180ms, %99.9 uptime bandı, >30dk süren incident yok
  • Bu mimaride asıl darboğaz Firestore write değil APNs delivery latency olur (4-6dk gecikme)
  • Priority routing ile 500K push'luk fan-out 25-35 saniye bandına çekilebilir
  • Sharded collection (20 shard) Firestore write throughput'unu 20x'e çıkarır
TahminApp Mimarisi: Realtime Push, Sharded Firestore ve Uptime Hedefleri
TahminApp kendi yan projem: küçük ölçekli bir spor tahmin uygulaması, hâlâ geliştirme aşamasında. Aşağıdakiler ölçülmüş ürün sonuçları değil; projenin mimari tasarım kararları ve tasarım hedefleri.

Problem: Spor tahmin platformunda gerçek zamanlı maç olayları (gol, kart, devre arası) anında 500K+ kullanıcıya push notification gönderme + canlı skor akışını UI'da güncelleme.

Tasarım hedefleri: 500K MAU, p99 latency 180ms, %99.9 üstü uptime, >30dk süren incident yok. Hiçbiri ölçülmüş bir sonuç değil — mimari bu hedeflere göre kuruluyor.

Pro Tip: Bottleneck beklediğin yer değil. Bu tasarımda Firestore write değil, push delivery routing. Her büyük scaling hikâyesi aynı şekilde başlar.

1. Architecture Overview

3-tier:

  • Edge layer (CF Workers): Webhook receiver, dedup, fan-out trigger
  • Backend (Firestore + Cloud Functions): Persistent state, business logic
  • Mobile (iOS native + Flutter Android): Realtime listener + push notification handler
swift
1[Sports Data Feed]
2 ↓ webhook
3[CF Worker — dedup + transform]
4 ↓ event
5[Cloud Function — match state update]
6 ↓ write
7[Firestore — predictions, users, scores]
8 ↓ realtime listener
9[Mobile Apps — UI update]
10 ↓
11[FCM/APNs — push notification]

2. Bottleneck Hikayesi

İlk hipotez: Firestore writes scale etmez. Bu ölçekte tutmaz — sharding ile çözülür.

İkinci hipotez: Cloud Functions cold start sorun. Warm instance pool ile bu da elenir.

Asıl bottleneck: APNs delivery latency. 500K push'luk bir fan-out'ta varsayılan routing 30 saniye değil 4-6 dakika bandında teslim eder. Büyük maç anlarında "geç bildirim" şikâyetinin tipik kaynağı budur.

Çözüm: Priority routing — match-event push'lar apns-priority: 10 + Cloudflare Workers'tan paralel batch send. Hedef: 500K push 25-35sn bandında teslim.

3. Firestore Tasarımı

500K user × 50 prediction/user × 100 match/season = 2.5M document. Naive design /predictions/{id} bu hacimde çöker.

Doğru pattern — sharded collection:

swift
1/predictions/shard-{0-19}/items/{predictionID}

Shard count 20, prediction ID hash'inden assignment. Her shard ayrı index, ayrı write limit. Toplam write throughput 20x.

Realtime listener: Mobile listen /predictions/shard-{userShard} — sadece kendi shard'ını izle. Network savings %95.

4. Cloud Functions Patterns

Tasarımda 40+ Cloud Function öngörülüyor. En kritik 3'ü:

  1. onMatchEvent: webhook trigger, dedup window 30sn, state update + push trigger
  2. onPredictionWrite: leaderboard recalc (sharded counter pattern)
  3. onUserWrite: profile cache invalidation (Cloudflare KV pürge)

Her function:

  • Memory: 256MB (most), 1GB (leaderboard)
  • Timeout: 60s
  • Max instances: 1000 (auto-scale)
  • Retry: 3x exponential backoff
  • Idempotency: eventID Firestore set-based dedup

5. iOS App Architecture

iOS native (SwiftUI iOS 16+):

  • TCA (The Composable Architecture) state management
  • Firestore Snapshot Publisher — Combine pattern
  • APNS Notification Service Extension — payload decryption + smart action
  • Local cache (SwiftData) — offline read-only mode

Memory baseline hedefi: 95MB. Peak (match-time live UI): 145MB.

Crash-free session rate için hedef bant: %99.8+ (Crashlytics ile izlenir).

6. Cost Profile

Tasarımın aylık infrastructure bütçe tahmini (500K MAU peak hedefi varsayımıyla):

Kalem
Cost
Firestore (read/write/storage)
$420
Cloud Functions (invocations)
$180
Cloud Messaging (FCM)
$0 (free tier OK)
APNs
$0 (Apple side)
Cloudflare Workers
$25 (Pro plan)
Cloudflare KV
$5
Hetzner monitoring server
$7
Toplam
$637/ay

Per-user cost: $0.00127/user/ay. Indie unit economics için fazlasıyla yeterli bir bant.

7. Öğrenimler (Lessons Learned)

1. Tahmin edilen bottleneck nadiren gerçek bottleneck. APNs delivery gibi kalemler ancak gerçek trafik altında görünür; launch sonrası ilk haftalarda ölçüm planı hazır olmalı.

2. Sharding'i ön ödeme yap. 500K user'a vardıktan sonra sharding eklemek aylarla ölçülen teknik borç demek.

3. Idempotency event ID kritik — webhook retry'ları aksi hâlde sessiz duplicate yaratır.

4. Notification Service Extension content modification + alert prioritization için altın.

5. Edge layer (CF Workers) üzerinde dedup + transform yapmak Cloud Functions maliyetini kat kat düşürür.

6. Crashlytics + custom telemetry ikisini birden çalıştır. Crashlytics aggregation, custom telemetry decision data.

7. Bu ürün sınıfında App Store yorumlarının en çok döndüğü konu, büyük maç anlarındaki ortalama notification latency'si. Latency'yi optimize etmek doğrudan rating'i hareket ettiren kalemdir.

Sonuç: 500K user ölçeği genellikle "Firestore" sorunu değil, "delivery infrastructure" sorunu. Architecture'ı en başta multi-tier kur, ölç ve refactor et.

Etiketler

#Case Study#Production#Firestore#Push Notifications#Cloudflare Workers#Scaling
Muhittin Çamdalı

Muhittin Çamdalı

Senior Mobile Engineer

12+ yıllık deneyime sahip Senior Mobile Engineer. iOS, Flutter ve React Native ile mobil ürünler geliştiriyorum; full-stack ve AI-native çalışıyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik