במדריך הזה מתוארות אופטימיזציות לשירותי Cloud Run שנכתבו בשפת התכנות Python, וגם מידע רקע שיעזור לכם להבין את היתרונות והחסרונות של חלק מהאופטימיזציות. המידע בדף הזה הוא בנוסף לטיפים כלליים לאופטימיזציה, שרלוונטיים גם ל-Python.
הרבה מהשיטות המומלצות והאופטימיזציות באפליקציות נפוצות שמבוססות על Python באינטרנט מתמקדות ב:
- טיפול בבקשות מקבילות (גם מבוססות-thread וגם I/O לא חוסם)
- הפחתת זמן האחזור של התגובה באמצעות איגום חיבורים (connection pooling) ועיבוד באצווה של פונקציות לא קריטיות, למשל שליחת עקבות ומדדים למשימות ברקע.
אופטימיזציה של קובץ אימג' של קונטיינר
כדי לצמצם את זמני הטעינה וההפעלה, כדאי לבצע אופטימיזציה של קובץ אימג' של קונטיינר באמצעות השיטות הבאות:
- צמצום הקבצים שנטענים בהפעלה
- אופטימיזציה של שרת WSGI
צמצום הקבצים שנטענים בהפעלה
כדי לייעל את זמן ההפעלה, טוענים רק את הקבצים הנדרשים בזמן ההפעלה ומקטינים את הגודל שלהם. אם הקובץ גדול, אפשר לנסות את האפשרויות הבאות:
אפשר לאחסן קבצים גדולים, כמו מודלים של AI, בקונטיינר כדי לגשת אליהם מהר יותר. כדאי לשקול לטעון את הקבצים האלה אחרי ההפעלה או בזמן הריצה.
כדאי להגדיר נקודות הרכבה של נפח אחסון ב-Cloud Storage לקבצים גדולים שלא חיוניים בהפעלה, כמו נכסי מדיה.
כדאי לייבא רק את מודולי המשנה הנדרשים מכל יחסי תלות כבדים, או לייבא מודולים כשנדרש בקוד, במקום לטעון אותם בהפעלת האפליקציה.
אופטימיזציה של שרת WSGI
שפת Python קובעת תקן לאופן שבו אפליקציות יכולות ליצור אינטראקציה עם שרתי אינטרנט באמצעות הטמעה של תקן WSGI, PEP-3333. אחד משרתי WSGI הנפוצים יותר הוא gunicorn, שמשמש בחלק גדול מהתיעוד לדוגמה.
אופטימיזציה של gunicorn
כדי לבצע אופטימיזציה של ההפעלה של gunicorn, מוסיפים את הטקסט CMD אל Dockerfile:
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
אם אתם שוקלים לשנות את ההגדרות האלה, כדאי להתאים את מספר העובדים והשרשורים לכל אפליקציה בנפרד. לדוגמה, אפשר לנסות להשתמש במספר עובדים ששווה למספר הליבות הזמינות ולוודא שיש שיפור בביצועים, ואז לשנות את מספר השרשורים. הגדרת יותר מדי תהליכים או שרשורים יכולה להשפיע באופן שלילי, למשל להאריך את זמן האחזור של הפעלה במצב התחלתי (cold start), להגדיל את נפח הזיכרון שנצרך, להקטין את מספר הבקשות לשנייה וכו'.
כברירת מחדל, gunicorn יוצר תהליכי עבודה ומאזין ליציאה שצוינה בזמן ההפעלה, עוד לפני שהוא מעריך את קוד האפליקציה. במקרה כזה, כדאי להגדיר בדיקות הפעלה בהתאמה אישית לשירות, כי בדיקת ההפעלה שמוגדרת כברירת מחדל ב-Cloud Run מסמנת באופן מיידי את מופע הקונטיינר כפעיל ברגע שהוא מתחיל להאזין ב-$PORT.
אם רוצים לשנות את ההתנהגות הזו, אפשר להפעיל את gunicorn עם ההגדרה --preload כדי להעריך את קוד האפליקציה לפני ההאזנה. הפעולה הזו יכולה לעזור לכם:
- זיהוי באגים חמורים בזמן הריצה בזמן הפריסה
- שמירת משאבי הזיכרון
לפני שמוסיפים את התג הזה, כדאי לחשוב מה האפליקציה טוענת מראש.
שרתי WSGI אחרים
אתם לא מוגבלים לשימוש ב-gunicorn להרצת Python בקונטיינרים.
אתם יכולים להשתמש בכל שרת אינטרנט WSGI או ASGI, כל עוד הקונטיינר מאזין ליציאת HTTP $PORT, בהתאם לחוזה של זמן הריצה של הקונטיינר.
בין החלופות הנפוצות אפשר למצוא את uwsgi, uvicorn ו-waitress.
לדוגמה, אם יש קובץ בשם main.py שמכיל את האובייקט app, הפעלת הפקודות הבאות תתחיל שרת WSGI:
# uwsgi: pip install pyuwsgi
uwsgi --http :$PORT -s /tmp/app.sock --manage-script-name --mount /app=main:app
# uvicorn: pip install uvicorn
uvicorn --port $PORT --host 0.0.0.0 main:app
# waitress: pip install waitress
waitress-serve --port $PORT main:app
אפשר להוסיף אותם כCMD exec שורה ב-Dockerfile או כweb: רשומה ב-Procfile כשמשתמשים ב-buildpacks של Google Cloud.
אופטימיזציה של אפליקציות
בקוד השירות של Cloud Run, אפשר גם לבצע אופטימיזציה לזמני הפעלה מהירים יותר ולשימוש בזיכרון.
הפחתת מספר השרשורים
כדי לבצע אופטימיזציה של הזיכרון, אפשר לצמצם את מספר השרשורים, להשתמש באסטרטגיות ריאקטיביות לא חוסמות ולהימנע מפעילויות ברקע. כמו כן, כדאי להימנע מכתיבה למערכת הקבצים, כפי שצוין בדף הטיפים הכלליים.
אם רוצים לתמוך בפעילויות ברקע בשירות Cloud Run, צריך להגדיר את שירות Cloud Run לחיוב לפי מופע כדי להריץ פעילויות ברקע מחוץ לבקשות ועדיין לקבל גישה למעבד.
הפחתת משימות ההפעלה
לאפליקציות מבוססות-אינטרנט של Python יכולות להיות הרבה משימות להשלמה במהלך ההפעלה, כמו טעינה מראש של נתונים, חימום המטמון ויצירת מאגרי חיבורים. אם מבצעים את המשימות האלה ברצף, הן יכולות להימשך זמן רב. עם זאת, אם רוצים שהן יפעלו במקביל, צריך להגדיל את מספר ליבות המעבד.
Cloud Run שולח בקשה ממשתמש אמיתי כדי להפעיל מופע של הפעלה במצב התחלתי (cold start). יכול להיות שיהיו עיכובים ארוכים למשתמשים שהבקשה שלהם הוקצתה למופע שהופעל לאחרונה.
שיפור האבטחה באמצעות תמונות בסיס דקות
כדי לשפר את האבטחה של האפליקציה, כדאי להשתמש בתמונת בסיס דקה עם פחות חבילות וספריות.
אם אתם בוחרים לא להתקין Python ממקור בתוך הקונטיינרים, אתם יכולים להשתמש בתמונת בסיס רשמית של Python מ-Docker Hub. התמונות האלה מבוססות על מערכת ההפעלה Debian.
אם אתם משתמשים בתמונה python מ-Docker Hub, כדאי להשתמש בגרסה slim. התמונות האלה קטנות יותר כי הן לא כוללות מספר חבילות שישמשו ליצירת גלגלים, שאולי לא תצטרכו לעשות עבור האפליקציה שלכם. תמונת python מגיעה עם מהדר GNU C, מעבד מקדים וכלי ליבה.
כדי לזהות את עשר החבילות הגדולות ביותר בתמונת בסיס, מריצים את הפקודה הבאה:
DOCKER_IMAGE=python # or python:slim
docker run --rm ${DOCKER_IMAGE} dpkg-query -Wf '${Installed-Size}\t${Package}\t${Description}\n' | sort -n | tail -n10 | column -t -s $'\t'
מכיוון שיש פחות חבילות ברמה הנמוכה הזו, התמונות שמבוססות על slim מציעות גם שטח פנים קטן יותר להתקפה, עם פחות נקודות פוטנציאליות לפגיעות. יכול להיות שחלק מהתמונות האלה לא יכללו את הרכיבים הנדרשים לבניית גלגלים מהמקור.
אפשר להוסיף חבילות ספציפיות בחזרה על ידי הוספת שורה RUN apt install ל-קובץ Docker. מידע נוסף זמין במאמר בנושא שימוש בחבילות מערכת ב-Cloud Run.
יש גם אפשרויות לקונטיינרים שלא מבוססים על Debian. python:alpine
האפשרות הזו עשויה להוביל ליצירת קונטיינר קטן בהרבה, אבל יכול להיות שהרבה חבילות של Python לא יכללו קבצים מסוג wheel שעברו קומפילציה מראש ותומכים במערכות מבוססות Alpine. התמיכה משתפרת (ראו PEP-656), אבל היא עדיין משתנה.
אפשרות נוספת היא להשתמש ב-distroless base image, שלא מכיל מנהלי חבילות, מעטפות או תוכנות אחרות.
שימוש במשתנה הסביבה PYTHONUNBUFFERED לרישום ביומן
כדי לראות יומנים לא מאוחסנים במטמון מאפליקציית Python, מגדירים את משתנה הסביבה PYTHONUNBUFFERED. כשמגדירים את המשתנה הזה, הנתונים של stdout ושל
stderr מוצגים מיד ביומני מאגרי התגים, במקום להישמר במאגר זמני עד שמצטברת כמות מסוימת של נתונים או עד שהסטרימינג נסגר.
המאמרים הבאים
טיפים נוספים זמינים במאמר