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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ארכיטקטורה של חיבור מאזין לתמונת מצב

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

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

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

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

יישום שיטות מומלצות להרחבת שאילתות בזמן אמת

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

הסבר על נפח גבוה של תנועת כתיבה במערכת

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

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

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

התאמה אוטומטית לעומס מאפשרת להגדיל את תעבורת הכתיבה ללא הגבלות, אבל ככל שהתעבורה גדלה, יכול להיות שיעבור זמן עד שהמערכת תגיב. כדי להימנע מיצירת נקודה חמה לכתיבה, מומלץ לפעול לפי ההמלצות של כלל 5-5-5. ‫Key Visualizer הוא כלי שימושי לניתוח נקודות חמות של כתיבה.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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