יחידת לימוד 6: מעבר מ-Cloud Datastore ל-Cloud Firestore

1. סקירה כללית

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

משתמשי App Engine שניגשים ל-Datastore באמצעות ספריות הלקוח Cloud NDB או Cloud Datastore זמינים לכל המשתמשים, והם לא צריכים לבצע העברה נוספת. יחד עם זאת, Cloud Firestore מייצג את מאגר הנתונים החדש ביותר, שניתן להתאמה עם זמינות גבוהה, NoSQL, עם תכונות ממסד הנתונים בזמן אמת של Firebase.

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

כאן מוסבר איך

  • הכרת ההבדלים בין Datastore ל-Firestore
  • מעבר מ-Cloud Datastore ל-Cloud Firestore

מה צריך להכין

סקר

איך בכוונתך להשתמש ב-Codelab הזה?

לקריאה בלבד לקרוא אותו ולבצע את התרגילים

2. רקע

Datastore של App Engine הפך למוצר עצמאי בשנת 2013, Google Cloud Datastore, וזמין כעת למפתחים מחוץ ל-App Engine. בשנה שלאחר מכן, Google רכשה את Firebase. בזמנו, הוא היה ידוע במסד הנתונים שלו בזמן אמת.

בשנים הקרובות, הצוותים של Firebase ו-Cloud Datastore עבדו על שילוב חלק מהתכונות של Firebase ב-Datastore. כתוצאה מכך, בשנת 2017 השקנו את הדור הבא של Cloud Datastore. כדי לשקף ירושה של חלק מהתכונות של Firebase, שם המותג השתנה כ-Cloud Firestore.

Cloud Firestore הפך למנגנון האחסון ב-NoSQL שמוגדר כברירת מחדל לפרויקטים ב-Google Cloud. אפליקציות חדשות יכולות להשתמש ב-Cloud Firestore באופן מקורי, ואילו מסדי נתונים קיימים של Datastore הומרו ל-Firestore קצה חדש ופועלים עכשיו כ'Firestore במצב Datastore' כדי לשמור על תאימות לפעולות של Datastore. כתוצאה מכך, אפליקציות יכולות להפעיל את Cloud Firestore רק באחד מהמצבים האלה, ולאחר הגדרתן, לא ניתן לשנות אותן.

בשלב הזה, כשמשתמשים יוצרים פרויקטים חדשים ובוחרים פתרון NoSQL, הם מתבקשים לבחור באחת מהאפשרויות הבאות: Firestore במצב Datastore או Firestore במצב נייטיב. אחרי שהמשתמשים מוסיפים ישויות של Datastore, הם לא יכולים לעבור ל-Firestore ובאופן דומה, אחרי שבוחרים במצב המקורי של Firestore, הם לא יכולים יותר לחזור ל-Datastore (או ל-Firestore במצב Datastore). לפרטים נוספים, אפשר לקרוא את המאמר בנושא בחירה בין Cloud Firestore במצב Datastore או בדף המקורי של מצב Firestore. כדי להעביר אפליקציה ל-Firestore, צריך ליצור פרויקט חדש ולייצא את Datastore ואז לייבא אותו אל Firestore. מטרת המדריך הזה היא לתת למפתחים מושג לגבי ההבדלים בין השימוש ב-Cloud Datastore לבין Cloud Firestore.

זו לא העברה שאנחנו מצפים מהמשתמשים לבצע, ולכן היא אופציונלית. יש יתרונות ברורים לשימוש ב-Cloud Firestore כמו אימות לקוח, שילוב של כללי Firebase וכמובן, מסד הנתונים בזמן אמת של Firebase, אבל שלבי ההעברה הם "לא נוחות":

  • חייבים להשתמש בפרויקט שונה מזה של הפרויקט הנוכחי של האפליקציה.
  • לא ניתן להעביר פרויקט שבו אפליקציה הוסיפה ישויות של Datastore ל-Firestore במצב נייטיב
  • באופן דומה, פרויקט שבחר ב-Firestore במצב נייטיב לא יכול לחזור ל-Firestore במצב Datastore.
  • אין כלי העברה שיכול להעביר נתונים בסטרימינג מפרויקט אחד לאחר.
  • חלק מהתכונות הקריטיות של Datastore, כולל מרחבי שמות ותפוקת כתיבה גבוהה יותר (מעל 10,000 שניות), לא זמינות ב-Firestore.
  • הכלים לייצוא ולייבוא הם "פרימיטיביים" וגם 'הכול או כלום' במקרים מסוימים.
    • אם באפליקציה יש הרבה ישויות של Datastore, הייצוא יכול להימשך כמה שעות ואז לייבא אותו אל Firestore.
    • בזמן הזה, לאפליקציה/לשירות לא תהיה אפשרות לכתוב או לעדכן נתונים.
    • פעילויות ההעברה נחשבות לשימוש רגיל; כדאי לחלק אותו (לגבי מכסות יומיות, אם אפשר) כדי למזער את העלויות.
    • מכיוון שהשירות החדש פועל בפרויקט אחר, יהיה צורך בחלון כדי להפיץ את עדכוני ה-DNS.
  • ל-Datastore ול-Firestore יש מודלים דומים של נתונים, אך שונים, כך שההעברה דורשת עדכון באופן שבו האפליקציה או השירות פועלים
    • שאילתות אב מ-Datastore הן עכשיו שאילתות איסוף של Firestore (ברירת המחדל)
    • שאילתות מסוג רחב מ-Datastore הן שאילתות על קבוצת איסוף ב-Firestore
    • המדדים והטיפול בהם שונים, וכו'.

עם זאת, אם יש לכם אפליקציה פשוטה למדי שאפשר לשקול להעברה, שמתכוננים לדמות העברה כזו או פשוט כאן כדי ללמוד על Datastore לעומת Firestore, כדאי להמשיך!

משתמשי Python 2: הקוד האופציונלי הזה להעברה מוצג רק ב-Python 3. עם זאת, מכיוון ש-Cloud Firestore תומך גם ב-2.x, המשתמשים יכולים לבצע אינטרפולציה של ההבדלים בשימוש. אחת הדוגמאות: רשומות Firestore משתמשות במחרוזות Unicode (במקום במחרוזות בייטים), ולכן נדרש אינדיקטור מוביל u'' לליטרלים של מחרוזת Python 2. כלומר, פונקציית store_visit() 2.x תיראה כך:

def store_visit(remote_addr, user_agent):
    doc_ref = fs_client.collection(u'Visit')
    doc_ref.add({
        u'timestamp': datetime.now(),
        u'visitor': u'{}: {}'.format(remote_addr, user_agent),
    })

מלבד זאת, ספריית הלקוח צריכה לפעול באופן דומה. הבעיה הנוספת היחידה שצריך לקחת בחשבון היא שספריית Cloud Firestore בגודל 2.x "קפואה". ככל שאנחנו מתקדמים יותר, כך יותר ויותר תכונות חדשות יהיו זמינות רק בספריית הלקוח של Firestore בגודל 3.x.

אם ממשיכים בהעברה, אלה השלבים העיקריים במדריך הזה:

  1. הגדרה/עבודה מוקדמת
  2. הוספת ספריית Cloud Firestore
  3. עדכון קובצי אפליקציה

3. הגדרה/עבודה מוקדמת

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

1. הגדרת הפרויקט

מומלץ להשתמש שוב באותו פרויקט ששימש להשלמת הקוד של יחידת לימוד 3. לחלופין, אפשר ליצור פרויקט חדש לגמרי או להשתמש שוב בפרויקט קיים. צריך לוודא שלפרויקט יש חשבון פעיל לחיוב וש-App Engine (אפליקציה) מופעל.

2. אחזור של אפליקציה בסיסית לדוגמה

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

בין אם אתם משתמשים בקוד של מודול 3 שלכם או שלנו, נתחיל בו. במודול 6 Codelab זה מנחה אותך בכל שלב בתהליך, ובסיום התהליך הוא אמור להיות דומה לקוד בנקודת FINISH. (המדריך הזה זמין רק ב-Python 3).

הספרייה של קובצי מודול 3 (שלכם או שלנו) אמורה להיראות כך:

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. (מחדש) פריסה של אפליקציית מודול 3

שאר השלבים לפני העבודה שצריך לבצע עכשיו:

  1. כדאי להכיר מחדש את כלי שורת הפקודה gcloud (אם רלוונטי)
  2. (אם צריך לפרוס מחדש את הקוד של מודול 3 ב-App Engine)

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

דרישות Python 2

  • חשוב לוודא ש-app.yaml (עדיין) מפנה לחבילות בחבילה של צד שלישי: grpcio ו-setuptools.
  • צריך לוודא ש-appengine_config.py עדיין משתמש ב-pkg_resources וב-google.appengine.ext.vendor כדי להפנות את האפליקציה למשאבים של צד שלישי.
  • בקטע הבא שמעדכנים את requirements.txt, צריך להשתמש ב-google-cloud-firestore==1.9.0 כי זו הגרסה הסופית של ספריית הלקוח של Python Firestore שתואמת ל- 2.x.
    • אם בrequirements.txt יש ערך עבור google-cloud-core, צריך להשאיר אותו כפי שהוא.
    • מוחקים את lib ומתקינים מחדש עם pip install -t lib -r requirements.txt.

4. עדכון קובצי תצורה (הוספת ספריית Cloud Firestore)

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

מחליפים את השורה google-cloud-datastore בשורה google-cloud-firestore ב-requirements.txt כדי שהיא תיראה כך:

Flask==1.1.2
google-cloud-firestore==2.0.2

מומלץ להשתמש בגרסאות האחרונות של כל ספרייה. מספרי הגרסאות שלמעלה הם העדכניים ביותר נכון לזמן כתיבה זה. הקוד בתיקיית המאגר FINISH מתעדכן בתדירות גבוהה יותר ויכול להיות שיש לו גרסה חדשה יותר.

אין שינויים נוספים בהגדרות, כך ש-app.yaml ו-templates/index.html יישארו כפי שהם.

5. עדכון קובצי אפליקציה

יש רק קובץ אפליקציה אחד, main.py, כך שכל השינויים בקטע הזה משפיעים רק על הקובץ הזה.

1. יבוא

שינוי ייבוא החבילות הוא שינוי קל מ-datastore ל-firestore:

  • לפני:
from google.cloud import datastore
  • אחרי:
from google.cloud import firestore

2. גישה ל-Firestore

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

  • לפני:
app = Flask(__name__)
ds_client = datastore.Client()
  • אחרי:
app = Flask(__name__)
fs_client = firestore.Client()

ההעברה מ-Cloud NDB ל-Cloud Datastore כבר מסתיימת בעבודה הקשה שצריך לעבור אל Cloud Firestore. באמצעות Datastore, יוצרים רשומות נתונים בצורת ישויות שמורכבות ממאפיינים נפוצים ומקבצים אותן לפי מפתחות. רשומות נתונים ב-Firestore הן מסמכים, שמורכבות מצמדי מפתח-ערך ומקובצות יחד לאוספים. מעבר מ-Datastore צריך לחשוב על ההבדלים האלה, כי הם יופיעו כשיוצרים רשומות נתונים ובשליחת שאילתות לגביהם. התוצאות עשויות להשתנות בהתאם לרמת המורכבות של הקוד של Datastore.

ב-Datastore, שולחים שאילתות שמבוססות על סוג הישות יחד עם קריטריונים לסינון ומיון. ב-Firestore, ביצוע שאילתות על הנתונים דומה. בואו נבחן דוגמה מהירה, בהנחה שערכי השאילתות, הלקוחות (ds_client או fs_client, בהתאמה) וייבוא של:

from datetime import datetime
from firestore.Query import DESCENDING

OCT1 = datetime(2020, 10, 1)
LIMIT = 10

לגבי Datastore, נחפש שאילתה לגבי עשר הישויות האחרונות של Visit אחרי 1 באוקטובר 2020 בסדר יורד:

query = ds_client.query(kind='Visit')
query.add_filter('timestamp', '>=', datetime(2020, 10, 1))
query.order = ['-timestamp']
return query.fetch(limit=LIMIT)

לעשות את אותו הדבר לגבי Firestore, מהאוסף של Visit:

query = fs_client.collection('Visit')
query.where('timestamp', '>=', datetime(2020, 10, 1))
query.order_by('timestamp', direction=DESCENDING)
return query.limit(LIMIT).stream()

השאילתה לדוגמה של האפליקציה פשוטה יותר (ללא משפט WHERE). לידיעתך, הנה הקוד של Cloud Datastore:

  • לפני:
def store_visit(remote_addr, user_agent):
    entity = datastore.Entity(key=ds_client.key('Visit'))
    entity.update({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })
    ds_client.put(entity)

def fetch_visits(limit):
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    return query.fetch(limit=limit)

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

  • אחרי:
def store_visit(remote_addr, user_agent):
    doc_ref = fs_client.collection('Visit')
    doc_ref.add({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })

def fetch_visits(limit):
    visits_ref = fs_client.collection('Visit')
    visits = (v.to_dict() for v in visits_ref.order_by('timestamp',
            direction=firestore.Query.DESCENDING).limit(limit).stream())
    return visits

הפונקציה הראשית root() לא משתנה כמו קובץ התבנית index.html. חשוב לבדוק שוב את השינויים, לשמור, לפרוס ולאמת.

6. סיכום/ניקוי

פריסת אפליקציה

פורסים מחדש את האפליקציה באמצעות gcloud app deploy ומוודאים שהאפליקציה פועלת. הקוד אמור עכשיו להתאים למה שמופיע במאגר של מודול 6 (או בגרסה 2.x אם זו ההעדפה שלכם).

אם עברתם לסדרה הזו בלי לבצע אף אחת מההדרכות הקודמות של הקוד, האפליקציה עצמה לא משתנה. הוא רושם את כל הביקורים בדף האינטרנט הראשי (/) ונראה כך לאחר שביקרת באתר מספיק פעמים:

אפליקציית visitme

כל הכבוד על השלמת ההעברה האופציונלית של מודול 6. סביר להניח שזו אחת מההעברות, אם לא הסופית, שתוכלו לבצע עד לאחסון הנתונים של App Engine. אפשרות אחת להעברה חלופית היא יצירת קונטיינרים לאפליקציה ל-Cloud Run, אם עדיין לא עשיתם זאת (ראו מודולים 4 ו-5, קישור ל-codelabs מקושר בהמשך).

אופציונלי: הסרת המשאבים

מה לעשות כדי שלא נחייב אתכם עד שתהיו מוכנים לעבור ל-Codelab הבא של ההעברה? כמפתחים קיימים, סביר להניח שאתם כבר מעודכנים לגבי נתוני התמחור של App Engine.

אופציונלי: השבתת האפליקציה

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

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

השלבים הבאים

מעבר למדריך הזה, יש כמה שיעורי Lab נוספים של מודולי העברה שאפשר להשתמש בהם:

  • מודול 7: תורים של משימות דחיפה ב-App Engine (נדרש אם משתמשים ב[push] תורי משימות)
    • הוספת משימות דחיפה ל-App Engine taskqueue לאפליקציית מודול 1
    • הכנת המשתמשים למעבר אל Cloud Tasks במודול 8
  • מודול 4: מעבר ל-Cloud Run באמצעות Docker
    • יצירת קונטיינרים לאפליקציה להרצה ב-Cloud Run באמצעות Docker
    • ההעברה הזו מאפשרת לכם להישאר ב-Python 2.
  • מודול 5: מעבר ל-Cloud Run עם Cloud Buildpacks
    • יצירת קונטיינרים לאפליקציה כדי לרוץ ב-Cloud Run באמצעות Cloud Buildpacks
    • לא צריך לדעת שום דבר על Docker, על קונטיינרים או על Dockerfile.
    • כדי שהאפליקציה צריכה לעבור כבר ל-Python 3 (ב-Buildpacks אין תמיכה ב-Python 2).

7. מקורות מידע נוספים

בעיות/משוב על Codelabs עם מודול ההעברה של App Engine

אם נתקלתם בבעיות ב-Codelab הזה, צריך קודם לחפש את הבעיה לפני השליחה. קישורים לחיפוש וליצירת בעיות חדשות:

משאבים להעברה

בטבלה שלמטה מופיעים הקישורים לתיקיות המאגר של מודול 3 (START) ומודול 6 (FINISH). אפשר לגשת אליהן גם דרך המאגר לכל ההעברות של App Engine, שאותו אפשר לשכפל או להוריד בקובץ ZIP.

Codelab

ֶPython 2

ֶPython 3

יחידת לימוד 3

(קוד)

קוד

יחידת לימוד 6

(לא רלוונטי)

קוד

משאבי App Engine

בהמשך מופיעים מקורות מידע נוספים בנוגע להעברה הספציפית הזו: