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

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

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

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

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

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

מזהי מסמכים

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

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

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

שמות שדות

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

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

מדדים

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

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

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

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

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

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

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

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

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

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

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

שדות TTL

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • יוצר מסמכים חדשים ברקצב גבוה מאוד ומקצה מזהי monotonically increasing משלו.

    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