המדריך הזה מיועד למי שמכיר את סביבת App Engine הרגילה, ומספק מבוא לסביבה הגמישה. במאמר מוסבר על קווי הדמיון וההבדלים העיקריים בין הסביבות, וגם מפורטות בו המלצות כלליות לגבי ארכיטקטורה של אפליקציות שמשתמשות בשתי הסביבות.
למיפוי של שירותים שזמינים בסביבה רגילה לאנלוגים שלהם בסביבה גמישה, אפשר לעיין במאמר העברת שירותים מהסביבה הרגילה לסביבה הגמישה.
נקודות דמיון והבדלים עיקריים
שתי הסביבות מספקות לכם את התשתית של App Engine לפריסה, להצגה ולהתאמה לעומס (scaling). ההבדלים העיקריים הם באופן שבו הסביבה מריצה את האפליקציה, באופן שבו האפליקציה ניגשת לשירותים חיצוניים, באופן שבו מריצים את האפליקציה באופן מקומי ובאופן שבו האפליקציה מתרחבת. אפשר גם לעיין בבחירת סביבה כדי לקבל סיכום כללי של ההבדלים האלה.
הרצת אפליקציה
בסביבה הרגילה, האפליקציה פועלת במכונה קלה בתוך ארגז חול. ארגז החול הזה מגביל את הפעולות שהאפליקציה יכולה לבצע. לדוגמה, ארגז החול מאפשר לאפליקציה להשתמש רק בקבוצה מוגבלת של ספריות בינאריות, והאפליקציה לא יכולה לכתוב לדיסק. בנוסף, בסביבה הרגילה יש מגבלות על אפשרויות המעבד והזיכרון שזמינות לאפליקציה. בגלל ההגבלות האלה, רוב האפליקציות הרגילות של App Engine הן אפליקציות אינטרנט חסרות מצב (stateless) שמגיבות במהירות לבקשות HTTP.
לעומת זאת, בסביבה הגמישה האפליקציה פועלת במאגרי Docker במכונות וירטואליות (VM) של Google Compute Engine, שבהן יש פחות הגבלות. לדוגמה, אתם יכולים להשתמש בכל שפת תכנות שתבחרו, לכתוב לדיסק, להשתמש בכל ספרייה שתרצו ואפילו להריץ כמה תהליכים. בסביבה הגמישה אפשר גם לבחור כל סוג מכונה של Compute Engine עבור המכונות שלכם, כדי שלאפליקציה תהיה גישה ליותר זיכרון ו-CPU.
גישה לשירותים חיצוניים
בסביבה הרגילה, האפליקציה בדרך כלל ניגשת לשירותים כמו Datastore דרך ממשקי ה-API המובנים של google.appengine. עם זאת, בסביבה הגמישה, ממשקי ה-API האלה כבר לא זמינים. במקום זאת, צריך להשתמש בספריות הלקוח של Google Cloud. ספריות הלקוח האלה פועלות בכל מקום, ולכן האפליקציה שלכם ניידת יותר. בדרך כלל, אפליקציות שפועלות בסביבה הגמישה יכולות לפעול ב-Google Kubernetes Engine או ב-Compute Engine בלי שינויים משמעותיים.
פיתוח מקומי
בסביבה הרגילה, בדרך כלל מריצים את האפליקציה באופן מקומי באמצעות App Engine SDK. ערכת ה-SDK מטפלת בהרצת האפליקציה ומדמה את השירותים של App Engine. בסביבה הגמישה, ה-SDK לא משמש יותר להפעלת האפליקציה. במקום זאת, אפליקציות שנכתבות לסביבה הגמישה צריכות להיכתב כמו אפליקציות אינטרנט רגילות שיכולות לפעול בכל מקום. כמו שצוין, בסביבה הגמישה האפליקציה פועלת בקונטיינר Docker. המשמעות היא שכדי לבדוק את האפליקציה באופן מקומי, פשוט מריצים את האפליקציה ישירות. לדוגמה, כדי להריץ אפליקציית Python באמצעות Django, פשוט מריצים את הפקודה python manage.py runserver.
הבדל חשוב נוסף הוא שאפליקציות בסביבה גמישה שפועלות באופן מקומי משתמשות בשירותים בפועל של Cloud Platform, כמו Datastore. מומלץ להשתמש בפרויקט נפרד לבדיקה מקומית, וכשזמין, להשתמש באמולטורים.
מאפייני הרחבה
שתי הסביבות משתמשות בתשתית של App Engine להתאמה אוטומטית לעומס, אבל אופן שינוי הגודל שונה. הסביבה הרגילה יכולה להתרחב מאפס מופעים ועד אלפים במהירות רבה. לעומת זאת, בסביבה גמישה צריכה לפעול לפחות אינטס אחד לכל גרסה פעילה, ויכול להיות שייקח יותר זמן להרחיב את הפריסה בתגובה לתנועת הגולשים.
בסביבה רגילה נעשה שימוש באלגוריתם מותאם אישית של התאמה אוטומטית לעומס. בסביבה גמישה נעשה שימוש במידרוג אוטומטי של Compute Engine. שימו לב: סביבה גמישה לא תומכת בכל האפשרויות של התאמה אוטומטית לעומס שזמינות ב-Compute Engine. App Engine מתחשב בהזמנות של מכונות וירטואליות ב-Compute Engine שכבר יש לכם באזור שתואם להגדרה שלכם. שמירת מקום למכונה וירטואלית מגדילה את הסיכוי שתקבלו הקצאת משאבים במהלך מחסור זמני במשאבים.
המפתחים צריכים לבדוק את התנהגות האפליקציה במגוון תנאים. לדוגמה, כדאי לבדוק איך התאמה אוטומטית לעומס מגיבה כשיישום שמוגבל על ידי מעבד (CPU) הופך להיות מוגבל על ידי קלט/פלט בתקופות שבהן יש השהיה מוגברת בקריאות לשירותים מרוחקים.
בדיקות תקינות
בסביבה רגילה לא נעשה שימוש בבדיקות תקינות כדי לקבוע אם לשלוח תנועה למופע. סביבה גמישה מאפשרת למפתחי אפליקציות לכתוב בעצמם את הפונקציות לטיפול בבדיקות תקינות, שישמשו את מאזן העומסים כדי לקבוע אם לשלוח תנועה למופע מסוים ואם לבצע תיקון אוטומטי. מפתחים צריכים לנקוט משנה זהירות כשמוסיפים לוגיקה לבדיקות תקינות. לדוגמה, אם בדיקת תקינות מבצעת קריאה לשירות חיצוני, כשל זמני בשירות הזה עלול לגרום לכל המופעים להיות לא תקינים, ואולי להוביל לכשל מדורג.
הפסקת בקשות במקרה של עומס יתר
אפליקציות יכולות להפסיק בקשות כשהן עמוסות מדי, כחלק מאסטרטגיה למניעת כשלים מדורגים. היכולת הזו מוטמעת בשכבת ניתוב התנועה בסביבה הרגילה. אנחנו ממליצים למפתחים של אפליקציות עם QPS גבוה מאוד בסביבה הגמישה, להוסיף לאפליקציות שלהם את היכולת להפחית את עומס התנועה על ידי הגבלת מספר הבקשות המקבילות.
כדי לוודא שהאפליקציה בסביבה הגמישה לא חשופה לסוג הזה של כשלים, אפשר ליצור גרסה עם מגבלה על המספר המקסימלי של המופעים. לאחר מכן, מגדילים בהדרגה את נפח התנועה עד שהבקשות נדחות. חשוב לוודא שהאפליקציה לא נכשלת בבדיקות תקינות במהלך עומס יתר.
ב-Java, אפליקציות Java שמשתמשות ב-Jetty runtime יכולות להגדיר את מסנן איכות השירות כדי ליישם השמטה של עומס יתר. באמצעות התכונה הזו, אפשר להגדיר את המספר המקסימלי של בקשות בו-זמניות שהאפליקציות מטפלות בהן, ואת משך הזמן שבו הבקשות ימתינו בתור.
גדלים של מכונות
במקרים של סביבות גמישות, אפשר להגדיר מגבלות גבוהות יותר של CPU וזיכרון מאשר במקרים של סביבות רגילות. כך אפשר להריץ על מופעים גמישים אפליקציות שדורשות יותר זיכרון ו-CPU. עם זאת, יכול להיות שהיא תגדיל את הסיכוי לבאגים של פעולות מקבילות בגלל הגידול במספר השרשורים במופע יחיד.
מפתחים יכולים להשתמש ב-SSH כדי להתחבר למופע של סביבה גמישה ולקבל dump של השרשור כדי לפתור בעיות מהסוג הזה.
לדוגמה, אם אתם משתמשים בסביבת זמן הריצה של Java, אתם יכולים להריץ את הפקודה הבאה:
$ ps auwwx | grep java $ sudo kill -3$ sudo docker logs gaeapp
זמן קצוב לתפוגה של בקשה
בסביבה רגילה, הזמן הקצוב לתפוגה של בקשה משתנה בהתאם לסוג ההתאמה שנבחרה, אבל בסביבה גמישה תמיד מוגדר זמן קצוב לתפוגה של 60 דקות. כדי למנוע מצב שבו בקשות נשארות פתוחות למשך 60 דקות מלאות ועלולות לגרום לשימוש בכל השרשורים בשרת האינטרנט:
כשמבצעים שיחות לשירותים חיצוניים, צריך לציין זמן קצוב לתפוגה.
מטמיעים מסנן servlet כדי לעצור בקשות שלוקח להן זמן ארוך מדי, למשל 60 שניות. צריך לוודא שהאפליקציה יכולה לחזור למצב עקבי אחרי שהמסנן מפסיק בקשה.
ניהול שרשורים
בסביבה רגילה של Java, לפני Java 8, אפשר היה להשתמש רק בthreads שנוצרו באמצעות SDK של סביבה רגילה של App Engine. מפתחים שמבצעים המרה של אפליקציה מסביבת זמן ריצה רגילה של Java מהדור הראשון לסביבה גמישה צריכים לעבור לשימוש בספריות של שרשורים מקוריים. אפליקציות שדורשות מספר גדול מאוד של threads עשויות לפעול בצורה יעילה יותר עם thread pools מאשר עם יצירה מפורשת של threads.
העברת תנועה
סביבה רגילה מספקת תכונה להעברת תנועה, שמעבירה בהדרגה תנועה לגרסה חדשה כדי למזער את העליות הפתאומיות בזמן האחזור. במסמכי המיגרציה של התנועה מוסבר איך למנוע עלייה פתאומית בזמן האחזור כשמעבירים את התנועה לגרסה חדשה.
כשלים באזור יחיד
אפליקציות בסביבה רגילה הן בעלות בית יחיד, כלומר כל המופעים של האפליקציה נמצאים באזור זמינות יחיד. במקרה של כשל באזור הזה, האפליקציה מפעילה מופעים חדשים באזור אחר באותו אזור, ומאזן העומסים מעביר את התנועה למופעים החדשים. תראו עלייה חדה בזמן האחזור בגלל טעינת הבקשות וגם ניקוי של Memcache.
אפליקציות בסביבה גמישה משתמשות בקבוצות של מופעי מכונה בניהול אזורי, כלומר המופעים מפוזרים בין כמה אזורי זמינות באזור מסוים. במקרה של כשל בתחום אחד, מאזן העומסים מפסיק להפנות תעבורה לתחום הזה. אם הגדרתם התאמה אוטומטית לעומס כדי להפעיל את המופעים שלכם בצורה הכי מהירה שאפשר, תראו תקופה קצרה של עומס יתר לפני שההתאמה האוטומטית לעומס תיצור עוד מופעים.
השוואות עלויות
יש הרבה גורמים שמשפיעים על השוואת העלויות בין עומסי עבודה שפועלים בסביבות רגילות ובסביבות גמישות. למשל:
- המחיר ששולם לכל מחזור חיובים.
- יכולות פלטפורמת ה-CPU, שמשפיעות על העבודה שאפשר לבצע בכל מחזור שעון (MCycle)
- עד כמה אפשר להריץ מופעים בכל פלטפורמה.
- העלות של הפריסות, שעשויה להיות שונה בכל פלטפורמה, ויכולה להיות משמעותית אם אתם משתמשים בפריסה רציפה לאפליקציה.
- תקורה של זמן הריצה.
תצטרכו להריץ ניסויים כדי לקבוע את העלות של עומס העבודה בכל פלטפורמה. בסביבה גמישה, אפשר להשתמש ב-QPS לכל ליבה כפרוקסי ליעילות העלות של האפליקציה כשמריצים ניסויים כדי לקבוע אם לשינוי יש השפעה על העלויות. בסביבה רגילה אין מנגנון כזה לקבלת מדדים בזמן אמת לגבי היעילות של העלויות באפליקציה. צריך לבצע שינוי ולהמתין עד לסיום מחזור החיוב היומי.
מיקרו-שירותים (microservices)
בסביבה הרגילה, אפשר לבצע אימות מאובטח בין אפליקציות באמצעות כותרת הבקשה X-Appengine-Inbound-Appid. בסביבה גמישה אין תכונה כזו. הגישה המומלצת לאימות מאובטח בין אפליקציות היא שימוש ב-OAuth.
פריסה
פריסות בסביבה רגילה בדרך כלל מהירות יותר מפריסות בסביבה גמישה. הרחבת גרסה קיימת בסביבה גמישה מהירה יותר מפריסת גרסה חדשה, כי תכנות הרשת של גרסה חדשה הוא בדרך כלל השלב הכי ארוך בתהליך הפריסה בסביבה גמישה. אחת מהאסטרטגיות לביצוע חזרות מהירות לגרסה קודמת בסביבה גמישה היא לשמור גרסה טובה מוכרת שהוקטנה למופע יחיד. לאחר מכן תוכלו להגדיל את הגרסה הזו ולהפנות אליה את כל התנועה באמצעות חלוקת תנועה.
מתי כדאי להשתמש בסביבה הגמישה
הסביבה הגמישה נועדה להשלים את הסביבה הרגילה. אם יש לכם אפליקציה קיימת שפועלת בסביבה הרגילה, בדרך כלל אין צורך להעביר את כל האפליקציה לסביבה הגמישה. במקום זאת, צריך לזהות את החלקים באפליקציה שדורשים יותר מעבד, יותר זיכרון RAM, ספרייה או תוכנה מיוחדת של צד שלישי, או שצריכים לבצע פעולות שלא אפשריות בסביבה הרגילה. אחרי שמזהים את החלקים האלה באפליקציה, יוצרים שירותים קטנים של App Engine שמשתמשים בסביבה הגמישה כדי לטפל רק בחלקים האלה. השירות הקיים שלכם שפועל בסביבה הרגילה יכול לקרוא לשירותים האחרים באמצעות HTTP, Cloud Tasks או Cloud Pub/Sub.
לדוגמה, אם יש לכם אפליקציית אינטרנט קיימת שפועלת בסביבה הרגילה ואתם רוצים להוסיף לה תכונה חדשה להמרת קבצים ל-PDF, אתם יכולים לכתוב מיקרו-שירות נפרד שפועל בסביבה הגמישה ומטפל רק בהמרה ל-PDF. המיקרו-שירות הזה יכול להיות תוכנית פשוטה שמורכבת רק ממטפל בקשות אחד או שניים. מיקרו-שירות יכול להתקין ולהשתמש בכל תוכנת Linux זמינה כדי לסייע בהמרה, כמו unoconv.
האפליקציה הראשית נשארת בסביבה הרגילה ויכולה לקרוא למיקרו-שירות הזה ישירות דרך HTTP, או שאם צפוי שההמרה תימשך זמן רב, האפליקציה יכולה להשתמש ב-Cloud Tasks או ב-Pub/Sub כדי להוסיף את הבקשות לתור.
המאמרים הבאים
ממפים את השירותים שבהם האפליקציה משתמשת בסביבה הרגילה לאנלוגים שלהם בסביבה הגמישה.