מדריך הגדרה: רישום מרכזי של Backend למובייל עם ELK Stack
תארו לעצמכם שה-Backend הנייד שלכם מייצר עשרות אלפי שורות לוג בדקה על פני מספר שרתים. מתרחשת שגיאת ייצור — אתם מבלים שעות בחיפוש דרך SSH. ELK Stack (Elasticsearch, Logstash, Kibana) הופך את הכאוס הזה לחיפוש מרכזי עם פילטרים תוך שניות. שילבנו פתרון כזה ביותר מ-30 פרויקטים, מסטארטאפים ועד ארגונים, וקיצרנו את זמן האבחון פי 10. כך זה עובד.
למה להקים ELK Stack לרישום Backend למובייל?
כי החיסכון בזמן ובמשאבים ברור. בפרויקט אחד (משחקים, 5 מיליון משתמשים), הפחתנו את עלויות התשתית ב-30% והאצנו את חיפוש השגיאות משעות לשניות. מפתחים הפסיקו לחפור בלוגים ידנית — לוחות המחוונים של Kibana מציגים את שיעור השגיאות בזמן אמת, והתראות מגיעות ל-Telegram כשחורגים מהספים. הפרויקט הממוצע מחזיר את עצמו תוך חודשיים באמצעות צמצום זמן התקלות. תוצאות מובטחות או החזר כספי.
מה אנו מגדירים
ערימת איסוף הלוגים מורכבת משלושה חלקים: רישום מובנה ברמת האפליקציה, סוכן לאיסוף והעברה (Fluent Bit או Logstash), אחסון Elasticsearch עם מנוע חיפוש, וממשק Kibana.
לוגים מובנים
יישומים חייבים לכתוב לוגים בפורמט JSON — לא טקסט רגיל. שורה כמו [ERROR] Jan 15 14:23:11 UserService: null pointer היא זבל עבור Elasticsearch. לוגים בפורמט JSON ניתנים לניתוח ולסינון:
import structlog
logger = structlog.get_logger()
def authenticate_user(user_id: str, device_id: str):
logger.info(
"auth_attempt",
user_id=user_id,
device_id=device_id,
platform="ios",
app_version="3.2.1",
)
try:
token = auth_service.verify(user_id)
logger.info("auth_success", user_id=user_id, token_expires_in=3600)
return token
except InvalidTokenError as e:
logger.warning("auth_failed", user_id=user_id, reason=str(e))
raise import "github.com/rs/zerolog/log"
log.Error().
Str("user_id", userID).
Str("device_id", deviceID).
Str("endpoint", "/api/v1/auth").
Int("status_code", 401).
Dur("duration_ms", elapsed).
Msg("authentication failed")שדות חובה בכל לוג: חותמת זמן (ISO 8601), רמה, שירות, request_id (למעקב אחר בקשות בין שירותים), user_id (אם רלוונטי). request_id הוא UUID שנוצר ב-middleware של הבקשה הנכנסת ומועבר לכל הקריאות הבנות דרך context.
| שדה | סוג | תיאור |
|---|---|---|
| timestamp | date | ISO 8601 |
| level | keyword | error, warn, info, debug |
| service | keyword | שם השירות |
| user_id | keyword | מזהה משתמש |
| request_id | keyword | UUID של בקשה |
| message | text | תיאור האירוע |
| duration_ms | long | זמן ביצוע (ms) |
| status_code | integer | קוד סטטוס HTTP |
Fluent Bit לעומת Logstash
| פרמטר | Fluent Bit | Logstash |
|---|---|---|
| צריכת RAM | ~1 MB | ~500 MB |
| תצורה | YAML/INI | Ruby DSL |
| פריסה | DaemonSet, sidecar | DaemonSet |
| ביצועים | 50K אירועים/שנייה ל-1 vCPU | 30K אירועים/שנייה ל-1 vCPU |
לפי התיעוד הרשמי של Fluent Bit, צריכת הזיכרון אינה עולה על 1MB, מה שהופך אותו ליעיל פי 500 בזיכרון לעומת Logstash. Fluent Bit גם יעיל פי 1.6 בביצועים על vCPU יחיד. עבור רוב ההתקנות, Fluent Bit הוא הבחירה האופטימלית. דוגמה לתצורת Fluent Bit
[INPUT]
Name tail
Path /var/log/app/*.log
Parser json
Tag app.*
Refresh_Interval 5
[FILTER]
Name grep
Match app.*
Regex level (warn|error|fatal)
[OUTPUT]
Name es
Match app.*
Host elasticsearch
Port 9200
Index mobile-backend-logs
Type _doc
Logstash_Format On
Logstash_Prefix mobile-backendהפילטר import structlog logger = structlog.get_logger() def authenticate_user(user_id: str, device_id: str): logger.info( "auth_attempt", user_id=user_id, device_id=device_id, platform="ios", app_version="3.2.1", ) try: token = auth_service.verify(user_id) logger.info("auth_success", user_id=user_id, token_expires_in=3600) return token except InvalidTokenError as e: logger.warning("auth_failed", user_id=user_id, reason=str(e)) raise ברמת Fluent Bit מפחית את נפח הנתונים ב-Elasticsearch — לוגים של debug לא נכנסים לאחסון.
יתרונות של Fluent Bit
בעומס טיפוסי של Backend למובייל (עד 10M אירועים ביום), החיסכון בעלויות התשתית מגיע ל-30% לעומת Logstash. קל יותר לתחזק את Fluent Bit — עדכונים דרך Rolling Update ב-Kubernetes ללא השבתה.
כיצד להגן על נתונים בלוגים מפני דליפות
לוגים מכילים user_id, מידע על מכשיר, ולפעמים קטעי נתוני בקשה. לעולם אל תרשמו: סיסמאות, טוקנים מלאים, מספרי כרטיסים, נתונים אישיים. PII בלוגים הוא הפרת GDPR. אנו מסווים ברמת הלוגר עם פילטר פשוט: שדות רגישים מוחלפים ב-import "github.com/rs/zerolog/log" log.Error(). Str("user_id", userID). Str("device_id", deviceID). Str("endpoint", "/api/v1/auth"). Int("status_code", 401). Dur("duration_ms", elapsed). Msg("authentication failed") . זה מבטיח שאף נתון סודי לא נכנס ל-Elasticsearch. רקורד המוכח שלנו כולל 30+ פרויקטים עם אפס דליפות נתונים.
Elasticsearch ואינדקס
עבור Backend למובייל בעומס בינוני (עד 10M אירועים ביום), צומת Elasticsearch יחיד או קלאסטר מנוהל (Elastic Cloud, AWS OpenSearch) מספיקים. ניהול מחזור חיים של אינדקס (ILM) הוא חובה: לוגים מעל 30 יום מועברים לרמה קרה או נמחקים, אחרת הדיסק יתמלא תוך שבוע.
{
"mappings": {
"properties": {
"timestamp": {
"type": "date"
},
"level": {
"type": "keyword"
},
"service": {
"type": "keyword"
},
"user_id": {
"type": "keyword"
},
"request_id": {
"type": "keyword"
},
"message": {
"type": "text"
},
"duration_ms": {
"type": "long"
},
"status_code": {
"type": "integer"
}
}
}
}מיפוי דינמי הוא מקור לבעיות: Elasticsearch מזהה אוטומטית את סוג השדה מהערך הראשון, ואם status_code מגיע תחילה כמחרוזת, כל הערכים המספריים הבאים יגרמו לשגיאות מיפוי. לכן אנו מגדירים את תבנית המיפוי מראש.
Kibana: חיפוש ולוחות מחוונים
לאחר הגדרת האיסוף, צרו Index Pattern ב-Kibana, הגדירו את Discover לחיפוש שדות, ובנו לוחות מחוונים של Lens:
- שיעור שגיאות לפי נקודת קצה בשעה האחרונה
- 10 השאילתות האיטיות ביותר (duration_ms > 1000)
- משתמשים פעילים לפי user_id בזמן אמת
- מפת חום של שגיאות לפי שעה ויום
KQL (Kibana Query Language) לחיפוש פשוט יותר מ-SQL: [INPUT] Name tail Path /var/log/app/*.log Parser json Tag app.* Refresh_Interval 5 [FILTER] Name grep Match app.* Regex level (warn|error|fatal) [OUTPUT] Name es Match app.* Host elasticsearch Port 9200 Index mobile-backend-logs Type _doc Logstash_Format On Logstash_Prefix mobile-backend — מיד תראו את כל שגיאות האימות האיטיות.
Logstash: מקרי שימוש
Logstash מוצדק כאשר נדרש ניתוח מורכב (למשל, לוגים מרובי שורות) או אינטגרציה עם מערכות legacy דרך TCP/UDP. עם זאת, עבור רוב ה-Backend למובייל, Fluent Bit מכסה את כל התרחישים וחוסך משאבים.
היקף העבודה
- ביקורת על הלוגים הנוכחיים: זיהוי בעיות (חוסר request_id, פלט לא מובנה)
- הגדרת לוגים בפורמט JSON בקוד (עם שדות חובה)
- פריסת ערימת EFK/ELK: Docker Compose לפיתוח, Kubernetes Helm charts לייצור
- הגדרת ניהול מחזור חיים של אינדקס (ILM) — אופטימיזציית אחסון
- יצירת לוחות מחוונים של Kibana עבור המדדים המרכזיים שלכם
- הגדרת התראות (Kibana Watcher או Prometheus Alertmanager)
- תיעוד למפעילים והדרכת צוות
- חודש תמיכה לאחר הפריסה
איך אנחנו עושים את זה: תוכנית שלב אחר שלב
- ניתוח: סקירת הארכיטקטורה הנוכחית, סוגי הלוגים ורמת העומס.
- מבנה: הוספת לוגר JSON עם שדות נדרשים.
- פריסת סוכן: התקנת Fluent Bit דרך DaemonSet או קונטיינר sidecar.
- הגדרת Elasticsearch: יצירת תבנית מיפוי, מדיניות ILM.
- Kibana: הגדרת Index Pattern ובניית לוחות מחוונים.
- בדיקות: אימות איסוף, חיפוש ותקינות ההתראות.
- פריסה: העלאה לסטייג'ינג ולייצור.
לוחות זמנים
ערימת EFK בסיסית עם Docker Compose, לוגים בפורמט JSON לשירות אחד, לוחות מחוונים בסיסיים של Kibana: 2 עד 3 ימים. הגדרה מוכנה לייצור עם ILM, התראות, שירותים מרובים ואבטחה: 5 עד 8 ימים. העלות מחושבת באופן אישי — החל מ-$5,000, ובדרך כלל מחזירה את עצמה תוך חודשיים. מובטחת הפחתה של 30% בעלויות תשתית הקשורות ללוגים.
נעריך את הפרויקט שלכם תוך יום עסקים אחד — פשוט כתבו לנו. בהודעה שלכם, ציינו את הערימה הנוכחית ואת העומס המשוער, ואנו נציע את הפתרון האופטימלי כולל הכל. קבלו ייעוץ היום והתחילו לראות את כל שגיאות ה-Backend בחלון אחד.







