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

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

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

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

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

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

מזהי מסמכים

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

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

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

שמות השדות

  • כדאי להימנע מהתווים הבאים בשמות של שדות, כי הם דורשים הוספה של תווי בריחה (escape):

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

אינדקסים

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

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

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

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

החרגות מהאינדקס

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

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

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

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

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

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

שדות TTL

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

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

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

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

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

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

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

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

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

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

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

עיצוב בקנה מידה גדול

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 בכל המסמכים שנמחקו לאחרונה. הפעולה הזו מאטה את השאילתות.

כדי לשפר את הביצועים, אפשר להשתמש ב-method‏ 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 יכול לטפל בתנועה לאוסף החדש.

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

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

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

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

פרטיות

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

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

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

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