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

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

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

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

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

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

מזהי מסמכים

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

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

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

שמות השדות

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

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

מדדים

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

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

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

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

פטורים מאינדקס

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

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

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

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

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

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

שדות TTL

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

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

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

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

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

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

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

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

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

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

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

עיצוב בהתאם להיקף

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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