מדרגיות בהיקף - הבסיס שכל מפתח חייב להכיר¶
"המערכת צריכה להיות סקיילבילית" זה אחד המשפטים שנזרקים הכי הרבה בישיבות תכנון, ולרוב בלי שמישהו עוצר להסביר בדיוק למה הכוונה. אז בואו נפרק את זה - מה זה בכלל מדרגיות, ומה באמת צריך כדי שמערכת תעמוד בעומס גדל בלי לקרוס.
מה זה בכלל מדרגיות¶
מדרגיות (scalability) היא היכולת של מערכת להמשיך לתפקד טוב כשהעומס עליה גדל - יותר משתמשים, יותר בקשות, יותר נתונים. מערכת לא סקיילבילית עובדת מצוין עם מאה משתמשים, ומתחילה להיתקע או לקרוס עם מאה אלף. מערכת סקיילבילית פשוט מוסיפה עוד משאבים ומחזיקה מעמד.
שתי דרכים להרחיב מערכת¶
יש שתי גישות בסיסיות, וההבדל ביניהן קריטי:
מדרגיות אנכית (vertical scaling) אומרת לחזק את השרת הקיים - יותר מעבד, יותר זיכרון, דיסק מהיר יותר. זה פשוט מאוד ליישום, כמעט בלי שינוי בקוד. הבעיה - יש תקרה. בשלב מסוים אין עוד חומרה חזקה יותר לקנות, והמחיר עולה בצורה לא פרופורציונלית ככל שמתקרבים לחומרה החזקה ביותר בשוק.
מדרגיות אופקית (horizontal scaling) אומרת להוסיף עוד שרתים במקום לחזק שרת אחד. עומס מתחלק בין כמה מכונות במקביל. זה כמעט ללא תקרה - רוצים לתמוך בעוד מיליון משתמשים? מוסיפים עוד שרתים. הבעיה - זה דורש שהאפליקציה שלכם תהיה בנויה נכון מלכתחילה, וזה לא תמיד קל.
התנאי הראשון - שירות ללא מצב¶
הדרישה הכי בסיסית כדי שמדרגיות אופקית תעבוד היא ששרתי האפליקציה שלכם יהיו stateless - חסרי מצב. זה אומר שכל בקשה יכולה להגיע לכל שרת, בלי תלות בזיכרון או נתונים שנשמרו בשרת ספציפי מבקשה קודמת.
אם אתם שומרים session של משתמש בזיכרון של שרת ספציפי, ואז הבקשה הבאה שלו מגיעה למאזן עומסים ומנותבת לשרת אחר - יש לכם בעיה, כי השרת השני לא מכיר את המשתמש. הפתרון הוא להוציא את המצב החוצה - לשמור sessions במסד נתונים משותף או במערכת קאש כמו Redis, שכל השרתים יכולים לגשת אליה. ברגע שהשרתים חסרי מצב, אפשר להוסיף ולהוריד שרתים בחופשיות לגמרי בלי לשבור כלום.
מדרגיות זה לא רק שרתי אפליקציה¶
הרבה מפתחים חושבים על מדרגיות רק במונחים של "כמה שרתי ווב יש לי", אבל זה הרבה מעבר לזה:
- מסד הנתונים לרוב הופך לצוואר הבקבוק האמיתי הרבה לפני שרתי האפליקציה. כאן נכנסים לתמונה שכפול (replication), פיצול נתונים (sharding), ואינדקסים חכמים.
- קאשינג הוא לרוב הדרך הזולה והמהירה ביותר לשפר מדרגיות - שמירת תוצאות שאילתות יקרות בזיכרון מהיר במקום לחשב אותן מחדש בכל פעם.
- תורי הודעות (message queues) מאפשרים לפרק עבודה כבדה לביצוע אסינכרוני ברקע, במקום לגרום למשתמש לחכות לתהליך שלם שקורה בזמן אמת.
איתור צוואר הבקבוק לפני שמרחיבים¶
טעות נפוצה היא להרחיב באופן גורף בלי לדעת איפה באמת הבעיה. אם מסד הנתונים הוא צוואר הבקבוק, הוספת עוד עשרה שרתי אפליקציה לא תעזור בכלל - כולם פשוט יעמדו בתור לאותו מסד נתונים עמוס. הצעד הראשון תמיד צריך להיות מדידה - שימוש בכלי ניטור כדי לראות בדיוק איפה הזמן מתבזבז, ורק אז להשקיע במקום הנכון.
מדרגיות עולה כסף¶
חשוב לזכור - מדרגיות אינה חינמית. כל שרת נוסף, כל שכבת קאש, כל מנגנון פיצול נתונים מוסיף עלות תפעולית ומורכבות תחזוקה. הכלל הזהב הוא לא לבנות למיליון משתמשים כשיש לכם אלף. תבנו בצורה שלא חוסמת אתכם מלהרחיב בעתיד - למשל, וודאו ששרתי האפליקציה חסרי מצב מההתחלה כי זה כמעט לא עולה כלום - אבל תמנעו מלבזבז שבועות על תשתית מורכבת לעומס שעוד לא קיים. זה בדיוק אותו עיקרון YAGNI שחוזר גם כאן.
זה בדיוק סוג ההחלטות שאנחנו מפרקים לגורמים בקורס ארכיטקטורת תוכנה - מתי להשקיע במדרגיות ומתי זה מוקדם מדי, עם מקרי בוחן אמיתיים של מערכות בהיקף גדול.
יש לכם מערכת שמתחילה "לגמגם" תחת עומס ולא בטוחים איפה הבעיה? שאלו את הקהילה בדיסקורד, לרוב שווה זוג עיניים נוספות שכבר ראו בעיה דומה.
לסיכום¶
מדרגיות היא לא תכונה אחת שמוסיפים למערכת, היא תוצאה של סדרת החלטות נכונות - שרתים חסרי מצב, מדידה לפני הרחבה, וגישה נכונה למסד הנתונים ולקאשינג. תתחילו מהיסודות, בעיקר משירותים חסרי מצב, וההרחבה בעתיד תהיה הרבה יותר טבעית ופשוטה.