להבין שאילתות בזמן אמת בקנה מידה נרחב

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

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

בקטעים הבאים מפורטות המלצות להתאמת האפליקציה לעומס.

בחירת מיקום של מסד נתונים קרוב למשתמשים

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

דוגמה לארכיטקטורה של אפליקציה בזמן אמת

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

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

תכנון למען אמינות

הנושאים הבאים משפרים את האמינות של האפליקציה או משפיעים עליה:

הפעלת מצב אופליין

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

הסבר על ניסיונות חוזרים אוטומטיים

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

בחירה בין מיקומים אזוריים למיקומים בכמה אזורים

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

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

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

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

לקוח א' כותב למסד הנתונים כדי להוסיף ולעדכן מסמכים באוסף שנקרא chatroom:

collection chatroom:
    document message1:
      from: 'Sparky'
      message: 'Welcome to Cloud Firestore!'

    document message2:
      from: 'Santa'
      message: 'Presents are coming'

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

הארכיטקטורה של קישור ל-snapshot של Listener

רצף האירועים הבא מתרחש כשלקוח ב' מחבר מאזין של קובץ snapshot למסד הנתונים:

  1. לקוח ב' פותח חיבור אל Cloud Firestore ורושם אוזן על ידי ביצוע קריאה ל-onSnapshot(collection("chatroom")) דרך Firebase SDK. המאזינים האלה יכולים להישאר פעילים למשך שעות.
  2. החזית של Cloud Firestore שולחת שאילתה למערכת האחסון הבסיסית כדי לאתחל את מערך הנתונים. הוא טוען את כל קבוצת התוצאות של המסמכים התואמים. אנחנו מכנים זאת שאילתה של סקרים. לאחר מכן המערכת מבצעת הערכה של כללי האבטחה של Firebase במסד הנתונים כדי לוודא שהמשתמש יכול לגשת לנתונים האלה. אם המשתמש מורשה, מסד הנתונים מחזיר את הנתונים למשתמש.
  3. לאחר מכן, השאילתה של לקוח ב' עוברת למצב הקשבה. ה-listener נרשם עם handler של מינויים וממתין לעדכונים בנתונים.
  4. לקוח א' שולח עכשיו פעולת כתיבה כדי לשנות מסמך.
  5. מסד הנתונים מבצע את השינויים במסמך במערכת האחסון שלו.
  6. מבחינת עסקאות, המערכת מבצעת את אותו עדכון ביומן השינויים הפנימי. ביומן השינויים מופיע סדר קפדני של השינויים כפי שהם מתרחשים.
  7. ביומן השינויים מתבצעת חלוקה של הנתונים המעודכנים למאגר של מודולים לטיפול במינוי.
  8. התאמת שאילתה הפוכה מתבצעת כדי לבדוק אם המסמך המעודכן תואם לרכיבי snapshot שרשומים כרגע. בדוגמה הזו, המסמך תואם למאזין של קובץ ה-snapshot של לקוח ב'. כפי שרומז השם, אפשר להתייחס למתאמת השאילתות ההפוכות כשאילתה רגילה של מסד נתונים, אבל הפוך. במקום לחפש במסמכים כדי למצוא את אלה שתואמים לשאילתה, המערכת מחפשת ביעילות בשאילתות כדי למצוא את אלה שתואמות למסמך נכנס. כשהמערכת מוצאת התאמה, היא מעבירה את המסמך הרלוונטי למאזינים של קובצי snapshot. לאחר מכן, המערכת מעריכה את כללי האבטחה של Firebase במסד הנתונים כדי לוודא שרק משתמשים מורשים מקבלים את הנתונים.
  9. המערכת מעבירה את עדכון המסמך ל-SDK במכשיר של לקוח ב', והקריאה החוזרת (callback) של onSnapshot מופעלת. אם התכונה 'שמירה במטמון מקומי' מופעלת, ה-SDK מחיל את העדכון גם במטמון המקומי.

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

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

שימוש בשיטות מומלצות להתאמה לעומס של שאילתות בזמן אמת

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

להבין את תנועת הכתיבה הגבוהה במערכת

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

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

הארכיטקטורה של יצירת ענפים ביומן השינויים

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

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

הסבר על האינטראקציה בין פעולות הכתיבה לפעולות הקריאה

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

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

כדאי לשמור על מסמכים ועל פעולות כתיבה קטנים

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

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

שימוש ברכיבי listener יעילים

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

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

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

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

שאילתות סקרים מהירות

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

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

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

אם שאילתות הסקרים שלכם מהירות מספיק, מצב הסקרים הופך לשקוף למשתמשים באפליקציה.

העדפה של פונקציות listener לטווח ארוך

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

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

המאמרים הבאים