מדריך לעסקאות במיקרו-שירותים

1. הקדמה

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

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

2. הימנעות מעסקאות במיקרו-שירותים

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

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

2.1. דוגמה לאדריכלות הדורשת עסקאות

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

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

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

ה מִשׁתַמֵשׁ שירות המיקרו יעסוק בפרופיל המשתמש (יצירת משתמש חדש, עריכת נתוני פרופיל וכו ') עם סוג הדומיין הבא:

מחלקה ציבורית @Entity מיישמת את המשתמש {@Id @GeneratedValue (אסטרטגיה = GenerationType.AUTO) מזהה פרטי פרטי; @ בסיס פרטי פרטי מחרוזת; שם משפחה פרטי מחרוזת בסיסי; @ Basic פרטי מיידי @ LastMessageTime; }

ה הוֹדָעָה שירותי מיקרוסופט יעסקו בשידור. זה מקיף את הישות הוֹדָעָה וכל מה שמסביב:

@Entity class class הודעה מיישמת באמצעות Serializable {@Id @GeneratedValue (אסטרטגיה = GenerationType.AUTO) מזהה ארוך פרטי; @ Basic פרטי משתמש ארוך מזהה; תוכן מחרוזת פרטי בסיסי @; @ Basic פרטי הודעה מיידית Timestamp; }

לכל מיקרו-שירות מסד נתונים משלו. שימו לב שאנחנו לא מתייחסים לישות מִשׁתַמֵשׁ מהישות הוֹדָעָה, מכיוון ששיעורי המשתמש אינם נגישים מה- הוֹדָעָה שירות מיקרו. אנו מתייחסים למשתמש רק לפי מזהה.

עכשיו ה מִשׁתַמֵשׁ הישות מכילה את lastMessageTime שדה מכיוון שאנחנו רוצים להציג את המידע אודות זמן פעילות המשתמש האחרונה בפרופיל שלה.

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

2.2. גישה חלופית ללא עסקאות

אנו יכולים לשנות את ארכיטקטורת המיקרו-שירות שלנו ולהסיר את השדה lastMessageTime מ ה מִשׁתַמֵשׁ יֵשׁוּת.

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

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

אבל זה יכול להיות מקובל יותר מאשר אי ביצוע עסקה מבוזרת כדי לשמור הודעה רק בגלל שהמיקרו-שירות של המשתמש לא הגיב בזמן.

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

3. פרוטוקול התחייבות דו-שלבי

פרוטוקול התחייבות דו-פאזי (או 2PC) הוא מנגנון ליישום עסקה על פני רכיבי תוכנה שונים (מסדי נתונים מרובים, תורי הודעות וכו ').

3.1. האדריכלות של 2PC

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

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

הבעיה עם 2PC היא שהיא די איטית בהשוואה לזמן הפעולה של שירות מיקרו יחיד.

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

3.2. תקן XA

תקן XA הוא מפרט לביצוע העסקאות המבוזרות של 2PC על פני המשאבים התומכים. כל שרת יישומים תואם JTA (JBoss, GlassFish וכו ') תומך בו מהקופסה.

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

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

3.3. טיוטת REST-AT רגילה

תקן מוצע נוסף הוא REST-AT שעבר פיתוח מסוים על ידי RedHat אך עדיין לא יצא משלב הטיוטה. עם זאת, הוא נתמך על ידי שרת היישומים WildFly מחוץ לקופסה.

תקן זה מאפשר שימוש בשרת היישומים כרכז עסקאות עם ממשק API ספציפי של REST ליצירה והצטרפות של העסקאות המבוזרות.

שירותי האינטרנט RESTful המעוניינים להשתתף בעסקה הדו-פאזית חייבים לתמוך בממשק API מסוים של REST.

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

4. עקביות ותמורה בסופו של דבר

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

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

4.1. מקרה של עקביות בסופו של דבר

לדוגמה, נניח שעלינו לפתור את המשימה הבאה:

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

המשימה השנייה היא להבטיח, למשל, שמשתמש זה לא נאסר מהשרתים שלנו משום מה.

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

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

  • ה מִשׁתַמֵשׁ מיקרו-שירות המוטל על רישום פרופיל משתמש
  • ה מַתַן תוֹקֵף microservice המוטל על ביצוע בדיקת רקע
  • פלטפורמת המסרים התומכת בתורים מתמשכים

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

4.2. תרחיש שמח

בארכיטקטורה זו, תרחיש משמח יהיה:

  • ה מִשׁתַמֵשׁ microservice רושמת משתמש ושומרת מידע אודותיה במאגר המידע המקומי שלה
  • ה מִשׁתַמֵשׁ microservice מסמן משתמש זה באמצעות דגל. זה יכול לסמן שמשתמש זה טרם אומת ואין לו גישה לפונקציונליות מלאה של המערכת
  • אישור על ההרשמה נשלח למשתמש עם אזהרה כי לא כל הפונקציונליות של המערכת נגישה מייד
  • ה מִשׁתַמֵשׁ שולח הודעה אל ה- מַתַן תוֹקֵף שירות מיקרו כדי לבצע בדיקת רקע של משתמש
  • ה מַתַן תוֹקֵף microservice מריץ את בדיקת הרקע ושולח הודעה אל מִשׁתַמֵשׁ שירות מיקרו עם תוצאות הבדיקה
    • אם התוצאות חיוביות, מִשׁתַמֵשׁ שירות מיקרו מבטל את חסימת המשתמש
    • אם התוצאות שליליות, מִשׁתַמֵשׁ microservice מוחק את חשבון המשתמש

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

השלב האחרון, כאשר המשתמש המיקרו-שירות מסיר את החשבון הלא חוקי, הוא שלב פיצויים.

4.3. תרחישים של כישלון

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

  • אם ה מַתַן תוֹקֵף שירות המיקרו אינו נגיש, ואז פלטפורמת ההודעות עם פונקציונליות התור המתמשכת שלה מבטיחה כי מַתַן תוֹקֵף microservice יקבל הודעה זו במועד מאוחר יותר
  • נניח שפלטפורמת המסרים נכשלת ואז ה- מִשׁתַמֵשׁ microservice מנסה לשלוח את ההודעה שוב בזמן מאוחר יותר, למשל, על ידי עיבוד אצווה מתוזמן של כל המשתמשים שעדיין לא אומתו
  • אם ה מַתַן תוֹקֵף שירות המיקרו - שירות מקבל את ההודעה, מאמת את המשתמש אך אינו יכול לשלוח את התשובה בחזרה בגלל כישלון פלטפורמת ההודעות מַתַן תוֹקֵף microservice מנסה שוב לשלוח את ההודעה במועד מאוחר יותר
  • אם אחת ההודעות הלכה לאיבוד, או שקרה כשל כלשהו אחר, מִשׁתַמֵשׁ microservice מוצא את כל המשתמשים שאינם מאומתים על ידי עיבוד אצווה מתוזמן ושולח בקשות לאימות שוב

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

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

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

5. מסקנה

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

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