נתקלנו במצבים שבהם אפליקציה ב-App Store מקבלת תלונות על גמגומים בגלילה, למרות שהכל פועל חלק בסימולטור. המשתמש לא ישלח לך פרופיל הקצאה, ואי אפשר להריץ Xcode Instruments ב-CI. ניטור ביצועים בסביבת production הוא דיסציפלינה נפרדת: הכלים חייבים לעבוד על המכשיר, לא לפגוע ב-UX, ולשלוח מדדים מצטברים. הניסיון שלנו מראה שניטור שיטתי מפחית את שיעור הקריסות ב-30% בחודש הראשון ומעלה את שימור המשתמשים ב-5%. במשך למעלה מ-10 שנים, יישמנו ניטור ליותר מ-50 אפליקציות מובייל עם קהלים שמתחילים ב-100 אלף משתמשים פעילים יומית (DAU).
למה ניטור ביצועים ב-Production הוא קריטי
בתנאי מעבדה קל למדוד FPS על רשת אידיאלית. ב-production, יש לך אלפי תצורות מכשירים, גרסאות מערכת הפעלה, מצבי סוללה ועומסי רקע. רק ניטור משתמשים אמיתי נותן מדדים אובייקטיביים של p50/p95/p99. לדוגמה, זמן התחלה קר ממוצע ב-iPhone 12 עשוי להיות 1.2 שניות, בעוד שב-Samsung Galaxy A10 הוא 4.5 שניות. בלי ניטור production, לא תראה את זה. יתרה מכך, מעקב אחר ביצועים בסביבה חיה חושף בעיות שלא משתכפלות במכשירי בדיקה: תנאי מרוץ (race conditions), דליפות זיכרון תחת עומס, ובעיות ריבוי-תהליכונים במעבדים שונים.
אילו מדדים לנטר לשימור משתמשים
FPS בגלילה הוא אחד המדדים המרכזיים לתחושת ביצועים נתפסת. לדוגמה, טלטולים ב-UITableView עקב פענוח JPEG סינכרוני ב-thread הראשי הם קלאסיקה. אנו מודדים באמצעות CADisplayLink ושולחים p5 (אחוז הפריימים מתחת ל-60 FPS).
איך למדוד FPS בגלילה
שלב אחר שלב עבור iOS:
- צור CADisplayLink והוסף אותו ל-run loop הראשי.
- ספור פריימים לשנייה.
- שלח את המדד עם שם המסך.
class FPSMonitor {
private var displayLink: CADisplayLink?
private var lastTimestamp: CFTimeInterval = 0
private var frameCount = 0
func start() {
displayLink = CADisplayLink(target: self, selector: #selector(tick))
displayLink?.add(to: .main, forMode: .common)
}
@objc private func tick(_ link: CADisplayLink) {
frameCount += 1
if link.timestamp - lastTimestamp >= 1.0 {
let fps = Double(frameCount) / (link.timestamp - lastTimestamp)
MetricsCollector.record("screen_fps", value: fps, screen: currentScreen)
frameCount = 0
lastTimestamp = link.timestamp
}
}
}באנדרואיד אנו משתמשים ב-class FPSMonitor { private var displayLink: CADisplayLink? private var lastTimestamp: CFTimeInterval = 0 private var frameCount = 0 func start() { displayLink = CADisplayLink(target: self, selector: #selector(tick)) displayLink?.add(to: .main, forMode: .common) } @objc private func tick(_ link: CADisplayLink) { frameCount += 1 if link.timestamp - lastTimestamp >= 1.0 { let fps = Double(frameCount) / (link.timestamp - lastTimestamp) MetricsCollector.record("screen_fps", value: fps, screen: currentScreen) frameCount = 0 lastTimestamp = link.timestamp } } } מ-FrameMetricsAggregator — הוא מספק פילוח לפי שלבי רינדור. חשוב לאסוף p5 (5% התחתונים של הפריימים), מכיוון שממוצע FPS יכול להסתיר טלטולים נדירים.
אזהרות זיכרון — iOS שולח androidx.core לפני סגירה כפויה של האפליקציה. רשום אירוע זה עם המסך הנוכחי ושימוש בזיכרון באמצעות didReceiveMemoryWarning. באנדרואיד, האנלוג הוא ActivityManager.getMemoryInfo ורישום fragments. ANR באנדרואיד הוא מדד קריטי נוסף: אם השיעור שלו עולה על 0.1%, זה מאותת על צורך באופטימיזציה מיידית של ה-thread הראשי. קרא עוד על ANR.
באיזה כלי ניטור לבחור?
השוואה בין שלושה פתרונות פופולריים:
| כלי | מדדים אוטומטיים | Traces מותאמים אישית | Distributed Tracing | Session Replay |
|---|---|---|---|---|
| Firebase Performance | התחלה קרה, HTTP, רינדור מסך | ✅ | ❌ | ❌ |
| Sentry Performance | קריסות, HTTP, אירועי UI | ✅ | ✅ | ❌ |
| Datadog RUM | קצב פריימים, רשת, פעולות משתמש | ✅ | ✅ | ✅ |
Firebase Performance — סף כניסה אפסי. ה-SDK אוסף אוטומטית זמן התחלה קרה, בקשות HTTP (חביון, גודל תגובה), ורינדור מסך. הוסף traces מותאמים אישית ללוגיקה עסקית:
let trace = Performance.startTrace(name: "catalog_load")
trace.start()
catalogService.load { [weak self] result in
trace.stop()
self?.handleResult(result)
} val trace = Firebase.performance.newTrace("catalog_load")
trace.start()
catalogRepository.load { result ->
trace.stop()
handleResult(result)
}Sentry Performance — אם אתה כבר משתמש ב-Sentry למעקב אחר קריסות, הפעלת Performance אינה דורשת SDK חדש. מצוין ל-distributed tracing: אתה רואה לא רק חביון בצד הלקוח אלא גם פילוח של בקשות backend. Datadog RUM — הבחירה עבור צוותים עם תשתית Datadog קיימת. הוא מקליט אוטומטית Session Replay (וידאו של אינטראקציות), FPS, ובקשות רשת עם stack trace מלא. הניסיון שלנו בשילוב Datadog RUM בפרויקט עם 500 אלף DAU צמצם את זמן חיפוש הבעיות משעתיים ל-10 דקות.
איך להגדיר התראות כדי למנוע אזעקות שווא
חשוב לא להעמיס על הצוות עם אזעקות שווא. ספים מומלצים:
| מדד | סף | מקור |
|---|---|---|
| זמן התחלה קרה (p75) | > 3 שניות | Apple ממליצה על < 400 אלפיות שנייה לפריים ראשון |
| שיעור שגיאות HTTP | > 2% | — |
| זמן רינדור מסך (p95) | > 500 אלפיות שנייה | — |
| שיעור ANR (אנדרואיד) | > 0.1% | — |
| אפליקציה לא מגיבה (iOS) | > 0.05% | לפי נתוני Crashlytics |
הגדר התראות ב-Firebase Performance או Datadog על ספים אלה עם הודעות ל-Slack/Telegram. עייפות התראות היא האויב העיקרי: אל תגדיר ספים נמוכים מדי. התחל עם p99 והגבר בהדרגה את הרגישות. ודא שההתראות מכילות מספיק הקשר (גרסת אפליקציה, דגם מכשיר, גרסת מערכת הפעלה) לזיהוי מהיר של בעיות.
מה כלול בעבודה
אנו מציעים שילוב של SDK אחד — Firebase Performance, Sentry Performance או Datadog RUM — תוך 1–3 ימים. אנו מוסיפים traces מותאמים אישית לפעולות מפתח, ניטור FPS, אזהרות זיכרון, ומגדירים התראות עם הודעות ל-Slack/Telegram. לוח מחוונים מלא עם מדדים — עד 5 ימים. העלות מחושבת באופן אישי. צור קשר כדי לבחור את הכלי — נעזור לך לבחור את האפשרות האופטימלית ולהקים ניטור מקצה לקצה. אנו מבטיחים הפחתה של 30% בשיעור הקריסות בחודש הראשון.







