בקרת בו-זמניות אופטימית (OCC) היא אסטרטגיה לניהול משאבים משותפים ולמניעת אובדן עדכונים או מרוצי תהליכים, כשכמה משתמשים או תהליכים משנים את אותו משאב בו-זמנית.
לדוגמה, כשעובדים עם ניהול זהויות והרשאות גישה (IAM), מדיניות IAM היא משאב משותף שמצורף למשאב כמו פרויקט, קטגוריה או שירות. בלי בקרת בו-זמניות, שינויים שמתבצעים בו-זמנית יכולים להחליף שינויים שבוצעו לאחרונה במדיניות, וכך לבטל בטעות גישה לגיטימית או להעניק הרשאות לא מורשות.
כדי להטמיע OCC, מערכות בדרך כלל משתמשות במספר גרסה או בשדה etag (תג ישות) במבנה המשאב.
איך פועלת אופטימיזציית המרות אונליין (OCC)
נניח ששני תהליכים, א' וב', מנסים לעדכן משאב משותף בו-זמנית:
- תהליך א' קורא את המצב הנוכחי של המשאב.
- תהליך ב' קורא את אותו מצב נוכחי.
- תהליך א' משנה את העותק שלו וכותב אותו בחזרה לשרת.
- תהליך ב' משנה את העותק שלו וכותב אותו בחזרה לשרת.
מכיוון שתהליך ב' מחליף את המשאב בלי לדעת שתהליך א' כבר שינה אותו, העדכונים של תהליך א' אובדים.
כדי לפתור את הבעיה הזו, ב-OCC משתמשים בטביעת אצבע ייחודית שמשתנה בכל פעם שמשנים ישות. במערכות רבות, כמו IAM, טביעת האצבע הזו היא etag. השרת בודק את התג הזה בכל כתיבה:
- כשקוראים את המשאב, השרת מחזיר
etag(טביעת אצבע ייחודית). - כששולחים בחזרה את המשאב ששונה, צריך לכלול את ה-
etagהמקורי. - אם הערך של
etagששמור לא תואם לערך שלetagששלחתם, כלומר תהליך אחר שינה את המשאב אחרי שקראתם אותו, פעולת הכתיבה תיכשל ותופיע השגיאהABORTEDאוFAILED_PRECONDITION.
השגיאה הזו מאותתת ללקוח לנסות שוב את כל התהליך: לקרוא מחדש את המצב המעודכן, להחיל מחדש את השינויים ולנסות שוב את הכתיבה עם ה-etag החדש.
הטמעת לולאת ה-OCC
הליבה של הטמעת OCC היא לולאת ניסיון חוזר שקוראת, משנה ומנסה לשמור את המשאב, ויוצאת אחרי כתיבה מוצלחת. כדי למנוע לולאות אינסופיות בזמן תחרות גבוהה, הגדירו מספר מקסימלי סביר של ניסיונות חוזרים.
שלבי הלולאה
בטבלה הבאה מתואר כל שלב בלולאת הניסיונות החוזרים של OCC:
| שלב | פעולה | דוגמה של הטמעה |
|---|---|---|
| קריאה | מאחזרים את מצב המשאב הנוכחי, כולל ה-etag. |
let mut policy = client .get_iam_policy() .set_resource(&secret_name) .send() .await?; |
| שינוי | מחילים את השינויים על ה-struct המקומי. | policy.bindings.push(new_binding); |
| כתיבה ובדיקה | מנסים לשמור את המשאב ששונה באמצעות ה-etag הקיים, ובודקים אם יש קודי שגיאה של בו-זמניות. |
match client .set_iam_policy() .set_resource(&secret_name) .set_policy(policy) .send() .await { Ok(p) => return Ok(p), Err(e) => { /* ... */ } } |
| הצלחה או ניסיון חוזר | אם הכתיבה מצליחה, יוצאים מהלולאה. אם הפעולה נכשלת עם שגיאת בו-זמניות, מגדילים את מונה הניסיונות החוזרים וממשיכים את הלולאה מהשלב Read. | - |
דוגמה
בדוגמה הבאה מוסבר איך להטמיע לולאת OCC שמעדכנת מדיניות IAM במשאב סודי של Secret Manager, על ידי הקצאת התפקיד roles/secretmanager.secretAccessor לחבר.
כדי להריץ את הדוגמה הזו, קודם צריך להצהיר על התלות בקובץ Cargo.toml:
cargo add google-cloud-secretmanager-v1
לאחר מכן, מטמיעים את לולאת הניסיון החוזר של OCC:
השלמת הקוד
הקוד הבא מציג את הפונקציה המלאה עם כל הייבואים הנדרשים: