הטמעה של ריבוי דיירים באמצעות מרחבי שמות

‫Namespaces API מאפשר לכם להפעיל בקלות multitenancy באפליקציה שלכם, פשוט על ידי בחירת מחרוזת של מרחב שמות לכל דייר ב-appengine_config.py using the namespace_manager package.

הגדרת מרחב השמות הנוכחי

אפשר לקבל, להגדיר ולאמת מרחבי שמות using the namespace_manager package. מנהל מרחב השמות מאפשר להגדיר מרחב שמות נוכחי עבור ממשקי API עם מרחב שמות מופעל. מגדירים מראש מרחב שמות נוכחי ב-appengine_config.py ומאגרי הנתונים ו-memcache משתמשים אוטומטית במרחב השמות הזה.

רוב המפתחים ב-App Engine משתמשים בדומיין שלהם ב-Google Workspace (לשעבר G Suite) כמרחב השמות הנוכחי. Google Workspace מאפשרת לפרוס את האפליקציה לכל דומיין שבבעלותכם, כך שתוכלו להשתמש בקלות במנגנון הזה כדי להגדיר מרחבי שמות שונים לדומיינים שונים. לאחר מכן, תוכלו להשתמש במרחבי השמות הנפרדים האלה כדי להפריד בין הנתונים בדומיינים. למידע נוסף, אפשר לעיין במאמר בנושא מיפוי דומיינים בהתאמה אישית.

בדוגמת הקוד הבאה מוצג איך להגדיר את מרחב השמות הנוכחי לדומיין של Google Workspace ששימש למיפוי כתובת ה-URL. חשוב לציין שהמחרוזת הזו תהיה זהה לכל כתובות ה-URL שממופות דרך אותו דומיין Google Workspace.

כדי להגדיר מרחב שמות ב-Python, משתמשים במערכת ההגדרות של App Engine‏ appengine_config.pyבתיקיית הבסיס של האפליקציה. בדוגמה הפשוטה הבאה אפשר לראות איך משתמשים בדומיין של Google Workspace כמרחב השמות הנוכחי:

from google.appengine.api import namespace_manager

# Called only if the current namespace is not set.
def namespace_manager_default_namespace_for_request():
    # The returned string will be used as the Google Apps domain.
    return namespace_manager.google_apps_namespace()

אם לא מציינים ערך למאפיין namespace, מרחב השמות מוגדר כמחרוזת ריקה. המחרוזת namespace היא שרירותית, אבל היא מוגבלת גם למקסימום של 100 תווים אלפאנומריים, נקודות, קווים תחתונים ומקפים. במילים אחרות, מחרוזות של מרחבי שמות צריכות להתאים לביטוי הרגולרי [0-9A-Za-z._-]{0,100}.

לפי המוסכמה, כל מרחבי השמות שמתחילים ב-_ (קו תחתון) שמורים לשימוש המערכת. הכלל הזה במרחב השמות של המערכת לא נאכף, אבל אם לא תפעלו לפיו, יכול להיות שתיתקלו בתוצאות שליליות לא מוגדרות.

מניעת דליפת נתונים

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

  • שימוש במרחבי שמות עם ממשקי App Engine API שעדיין לא תומכים במרחבי שמות. לדוגמה, ב-Blobstore אין תמיכה במרחבי שמות. אם אתם משתמשים במרחבי שמות עם Blobstore, אתם צריכים להימנע משימוש בשאילתות של Blobstore לבקשות של משתמשי קצה, או במפתחות של Blobstore ממקורות לא מהימנים.
  • שימוש באמצעי אחסון חיצוני (במקום memcache ו-Datastore), באמצעות URL Fetch או מנגנון אחר, בלי לספק תוכנית חלוקה למרחבי שמות.
  • הגדרת מרחב שמות על סמך דומיין האימייל של המשתמש. ברוב המקרים, לא רוצים שכל כתובות האימייל בדומיין יוכלו לגשת למרחב שמות. שימוש בדומיין האימייל גם מונע מהאפליקציה שלכם להשתמש במרחב שמות עד שהמשתמש מתחבר.

פריסת מרחבי שמות

בקטעים הבאים מוסבר איך פורסים מרחבי שמות באמצעות כלים אחרים של App Engine וממשקי API.

יצירת מרחבי שמות לכל משתמש

יש אפליקציות שצריכות ליצור מרחבי שמות על בסיס כל משתמש. אם רוצים להפריד בין נתונים ברמת המשתמש עבור משתמשים מחוברים, אפשר להשתמש ב- User.user_id() , שמחזיר מזהה ייחודי וקבוע למשתמש. דוגמת הקוד הבאה מדגימה איך להשתמש ב-Users API למטרה הזו:

from google.appengine.api import users

def namespace_manager_default_namespace_for_request():
    # assumes the user is logged in.
    return users.get_current_user().user_id()

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

שימוש במרחבי שמות עם Datastore

כברירת מחדל, Datastore משתמש בהגדרה הנוכחית של מרחב השמות בכלי לניהול מרחבי שמות לבקשות של Datastore. ממשק ה-API מחיל את מרחב השמות הנוכחי על אובייקטים מסוג Key או Query כשהם נוצרים. לכן, צריך להיזהר אם אפליקציה מאחסנת אובייקטים של Key או Query בפורמטים סדרתיים, כי מרחב השמות נשמר בסדרות האלה.

אם אתם משתמשים באובייקטים של Key ושל Query שעברו דה-סריאליזציה, חשוב לוודא שהם פועלים כמצופה. רוב האפליקציות הפשוטות שמשתמשות ב-Datastore‏ (put/query/get) בלי להשתמש במנגנוני אחסון אחרים יפעלו כמצופה אם תגדירו את מרחב השמות הנוכחי לפני שתקראו ל-Datastore API.

אובייקטים מסוג Query ו-Key מדגימים את ההתנהגויות הייחודיות הבאות בהקשר של מרחבי שמות:

  • אובייקטים מסוג Query ו-Key יורשים את מרחב השמות הנוכחי כשהם נוצרים, אלא אם מגדירים מרחב שמות מפורש.
  • כשיוצרים Key חדש מאב קדמון, הוא יורש את מרחב השמות של האב הקדמון.

שימוש במרחבי שמות עם Memcache

כברירת מחדל, memcache משתמש במרחב השמות הנוכחי ממנהל מרחבי השמות לבקשות memcache. ברוב המקרים, לא צריך להגדיר מרחב שמות באופן מפורש ב-memcache, ופעולה כזו עלולה לגרום לבאגים לא צפויים.

עם זאת, יש מקרים ייחודיים שבהם כדאי להגדיר מרחב שמות באופן מפורש ב-memcache. לדוגמה, יכול להיות שלאפליקציה שלכם יש נתונים משותפים שמשותפים לכל מרחבי השמות (כמו טבלה שמכילה קודי מדינות).

באמצעות Python API ל-memcache, אפשר לקבל את מרחב השמות הנוכחי ממנהל מרחבי השמות או להגדיר אותו באופן מפורש כשיוצרים את שירות memcache. בדוגמה שלמטה מוגדר מרחב השמות באופן מפורש כשמאחסנים ערך ב-memcache:

  // Store an entry to the memcache explicitly
memcache.add("key", data, namespace='abc')

שימוש במרחבי שמות בתור למשימות

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

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

כשמשימה חדשה קוראת לשיטה של תור המשימות add() , תור המשימות מעתיק את מרחב השמות הנוכחי ואת הדומיין של Google Workspace (אם רלוונטי) ממנהל מרחבי השמות. כשהמשימה מופעלת, מרחב השמות הנוכחי ומרחב השמות של Google Workspace משוחזרים.

אם מרחב השמות הנוכחי לא מוגדר בבקשה המקורית (במילים אחרות, אם get_namespace() מחזירה ''), אפשר להשתמש ב-set_namespace() כדי להגדיר את מרחב השמות הנוכחי למשימה.

יש מקרים ייחודיים שבהם כדאי להגדיר במפורש מרחב שמות למשימה שפועלת בכל מרחבי השמות. לדוגמה, אפשר ליצור משימה שמצברת נתוני שימוש בכל מרחבי השמות. אחר כך תוכלו להגדיר במפורש את מרחב השמות של המשימה.

שימוש במרחבי שמות ב-Blobstore

ה-Blobstore לא מפולח לפי מרחב שמות. כדי לשמור על מרחב שמות ב-Blobstore, צריך לגשת ל-Blobstore דרך אמצעי אחסון שמודע למרחב השמות (נכון לעכשיו רק memcache,‏ Datastore ו-task queue). לדוגמה, אם ה-Key של Blob מאוחסן בישות Datastore, אפשר לגשת אליו באמצעות Key או Query שמכיר את מרחב השמות.

אם האפליקציה ניגשת ל-Blobstore באמצעות מפתחות שמאוחסנים באחסון עם מרחב שמות, אין צורך לפלח את Blobstore עצמו לפי מרחב שמות. כדי למנוע דליפות של BLOB בין מרחבי שמות, האפליקציות צריכות:

  • לא נעשה שימוש ב- BlobInfo.gql() לבקשות של משתמשי קצה. אפשר להשתמש בשאילתות BlobInfo לבקשות אדמיניסטרטיביות (כמו יצירת דוחות על כל ה-blob של האפליקציות), אבל שימוש בהן לבקשות של משתמשי קצה עלול לגרום לדליפות נתונים, כי כל רשומות ה-BlobInfo לא מחולקות לפי מרחב שמות.
  • לא להשתמש במפתחות Blobstore ממקורות לא מהימנים.

הגדרת מרחבי שמות לשאילתות ב-Datastore

ב Google Cloud מסוף, אפשר להגדיר את מרחב השמות לשאילתות Datastore.

אם לא רוצים להשתמש בברירת המחדל, בוחרים את מרחב השמות הרצוי מהתפריט הנפתח.

שימוש במרחבי שמות בכלי להעלאה בכמות גדולה

כלי ההעלאה בכמות גדולה תומך בדגל --namespace=NAMESPACE שמאפשר לציין את מרחב השמות שבו רוצים להשתמש. כל מרחב שמות מטופל בנפרד, ואם רוצים לגשת לכל מרחבי השמות, צריך לבצע איטרציה דרכם.

כשיוצרים מופע חדש של Index, הוא מוקצה למרחב השמות הנוכחי כברירת מחדל:

# set the current namespace
namespace_manager.set_namespace("aSpace")
index = search.Index(name="myIndex")
# index namespace is now fixed to "aSpace"

אפשר גם להקצות מרחב שמות באופן מפורש בבונה:

index = search.Index(name="myIndex", namespace="aSpace")

אחרי שיוצרים מפרט אינדקס, אי אפשר לשנות את מרחב השמות שלו:

# change the current namespace
namespace_manager.set_namespace("anotherSpace")
# the namespaceof 'index' is still "aSpace" because it was bound at create time
index.search('hello')