תכנון שירותי Cloud Run לפי השיטות המומלצות מאפשר לכם לשפר את יעילות זמן הריצה, לצמצם את זמן האחזור בהפעלת קונטיינרים ולשנות את קנה המידה של עומסי העבודה באופן צפוי. אסטרטגיות העיצוב, בו-זמניות ושיטות האבטחה האלה עוזרות לכם לבנות שירותים גמישים וחסכוניים. אם אתם מעבירים שירות אינטרנט קיים ל-Cloud Run, קראו את המאמר העברת שירות קיים.
איך לכתוב שירותים אפקטיביים
בקטע הזה מתוארות שיטות מומלצות כלליות לתכנון ולהטמעה של שירות Cloud Run.
פעילות ברקע
פעילות ברקע היא כל מה שקורה אחרי שתגובת ה-HTTP נשלחה. כדי לבדוק אם יש פעילות ברקע בשירות שלא נראית לעין, בודקים אם יש ביומנים רשומות שנוספו אחרי הרשומה של בקשת ה-HTTP.
הגדרת חיוב לפי מכונה לשימוש בפעילויות ברקע
אם אתם רוצים לתמוך בפעילויות ברקע בשירות Cloud Run, הגדירו את השירות לחיוב מבוסס-מכונה כדי שתוכלו להריץ פעילויות ברקע מחוץ לבקשות ועדיין תהיה לכם גישה למעבד (CPU).
אם אתם משתמשים בחיוב לפי בקשות, הימנעו מפעילויות ברקע
אם אתם צריכים להגדיר את השירות לחיוב מבוסס-בקשות, כשהשירות של Cloud Run יסיים לטפל בבקשה, הגישה של המכונה למעבד תושבת או תוגבל באופן משמעותי. אם אתם משתמשים בסוג החיוב הזה, אל תפעילו תהליכים או שגרות ברקע שפועלים מחוץ להיקף של ה-request handlers.
בודקים את הקוד כדי לוודא שכל הפעולות האסינכרוניות מסתיימות לפני ששולחים את התשובה.
אם מפעילים שרשורים ברקע כשמופעל חיוב מבוסס-בקשות, יכולה להיות התנהגות לא צפויה כי כל בקשה עוקבת לאותו מכונה של מאגר ממשיכה את כל הפעילות ברקע שהושהתה.
מחיקת קבצים זמניים
בסביבת Cloud Run, האחסון בדיסק הוא מערכת קבצים בזיכרון. קבצים שנכתבים בדיסק צורכים זיכרון שזמין לשירות, ויכולים להישמר בין הפעלות. אם לא מוחקים את הקבצים האלה, בסופו של דבר עלולה להופיע שגיאת חוסר בזיכרון, וכתוצאה מכך זמני ההפעלה של הקונטיינר יהיו איטיים.
דיווח על שגיאות
לטפל בכל החריגות ולא לאפשר לשירות לקרוס בגלל שגיאות. קריסה גורמת להפעלה איטית של הקונטיינר בזמן שהתנועה ממתינה בתור למכונה חלופית.
ראו את המדריך ל-Error Reporting לקבלת מידע על איך לדווח על שגיאות בצורה נכונה.
אופטימיזציה של הביצועים
בקטע הזה מתוארות שיטות מומלצות לאופטימיזציה של הביצועים.
הפעלה מהירה של קונטיינרים
מכיוון שהמכונות מותאמות לפי הצורך, זמן ההפעלה שלהן משפיע על זמן האחזור של השירות. ב-Cloud Run, הפעלת המכונה ועיבוד הבקשה לא קשורים זה לזה, ולכן במקרים מסוימים הבקשה צריכה להמתין עד שהמכונה החדשה תופעל לפני שהיא תעובד. זה קורה בדרך כלל כששירות משתנה מאפס.
התרחיש לפתיחת היום כולל:
- הורדת קובץ האימג' של הקונטיינר (באמצעות טכנולוגיית הסטרימינג של קובץ האימג' של הקונטיינר ב-Cloud Run)
- הפעלת הקונטיינר באמצעות הפקודה entrypoint.
- ממתינים שהקונטיינר יתחיל להאזין ביציאה שהוגדרה.
אופטימיזציה של מהירות ההפעלה של הקונטיינר מצמצמת את זמן האחזור של עיבוד הבקשות.
שימוש בהאצת המעבד בזמן אתחול כדי לצמצם את זמן האחזור של האתחול
כדי להפחית את זמן האחזור של ההפעלה, אתם יכולים להפעיל את האצת המעבד בזמן אתחול כדי להגדיל באופן זמני את הקצאת המעבד בזמן הפעלת המכונה.
שימוש במספר מינימלי של מכונות כדי לקצר את זמני ההפעלה של קונטיינרים
כדי לקצר את זמני ההפעלה של קונטיינרים, אתם יכולים להגדיר מספר מינימלי של מכונות ובו-זמניות. לדוגמה, אם תגדירו מספר מינימלי של מכונות ל-1, השירות יהיה מוכן לקבל עד למספר הבקשות המקבילות שהוגדר לשירות, בלי צורך להפעיל מכונה חדשה. כשמשתמשים במספר מינימלי של מכונות, כדאי להימנע משימוש ביציאות מהמערכת שיכבו מכונה ועלולות להגדיל את מספר ההפעלות מההתחלה (cold start).
שימו לב שבקשה שממתינה להפעלת מכונה תישאר בהמתנה בתור באופן הבא:
הבקשות ימתינו עד פי 3.5 מזמן ההפעלה הממוצע של מכונות קונטיינר של השירות הזה, או 10 שניות, הגבוה מביניהם.
שימוש חכם ביחסי תלות
אם אתם משתמשים בשפה דינמית עם ספריות תלויות, כמו ייבוא מודולים ב-Node.js, זמן הטעינה של המודולים האלה מתווסף לזמן האחזור של ההפעלה.
כדי לקצר את זמן הטעינה של האפליקציה:
- כדי ליצור שירות קל, צמצמו את המספר והגודל של יחסי התלות.
- אם השפה תומכת בכך, כדאי להשתמש בטעינה מדורגת של קוד שלא נמצא בשימוש לעיתים קרובות.
- להשתמש באופטימיזציות של טעינת קוד, כמו אופטימיזציה של טעינה אוטומטית של Composer ב-PHP.
שימוש במשתנים גלובליים
ב-Cloud Run, אי אפשר להניח שמצב השירות נשמר בין בקשות. עם זאת, ב-Cloud Run נעשה שימוש חוזר במכונות ספציפיות כדי לטפל בתנועה שוטפת, כך שאפשר להצהיר על משתנה בהיקף גלובלי כדי לאפשר שימוש חוזר בערך שלו בהפעלות הבאות. אי אפשר לדעת מראש אם בקשה ספציפית תיהנה מהיתרון של השימוש החוזר הזה.
אפשר גם לשמור אובייקטים במטמון בזיכרון אם הם דורשים משאבים רבים כדי ליצור אותם מחדש בכל בקשת שירות. העברת המשתנה מהלוגיקה של הבקשה להיקף הגלובלי משפרת את הביצועים.
Node.js
Python
Go
Java
ביצוע אתחול מדורג של משתנים גלובליים
האתחול של משתנים גלובליים תמיד מתרחש במהלך ההפעלה, מה שמאריך את זמן ההפעלה של הקונטיינר. כדי לדחות את עלות הזמן ולקצר את זמני ההפעלה של הקונטיינר, כדאי להשתמש באתחול עצל (lazy initialization) לאובייקטים שלא משתמשים בהם לעיתים קרובות.
אחד החסרונות של אתחול מדורג הוא זמן אחזור ארוך יותר בבקשות הראשונות למכונות חדשות. זה יכול לגרום להגדלת יתר של קנה המידה ולדחיית בקשות כשפורסים גרסה חדשה של שירות שמטפל באופן פעיל בבקשות רבות.
Node.js
Python
Go
Java
שימוש בסביבת הפעלה אחרת
כדי לקצר את זמני ההפעלה, אפשר להשתמש בסביבת הפעלה אחרת.
אופטימיזציה של בו-זמניות (concurrency)
מכונות של Cloud Run יכולות לטפל בכמה בקשות בו-זמנית, עד למספר המקסימלי של בקשות בו-זמניות שניתן להגדיר.
Cloud Run משנה באופן אוטומטי את מספר הבקשות בו-זמנית עד למקסימום שהוגדר.
ברירת המחדל של מספר הבקשות המקסימלי בו-זמנית היא 80, וזה מתאים להרבה קובצי אימג' של קונטיינרים. עם זאת, חשוב:
- אם הקונטיינר לא יכול לעבד הרבה בקשות מקבילות, צריך להקטין את הערך.
- אם הקונטיינר יכול לטפל בנפח גדול של בקשות, כדאי להגדיל את הערך.
כוונון של מספר הבקשות בו-זמנית בשירות
מספר הבקשות המקבילות שכל מכונה יכולה לטפל בהן עשוי להיות מוגבל על ידי סטאק התוכנות והשימוש במשאבים משותפים, כמו משתנים וחיבורים למסדי נתונים.
כדי לבצע אופטימיזציה של השירות למספר מקסימלי של בקשות בו-זמניות יציבות:
- אופטימיזציה של ביצועי השירות.
- מגדירים את רמת התמיכה הצפויה בו-זמניות בכל הגדרה של בו-זמניות ברמת הקוד. לא כל סטאק תוכנות דורש הגדרה כזו.
- פורסים את השירות.
- מגדירים את מספר הבקשות בו-זמנית ב-Cloud Run לשירות, כך שיהיה שווה או קטן מכל הגדרה ברמת הקוד. אם אין הגדרה ברמת הקוד, משתמשים במספר הצפוי של פעולות בו-זמניות.
- משתמשים בכלים לבדיקת עומסים שתומכים בהגדרת בו-זמניות. אתם צריכים לוודא שהשירות נשאר יציב בעומס ובמקביליות הצפויים.
- אם השירות לא פועל כמו שצריך, חוזרים לשלב 1 כדי לשפר את השירות או לשלב 2 כדי להפחית את מספר הבקשות בו-זמנית. אם השירות פועל היטב, חוזרים לשלב 2 ומגדילים את מספר הבקשות בו-זמנית.
ממשיכים לחזור על הפעולה עד שמוצאים את מספר הבקשות המקבילות המקסימלי היציב.
התאמת הזיכרון למספר הבקשות בו-זמנית
כל בקשה שהשירות מטפל בה דורשת כמות מסוימת של זיכרון נוסף. לכן, כשמשנים את מספר הבקשות בו-זמנית, חשוב לשנות גם את מגבלת הזיכרון.
הימנעו ממצב גלובלי שניתן לשינוי
אם אתם רוצים להשתמש במצב גלובלי שניתן לשינוי בהקשר בו-זמני, תצטרכו לבצע שלבים נוספים בקוד כדי לוודא שהפעולה מתבצעת באופן בטוח. כדי לצמצם את התחרות על משאבים, הגבילו את המשתנים הגלובליים לאתחול חד-פעמי ולשימוש חוזר, כמו שמתואר למעלה בקטע אופטימיזציה של הביצועים.
אם אתם משתמשים במשתנים גלובליים ניתנים לשינוי בשירות שמטפל בכמה בקשות בו-זמנית, הקפידו להשתמש בנעילות או ב-mutexes כדי למנוע מרוץ תהליכים.
היחס בין תפוקה, זמן אחזור ועלות
כוונון ההגדרה של מספר הבקשות המקסימלי בו-זמנית יכול לעזור לאזן בין התפוקה, זמן האחזור והעלות של השירות.
באופן כללי, הגדרה נמוכה יותר של מספר הבקשות המקסימלי בו-זמנית גורמת לזמן אחזור קצר יותר ולתפוקה נמוכה יותר לכל מכונה. ככל שמספר הבקשות המקסימלי בו-זמנית נמוך יותר, פחות בקשות מתחרות על משאבים בכל מכונה, וכל בקשה משיגה ביצועים טובים יותר. אבל בגלל שכל מכונה יכולה לטפל בפחות בקשות בו-זמנית, קצב העיבוד של כל מכונה נמוך יותר והשירות צריך יותר מכונות כדי לטפל באותו נפח תנועה.
בכיוון ההפוך, הגדרה גבוהה יותר של מספר הבקשות המקסימלי בו-זמנית בדרך כלל מובילה לזמן אחזור ארוך יותר ולתפוקה גבוהה יותר לכל מכונה. יכול להיות שהבקשות יצטרכו להמתין לגישה למשאבים כמו מעבד (CPU), GPU ורוחב פס של זיכרון בתוך המכונה, מה שיוביל לזמן אחזור ארוך יותר. אבל כל מכונה יכולה לעבד יותר בקשות בו-זמנית, כך שהשירות צריך פחות מכונות באופן כללי כדי לעבד את אותה תנועה.
שיקולי עלות
התמחור של Cloud Run הוא לפי זמן המכונה. אם הגדרתם חיוב מבוסס-מכונה, זמן המכונה הוא משך החיים הכולל של כל מכונה. אם הגדרתם חיוב לפי בקשות, זמן המכונה הוא הזמן שבו כל מכונה מעבדת בקשה אחת לפחות.
ההשפעה של המספר המקסימלי של בקשות מקבילות על החיוב תלויה בדפוס התנועה. הפחתת המספר המקסימלי של בקשות מקבילות יכולה להוביל לחשבון נמוך יותר אם ההגדרה הנמוכה יותר מובילה
- זמן אחזור קצר יותר
- מכונות שמסיימות את העבודה שלהן מהר יותר
- המכונות מושבתות מהר יותר, גם אם נדרשות יותר מכונות בסך הכול
אבל גם ההפך יכול לקרות: הקטנת המספר המקסימלי של בקשות מקבילות יכולה להגדיל את החיוב אם העלייה במספר המכונות לא מתקזזת עם הירידה בזמן הריצה של כל מכונה, בגלל זמן האחזור המשופר.
הדרך הטובה ביותר לבצע אופטימיזציה של החיוב היא באמצעות בדיקת עומסים, תוך שימוש בהגדרות שונות של מספר הבקשות המקסימלי בו-זמנית, כדי לזהות את ההגדרה שמובילה לזמן המופע הנמוך ביותר לחיוב, כפי שמוצג במדד המעקב container/billable_instance_time.
Container Security
הרבה שיטות אבטחה של תוכנות למטרות כלליות חלות על שירותים בקונטיינרים. יש כמה שיטות שספציפיות לקונטיינרים או שתואמות לפילוסופיה ולארכיטקטורה של קונטיינרים.
כדי לשפר את אבטחת הקונטיינר:
השתמשו בקובצי אימג' בסיסיים מאובטחים ומתוחזקים באופן פעיל, כמו קובצי האימג' הבסיסיים של Google או קובצי האימג' הרשמיים של Docker Hub.
כדי להחיל עדכוני אבטחה על השירותים, צריך לבנות מחדש באופן קבוע את קובצי האימג' של הקונטיינרים ולפרוס מחדש את השירותים.
הקפידו לכלול בקונטיינר רק את מה שנדרש כדי להפעיל את השירות. קוד, חבילות וכלים נוספים הם פרצות אבטחה פוטנציאליות. במאמר יצירת קובצי אימג' מינימליים של קונטיינרים מוסבר על ההשפעה על הביצועים.
מטמיעים תהליך build דטרמיניסטי שכולל גרסאות ספציפיות של תוכנות וספריות. כך אפשר למנוע הכללה של קוד לא מאומת במאגר התגים.
מגדירים את הקונטיינר כך שיפעל כמשתמש שאינו
rootבאמצעות ההצהרהUSERבקובץ Docker. יכול להיות שבחלק מקובצי האימג' של הקונטיינרים כבר מוגדר משתמש ספציפי.למנוע את השימוש בתכונות בגרסת טרום-השקה (Preview) באמצעות מדיניות ארגון מותאמת אישית.
סריקת אבטחה אוטומטית
מפעילים סריקת נקודות חולשה כדי לבצע סריקת אבטחה של קובצי אימג' של קונטיינרים שמאוחסנים ב-Artifact Registry.
יצירת קובצי אימג' מינימליים של קונטיינרים
קובצי אימג' גדולים של קונטיינרים עלולים להגדיל את פרצות האבטחה, כי הם מכילים יותר ממה שהקוד צריך.
בזכות טכנולוגיית הסטרימינג של קובצי אימג' של קונטיינרים ב-Cloud Run, הגודל של קובץ האימג' של הקונטיינר לא משפיע על זמני ההפעלה של הקונטיינר או על זמן העיבוד של הבקשות. גודל קובץ האימג' של הקונטיינר גם לא נכלל בזיכרון הזמין של הקונטיינר.
כדי ליצור קונטיינר מינימלי, כדאי לעבוד עם קובץ אימג' בסיסי ופשוט, כמו:
Ubuntu הוא קובץ אימג' גדול יותר, אבל הוא קובץ אימג' בסיסי נפוץ עם סביבת שרת מוכנה לשימוש ושלמה יותר.
אם תהליך ה-build של השירות שלכם כולל הרבה כלים, כדאי להשתמש ב-builds בכמה שלבים כדי שהקונטיינר יהיה קל בזמן הריצה.
במקורות המידע הבאים תוכלו לקרוא מידע נוסף על יצירת קובצי אימג' קלים של קונטיינרים:
- Kubernetes best practices: How and why to build small container images
- 7 שיטות מומלצות ליצירת קונטיינרים