שיטות מומלצות עבור Cloud Firestore

השיטות המומלצות שמפורטות כאן יכולות לשמש כחומר עזר מהיר כשמפתחים אפליקציה שמשתמשת ב-Cloud Firestore.

מיקום מסד הנתונים

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

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

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

מזהי מסמכים

  • לא להשתמש במזהי המסמכים . ו-...
  • אל תשתמשו בלוכסנים / במזהי מסמכים.
  • אל תשתמשו במזהי מסמכים שהערכים שלהם עולים באופן מונוטוני, כמו:

    • Customer1, ‏ Customer2, ‏ Customer3,‏ ...
    • Product 1, ‏ Product 2, ‏ Product 3,‏ ...

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

שמות השדות

  • לא מומלץ להשתמש בתווים הבאים בשמות של שדות, כי הם מחייבים שימוש נוסף בתו בריחה:

    • . נקודה
    • [ סוגר מרובע שמאלי
    • ] סוגר מרובע ימני
    • * כוכבית
    • ` גרש הפוך

מדדים

הפחתת זמן האחזור של פעולות הכתיבה

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

  • הגדרת החרגות מהאינדקס ברמת האוסף. ברירת מחדל פשוטה היא להשבית את האפשרויות Descending (יורד) ו-Array indexing (אינדקס מערכים). הסרת ערכים מאונדקס שלא נמצאים בשימוש תפחית גם את עלויות האחסון.

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

פטורים מסימון השעות

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

נרתיק תיאור
שדות מחרוזת גדולים

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

שיעורי כתיבה גבוהים לאוסף שמכיל מסמכים עם ערכים עוקבים

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

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

שדות TTL

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

שדות של מערכים או מפות גדולים

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

פעולות קריאה וכתיבה

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

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

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

ניסיונות חוזרים של עסקאות

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

עדכונים בזמן אמת

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

תכנון בהתאם להיקף

השיטות המומלצות הבאות מתארות איך להימנע ממצבים שיוצרים בעיות של התנגשות.

עדכונים במסמך יחיד

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

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

שיעורי קריאה, כתיבה ומחיקה גבוהים בטווח מצומצם של מסמכים

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

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

    Cloud Firestore allocates document IDs using a scatter algorithm. לא אמורות להיות בעיות של נקודות חמות בכתיבה אם יוצרים מסמכים חדשים באמצעות מזהי מסמכים אוטומטיים.

  • יוצר מסמכים חדשים בקצב גבוה באוסף עם מעט מסמכים.

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

  • מוחק מסמכים באוסף בקצב גבוה.

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

איך להימנע מדילוג על נתונים שנמחקו

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

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

docs = db.collection('WorkItems').order_by('created').limit(100)
delete_batch = db.batch()
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
delete_batch.commit()

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

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

completed_items = db.collection('CompletionStats').document('all stats').get()
docs = db.collection('WorkItems').start_at(
    {'created': completed_items.get('last_completed')}).order_by(
        'created').limit(100)
delete_batch = db.batch()
last_completed = None
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
  last_completed = doc.get('created')

if last_completed:
  delete_batch.update(completed_items.reference,
                      {'last_completed': last_completed})
  delete_batch.commit()

הערה: בדוגמה שלמעלה נעשה שימוש בשדה עם עלייה מונוטונית, שמהווה אנטי-תבנית לשיעורי כתיבה גבוהים.

הגדלת נפח התנועה

כדי לתת ל-Cloud Firestore מספיק זמן להכין מסמכים לעלייה בתנועה, צריך להגדיל בהדרגה את התנועה לאוספים חדשים או למסמכים שקרובים זה לזה בסדר לקסיקוגרפי. מומלץ להתחיל עם עד 500 פעולות בשנייה באוסף חדש, ואז להגדיל את נפח התנועה ב-50% כל 5 דקות. באופן דומה, אפשר להגדיל את נפח התנועה של פעולות הכתיבה, אבל חשוב לזכור את המגבלות הרגילות של Cloud Firestore. חשוב לוודא שהפעולות מפוזרות באופן שווה יחסית בכל טווח המפתחות. זה נקרא כלל 500/50/5.

העברת תנועה לאוסף חדש

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

בעיה דומה יכולה להתרחש אם משנים את מזהי המסמכים של הרבה מסמכים באותו האוסף.

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

קריאה מקבילה

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

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

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

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

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

פרטיות

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

מניעת גישה לא מורשית

כדי למנוע פעולות לא מורשות במסד הנתונים, צריך להשתמש ב-Cloud Firestore Security Rules. לדוגמה, שימוש בכללים יכול למנוע מצב שבו משתמש זדוני מוריד שוב ושוב את כל מסד הנתונים שלכם.

מידע נוסף על שימוש ב-Cloud Firestore Security Rules