מבוא
כשקוראים נתונים ב-Spanner בטרנזקציה לקריאה בלבד או בקריאה יחידה, אפשר להגדיר גבול של חותמת זמן, שמציין ל-Spanner איך לבחור חותמת זמן לקריאת הנתונים.
למה כדאי להגדיר חותמת זמן? אם מסד הנתונים שלכם מבוזר גיאוגרפית (כלומר, יצרתם את מופע Spanner באמצעות הגדרת מופע במספר אזורים), והאפליקציה שלכם יכולה לסבול מידת מה של נתונים לא עדכניים כשקוראים נתונים, תוכלו להפיק תועלת מביצוע קריאה בעבר במקום קריאה של נתונים עדכניים. (מידע נוסף על סוגי הקריאה האלה זמין במאמר בנושא קריאות).
סוגים של חותמות זמן
סוגי חותמות הזמן הם:
- חזק (ברירת המחדל): קריאת הנתונים העדכניים.
- השהיית נתונים מוגבלת: קריאת גרסה של הנתונים שלא עברה את ההשהיה המוגבלת.
- התיישנות מדויקת: קריאת גרסת הנתונים בחותמת זמן מדויקת, למשל, נקודת זמן בעבר, אם כי אפשר לציין חותמת זמן של זמן שעוד לא חלף. (אם מציינים חותמת זמן עתידית, Spanner ימתין עד לחותמת הזמן הזו לפני שיציג את הקריאה).
הערות:
למרות שפעולות קריאה באמצעות מצבים מוגבלים בזמן לא נכללות בעסקת קריאה-כתיבה, הן יכולות לחסום את ההמתנה לעסקאות קריאה-כתיבה מקבילות עד שהן יאושרו. קריאות של נתונים לא עדכניים עם חסם מנסות לבחור חותמת זמן כדי להימנע מחסימה, אבל עדיין יכולות לחסום.
קריאות לא עדכניות (כלומר, שימוש בסוגי אי-עדכניות מוגבלת או מדויקת) מספקות את היתרון המקסימלי בביצועים במרווחי אי-עדכניות ארוכים ביותר. כדי ליהנות מהיתרון הזה, צריך להשתמש בערך מינימלי של 10 שניות לציון משך הזמן שעבר מאז שהנתונים נשמרו.
ב-Spanner מתבצע מעקב אחרי
earliest_version_timeשל מסד נתונים, שמציין את הזמן המוקדם ביותר שבו אפשר לקרוא גרסאות קודמות של נתונים. אי אפשר לקרוא בחותמת זמן שלפני השעה של הגרסה המוקדמת ביותר.
בהמשך מוסבר בפירוט על סוגי הגבולות של חותמות הזמן ב-Spanner.
חזק
Spanner מספק סוג מאוגד לקריאות חזקות. קריאות חזקות מבטיחות לראות את ההשפעות של כל העסקאות שאושרו לפני תחילת הקריאה. בנוסף, כל השורות שמתקבלות מקריאה יחידה עקביות זו עם זו – אם חלק כלשהו מהקריאה מתייחס לעסקה, כל החלקים של הקריאה רואים את העסקה.
קריאות חזקות לא ניתנות לחזרה: שתי טרנזקציות רצופות של קריאה בלבד עשויות להחזיר תוצאות לא עקביות אם מתבצעות פעולות כתיבה בו-זמנית. אם נדרשת עקביות בין הקריאות, צריך לבצע את הקריאות באותה טרנזקציה או בחותמת זמן מדויקת של קריאה.
Bounded staleness
Spanner מספק סוג מאוגד ל-bounded staleness. מצבי חוסר עדכניות מוגבלים מאפשרים ל-Spanner לבחור את חותמת הזמן של הקריאה, בכפוף למגבלת חוסר עדכניות שהמשתמש מספק. Spanner בוחר את חותמת הזמן החדשה ביותר בתוך הגבול של מידת העדכניות, שמאפשרת לבצע את פעולות הקריאה ברפליקה הזמינה הקרובה ביותר בלי חסימה.
כל השורות שמוחזרות עקביות זו עם זו – אם חלק כלשהו מהקריאה מתייחס לעסקה, כל החלקים של הקריאה מתייחסים לעסקה. קריאות עם חוסר עדכניות מוגבל לא ניתנות לחזרה: שתי קריאות עם חוסר עדכניות, גם אם הן משתמשות באותו סף חוסר עדכניות, יכולות להתבצע בחותמות זמן שונות וכך להחזיר תוצאות לא עקביות.
קריאות עם חוסר עדכניות מוגבל הן בדרך כלל קצת יותר איטיות מקריאות עם חוסר עדכניות מדויק.
השהייה המדויקת
Spanner מספק סוג bound לציון רמת עדכניות מדויקת. הגבולות של חותמות הזמן האלה מבצעים קריאות בחותמת זמן שצוינה על ידי המשתמש. קריאות בנקודת זמן מסוימת מובטחות לראות קידומת עקבית של היסטוריית העסקאות הגלובלית: הן יראו שינויים שבוצעו על ידי כל העסקאות עם חותמת זמן של אישור עסקה שקטנה או שווה לחותמת הזמן של הקריאה, ולא יראו שינויים שבוצעו על ידי עסקאות עם חותמת זמן גדולה יותר של אישור עסקה. הם ייחסמו עד שכל העסקאות המתנגשות שאולי יוקצו להן חותמות זמן של ביצוע (commit) שקטנות או שוות לחותמת הזמן של הקריאה יסתיימו.
חותמת הזמן יכולה להיות מבוטאת כחותמת זמן מוחלטת של ביצוע Commit ב-Spanner או כמידת העדכניות ביחס לזמן הנוכחי.
במצבים האלה לא נדרש 'שלב משא ומתן' כדי לבחור חותמת זמן. כתוצאה מכך, הם פועלים קצת יותר מהר ממצבי בו-זמניות שווי ערך עם חוסר עדכניות מוגבל. מצד שני, קריאות עם חוסר עדכניות מוגבל בדרך כלל מחזירות תוצאות עדכניות יותר.
הזמן המקסימלי שחלף מאז חותמת הזמן
מערכת Spanner מבצעת כל הזמן איסוף של נתונים שנמחקו או שנכתבו מחדש ברקע, כדי לפנות מקום באחסון. התהליך הזה נקרא version GC. תהליך איסוף הגרסאות (GC) אוסף גרסאות אחרי שהן פגות, בהתאם לversion_retention_period של מסד הנתונים. ברירת המחדל היא שעה אחת, אבל אפשר להגדיר עד שבוע. ההגבלה הזו חלה גם על קריאות בתהליך או על שאילתות SQL שהחותמת שלהן ישנה מדי בזמן ההפעלה. קריאות ושאילתות SQL עם חותמות זמן קריאה ישנות מדי נכשלות עם השגיאה FAILED_PRECONDITION. היוצא מן הכלל היחיד הוא Partition Read/Query עם אסימוני מחיצה, שימנעו garbage collection של נתונים שפג תוקפם בזמן שהסשן פעיל.