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

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

מבוא

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

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

קריטריונים של תנאי מוקדם

‫Cloud Storage תומך בשימוש במספר מאפייני משאבים שאינם ניתנים לשינוי בתנאים המוקדמים:

בטבלה הבאה מפורטים התנאים המוקדמים הנתמכים על ידי API בפורמט JSON ו-API בפורמט XML:

‫API בפורמט JSON ‫API בפורמט XML תיאור
פרמטר של שאילתת ifGenerationMatch כותרת x-goog-if-generation-match הבקשה תמשיך אם ה-generation של משאב היעד תואם לערך שנעשה בו שימוש בתנאי המוקדם. אם הערכים לא תואמים, הבקשה תיכשל עם תשובת 412 Precondition Failed.
פרמטר של שאילתת ifMetagenerationMatch כותרת x-goog-if-metageneration-match הבקשה תמשיך אם ה-metageneration של משאב היעד תואם לערך שנעשה בו שימוש בתנאי המוקדם. אם הערכים לא תואמים, הבקשה תיכשל עם תשובת 412 Precondition Failed.
פרמטר של שאילתת ifGenerationNotMatch לא רלוונטי הבקשה תמשיך אם ה-generation של משאב היעד לא תואם לערך שנעשה בו שימוש בתנאי המוקדם. אם הערכים תואמים, הבקשה תיכשל עם תשובת 304 Not Modified.
פרמטר של שאילתת ifMetagenerationNotMatch לא רלוונטי הבקשה תמשיך אם ה-metageneration של משאב היעד לא תואם לערך שנעשה בו שימוש בתנאי המוקדם. אם הערכים תואמים, הבקשה תיכשל עם תשובת 304 Not Modified.
כותרת If-Match כותרת If-Match רלוונטי לבקשות המאחזרות נתונים. הבקשה תמשיך אם ה-ETag של משאב היעד תואם לערך שנעשה בו שימוש בתנאי המוקדם. אם הערכים לא תואמים, הבקשה תיכשל עם תשובת 412 Precondition Failed.
כותרת If-None-Match כותרת If-None-Match רלוונטי לבקשות המאחזרות נתונים. הבקשה תמשיך אם ה-ETag של משאב היעד לא תואם לערך שנעשה בו שימוש בתנאי המוקדם. אם הערכים תואמים, הבקשה תיכשל עם תשובת 304 Not Modified.
לא רלוונטי כותרת If-Modified-Since הבקשה תמשיך אם למשאב היעד יש תאריך Last-Modified אחרי הערך שנעשה בו שימוש בתנאי המוקדם. אם משאב היעד לא עומד בתנאי המוקדם הזה, הבקשה תיכשל עם תשובת 304 Not Modified.
לא רלוונטי כותרת If-Unmodified-Since הבקשה תמשיך אם למשאב היעד יש תאריך Last-Modified מוקדם יותר או שווה לערך שנעשה בו שימוש בתנאי המוקדם. אם משאב היעד לא עומד בתנאי המוקדם הזה, הבקשה תיכשל עם תשובת 412 Precondition Failed.

תנאים מוקדמים ליצירת אובייקט מורכב

כשיוצרים אובייקט מורכב, גם API בפורמט JSON וגם API בפורמט XML תומכים בדברים הבאים:

  • התנאים המוקדמים של התאמה לגנרציה והתאמה למטא-גנרציה של אובייקט היעד.

  • התנאי המוקדם של התאמה לגנרציה של כל אובייקט מקור. השימוש בתנאי המוקדם הזה מונע שימוש ברכיבים שגויים במקרה שבו תהליך בלתי-תלוי מחליף את אחד מהרכיבים המיועדים של האובייקט המורכב שיוצרים. אם משתמשים בתנאים מוקדמים והחלפה כזו מתרחשת, הפעולות של compose נכשלות עם תשובת 412 Precondition Failed.

תנאים מוקדמים להעתקת אובייקט

כשמעתיקים או משכתבים אובייקט ב-Cloud Storage, גם ב-API בפורמט JSON וגם ב-API בפורמט XML יש תמיכה בתנאים מוקדמים סטנדרטיים בשביל אובייקט היעד. לכל API יש תמיכה נוספת בתנאי מוקדם בשביל אובייקטי מקור:

  • ב-API בפורמט JSON יש תמיכה בתנאים מוקדמים לגנרציה ולמטא-גנרציה של אובייקט המקור, המוגדרים באמצעות פרמטרים של שאילתות שהקידומת שלהן היא ifSource.

  • אפשר להשתמש בכל התנאים המוקדמים הנתמכים על-ידי API בפורמט XML בשביל אובייקט המקור. התנאים המוקדמים האלו מוגדרים בכותרות עם הקידומת x-goog-copy-source-.

הערך 0 בתנאי מוקדם של התאמה לגנרציה

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

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

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

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

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

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

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

  • אי אפשר להשתמש בתנאים המוקדמים בהעלאות מרובות חלקים ב-API בפורמט XML. ניסיון לעשות זאת יגרום להצגה של שגיאת 400 NotImplemented.

העלות של תנאים מוקדמים

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

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

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

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

דוגמה: שימוש בתנאי מוקדם

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

שורת הפקודה

gcloud

משתמשים בדגל --if-generation-match יחד עם הפקודה הרגילה:

gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME/ --if-generation-match=GENERATION

כאשר:

  • GENERATION הוא מספר הגנרציה המיועד של האובייקט שמחליפים. לדוגמה, 1122334455667788.

  • OBJECT_LOCATION הוא הנתיב המקומי לאובייקט. לדוגמה, Desktop/dog.png.

  • DESTINATION_BUCKET_NAME הוא שם הקטגוריה שאליה מעלים את האובייקט. לדוגמה, my-bucket.

gsutil

משתמשים בדגל -h יחד עם הפקודה הרגילה:

gsutil -h x-goog-if-generation-match:GENERATION cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME/

כאשר:

  • GENERATION הוא מספר הגנרציה המיועד של האובייקט שמחליפים. לדוגמה, 1122334455667788.

  • OBJECT_LOCATION הוא הנתיב המקומי לאובייקט. לדוגמה, Desktop/dog.png.

  • DESTINATION_BUCKET_NAME הוא שם הקטגוריה שאליה מעלים את האובייקט. לדוגמה, my-bucket.

‫API בפורמט JSON

  1. מקבלים אסימון גישה להרשאה מ-OAuth 2.0 Playground. מגדירים את ה-Playground לשימוש בפרטי הכניסה שלכם ב-OAuth. הוראות מפורטות מופיעות במאמר אימות API.
  2. משתמשים ב-cURL כדי לשלוח קריאה ל-API בפורמט JSON באמצעות בקשת אובייקט POST:

    curl -X POST --data-binary @OBJECT_LOCATION \
      -H "Authorization: Bearer OAUTH2_TOKEN" \
      -H "Content-Type: OBJECT_CONTENT_TYPE" \
      "https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o?uploadType=media&name=OBJECT_NAME"&ifGenerationMatch=GENERATION"

    כאשר:

    • OBJECT_LOCATION הוא הנתיב המקומי לאובייקט. לדוגמה, Desktop/dog.png.
    • OAUTH2_TOKEN הוא אסימון הגישה שיצרתם בשלב 1.
    • OBJECT_CONTENT_TYPE הוא סוג התוכן של האובייקט. לדוגמה, image/png.
    • BUCKET_NAME הוא שם הקטגוריה שאליה מעלים את האובייקט. לדוגמה, my-bucket.
    • OBJECT_NAME הוא השם שרוצים לתת לאובייקט. לדוגמה, dog.png.
    • GENERATION הוא מספר הגנרציה המיועד של האובייקט שמחליפים. לדוגמה, 1122334455667788.

‫API בפורמט XML

  1. מקבלים אסימון גישה להרשאה מ-OAuth 2.0 Playground. מגדירים את ה-Playground לשימוש בפרטי הכניסה שלכם ב-OAuth. הוראות מפורטות מופיעות במאמר אימות API.
  2. משתמשים ב-cURL כדי לשלוח קריאה ל-API בפורמט XML באמצעות בקשת אובייקט PUT:

    curl -X PUT --data-binary @OBJECT_LOCATION \
      -H "Authorization: Bearer OAUTH2_TOKEN" \
      -H "Content-Type: OBJECT_CONTENT_TYPE" \
      -H "x-goog-if-generation-match: GENERATION" \
      "https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME"

    כאשר:

    • OBJECT_LOCATION הוא הנתיב המקומי לאובייקט. לדוגמה, Desktop/dog.png.
    • OAUTH2_TOKEN הוא אסימון הגישה שיצרתם בשלב 1.
    • OBJECT_CONTENT_TYPE הוא סוג התוכן של האובייקט. לדוגמה, image/png.
    • GENERATION הוא מספר הגנרציה המיועד של האובייקט שמחליפים. לדוגמה, 1122334455667788.
    • BUCKET_NAME הוא שם הקטגוריה שאליה מעלים את האובייקט. לדוגמה, my-bucket.
    • OBJECT_NAME הוא השם שרוצים לתת לאובייקט. לדוגמה, dog.png.

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

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

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

‫Cloud Storage היא מערכת מבוזרת. בגלל שבקשות עלולות להיכשל בגלל התנאים של הרשת או השירות, Google ממליצה לנסות שוב בקשות שנכשלו באמצעות השהיה מעריכית לפני ניסיון חוזר (exponential backoff). עם זאת, בשל אופי מערכות מבוזרות, לפעמים ניסיונות חוזרים אלו עלולים לגרום להתנהגות מפתיעה.

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

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

מרוץ תהליכים מתחיל אם הנתב שאיבד את הקישוריות מחדש אותה, ולאחר מכן שולח את בקשת המחיקה המקורית, שאבדה לכאורה, הלאה ל-Cloud Storage. כשמתקבלת הבקשה ל-Cloud Storage, היא מצליחה כי יש file.txt חדש. Cloud Storage שולח תשובה שלא מגיעה כי הלקוח הפסיק להקשיב לה. לא רק שהקובץ החדש יימחק, בניגוד לכוונות, אלא גם לא תהיו מודעים לכך שהמחיקה השנייה התרחשה.

בתרשים הבא מוצג מה שקרה:

מניעת מרוץ התהליכים

כדי למנוע מצב כזה, כדאי להתחיל בקבלת המטא-נתונים של file.txt כדי לזהות את הגנרציה הנוכחית. לאחר מכן משתמשים בגנרציה בתנאי המוקדם של התאמה לגנרציה שכוללים כחלק מבקשת המחיקה. התנאי המוקדם מבטיח שרק האובייקט עם מספר הגנרציה הספציפי יימחק, לא משנה מתי בקשת המחיקה מגיעה ל-Cloud Storage או כמה פעמים בקשת המחיקה עם התנאי המוקדם נשלחת. כל ניסיון לא מכוון למחוק גרסה אחרת של file.txt ייכשל עם קוד התגובה 412 Precondition Failed.

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

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

שיוך מטא-נתונים של אובייקט

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

כדאי להביא בחשבון את המקרים הבאים:

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

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

מניעת מרוץ התהליכים

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

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

עדכניות של עותק מקומי

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

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

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

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

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