שיטות מומלצות

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

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

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

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

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

מזהי מסמכים

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

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

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

שמות השדות

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

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

מדדים

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

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

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

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

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

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

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

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

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

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

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

שדות TTL

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    מערכת 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()

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

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

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

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

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

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

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

אפשרויות קריאה מקבילות

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

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

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

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

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

פרטיות

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