מבוא לבחירת דאטה בייס – חלק ב׳: מודדים במקום לנחש

מבוא לבחירת דאטה בייס – חלק ב׳: מודדים במקום לנחש

קוראי הבלוג עם זיכרון ארוך אולי זוכרים שבאוגוסט 2022 הבטחתי פוסט המשך. בעיה מהעולם האמיתי, כמה בסיסי נתונים, השוואת עלויות וביצועים. אחר כך עברו ארבע שנים, היה אקזיט, היה שקט, וההבטחה נשארה בסוף הפוסט כמו TODO בקומנט שאף אחד לא מוחק.

אז הנה המספרים. בלי Redis is the new king, ובלי להמליץ לכם להתחתן עם אף אחד.

תקציר הפרקים הקודמים

בחלק א׳ דיברתי על עקרונות: קודם כותבים מה קוראים, אחר כך מחליטים איך שומרים, ודוחים את החתונה עם בסיס הנתונים כמה שאפשר. הסיפור מהחיים היה משחק תורות מרובה משתתפים. ארבעה שחקנים, השרת מציג שאלה, ברגע שמישהו עונה לכולם יש 15 שניות, כולם עושים polling ל־REST כדי לראות מה חדש על הלוח.

הממשק נראה בערך ככה:

הניסיון הראשון היה Redis, כי רצינו משהו מהיר שחי בין שרתים. זה היה איטי ולא סקלבילי. אחר כך Firebase Realtime Database, כי דחיפה לקליינט נשמעת כמו הפתרון הנכון ל־polling. גם זה לא הציל. בסוף הבנו שבמשחק עם ארבעה אנשים לכמה דקות אין שום סיבה לבסיס נתונים משותף לכל השרתים, ושמרנו הכל ב־RAM. הביצועים קפצו, ואם שרת נופל באמצע משחק לוקח 30 שניות להרים חדש ואין מה לשחזר anyway.

החוק היה: אל תתחתן עם בסיס הנתונים שלך. מה לא היה שם: מספרים.

מה בעצם מדדנו

אותו ממשק, חמישה מימושים, והעומס שהרג את Redis בסיפור: הרבה קליינטים ששואלים get_updates כל רבע שנייה, ורק מדי פעם מישהו באמת עושה מהלך.

  1. RAM. מילון בפייתון, לכל משחק רשימת אירועים בזיכרון. הניצחון מ־2022.
  2. Redis נאיבי. מפתח אחד לכל משחק, GET לכל ה־JSON, מוסיפים שורה, SET חזרה. Redis כמחסן משותף, לא כמבנה נתונים.
  3. Redis כמו שצריך. רשימה לכל משחק, LRANGE מ־last_index, RPUSH במהלך.
  4. SQLite. טבלה על דיסק, SELECT מ־idx, INSERT במהלך. WAL.
  5. Postgres. אותה טבלה, על דיסק, עם fsync. הדבר שאנשים מתחתנים איתו.

Firebase לא רץ בחי. אין חשבון ניסוי, ולא רציתי לשלם כדי להוכיח נקודה. את העלות מחשבים ממחירון ברגע שיש נפח polling.

שתי רמות עומס: 50 משחקים (200 שחקנים) ו־200 משחקים (800 שחקנים). Poll כל 250ms, מהלך כל 3 שניות, חימום שתי שניות, מדידה 20. בלי HTTP. Redis על localhost בלי persistence. Postgres מקומי עם ברירות המחדל. מכונה אחת. מספיק בשביל סדרי גודל, לא בשביל DBA.

המספרים

50 משחקים, p99 של get_updates:

מימושp50p95p99קריאות לשנייה
RAM0.001ms0.004ms0.009ms800
Redis כמו שצריך0.32ms4.0ms10ms800
SQLite0.46ms5.5ms9.2ms800
Redis נאיבי4.1ms16ms25ms800
Postgres13ms25ms37ms800

אפס שגיאות. כבר פה רואים שרשימה ב־Redis זה לא אותו דבר כמו JSON שלם בכל GET.

200 משחקים, 800 שחקנים:

מימושp50p95p99קריאות לשנייה
RAM0.001ms0.002ms0.005ms3,200
Redis כמו שצריך0.45ms9.6ms33ms3,200
SQLite14ms34ms47ms3,200
Redis נאיבי9.7ms43ms81ms3,200
Postgres50ms136ms200ms3,200
p99 של get_updates ב־200 משחקים
p99 של get_updates, 200 משחקים. הציר ליניארי בכוונה: RAM בקושי נראה, וזה הסיפור.

RAM נשאר על אלפית המילישנייה. Redis שנכתב כמו שצריך יורד מ־81ms ל־33ms ב־p99, ועדיין לא קרוב ל־RAM. SQLite על דיסק מנצח את ה־Redis הנאיבי, ומנצח את Postgres בעומס הזה (יותר קוראים ממספר החיבורים במאגר, ו־Postgres משלם fsync). make_move ב־Postgres באותו עומס: p99 של 328ms. במשחק עם חלון של 15 שניות זה עוד חי. בשרת שגם עושה דברים אחרים זה כבר רעש.

p99 של get_updates, 50 משחקים מול 200
אותו p99 ב־50 משחקים מול 200. ציר לוגריתמי, אחרת RAM נעלם לגמרי. Postgres קופץ פי חמש, RAM נשאר במקום.

RAM מנצח כי אין רשת, אין JSON בקריאה, ואין תהליך אחר. לא פייר מול בסיס נתונים, וזה בדיוק העניין: למשחק תורות עם ארבעה אנשים, בסיס נתונים הוא פיצ'ר ששילמתם עליו בלי להזמין אותו.

כמה זה עולה

מחירון ציבורי מאוגוסט 2026, לא חשבונית.

RAM ו־SQLite. אפס מעל השרת שכבר רץ.

Redis מנוהל. ElastiCache cache.t3.micro, כ־12 דולר לחודש גם כשהצומת מובטל. בין אם כתבתם רשימה ובין אם כתבתם JSON, החשבון אותו דבר. הביצועים לא.

Postgres מנוהל. Cloud SQL מתחיל בסביבות 9 דולר לחודש למכונה קטנה. אותו סדר גודל כמו Redis, על עומס שהקובץ המקומי פתר בלי חשבון.

Firebase Realtime Database. אחסון 5 דולר לג׳יגה אחרי הג׳יגה הראשון, הורדות דולר לג׳יגה אחרי בערך 10 ג׳יגה בחודש. REST polling של 800 שחקנים הופך את ההורדות לבור. Push אמיתי זול יותר, וב־2022 הוא לא הציל אותנו כי הבעיה הייתה המודל.

הפתרון הזול ביותר היה לא לקנות בסיס נתונים.

"אם אין לך בעיית סקייל, אל תקנה פתרון סקייל. תקנה קפה."

מתוך מדריך ההייטקיסט לגלקסיה, פרק שלא עבר code review

מה לקחת מזה

מכונה אחת, בלי HTTP, Redis בלי דיסק, Postgres עם fsync ברירת מחדל. מי שיגיד מזה ש־Postgres איטי או ש־Redis מהיר, לא קרא.

מה כן: העומס פה הוא אלפי get_updates ריקים, לא המהלכים. אל תתחתן עם בסיס הנתונים שלך, ואל תמדוד אותו לפי הברושור. תמדוד את הקריאה שקורית 50 פעם יותר מהכתיבה.

הערה: הטיוטה נכתבה עם Grok בממשק Grok Bot ב־Cursor. המדידות הן ניסוי מקומי בפייתון 3.13 מול Redis 8.0.2, SQLite 3.46 ו־Postgres 17. המספרים מהקוד, לא מהמודל.

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

*