כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions

שלום, הבר! אני ארטם קרמישב, ראש צוות ניהול המערכת Mail.Ru Cloud Solutions (MCS). היו לנו השקות רבות של מוצרים חדשים במהלך השנה האחרונה. רצינו להבטיח ששירותי API יהיו ניתנים להרחבה בקלות, עמידים בפני תקלות ומוכנים לצמיחה מהירה בעומס המשתמש. הפלטפורמה שלנו מיושמת ב-OpenStack, ואני רוצה לספר לכם אילו בעיות סובלנות תקלות של רכיבים היינו צריכים לפתור כדי לקבל מערכת סובלנית לתקלות. אני חושב שזה יהיה מעניין למי שגם מפתח מוצרים ב-OpenStack.

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

גרסת וידאו של הסיפור הזה, שהמקור העיקרי שלו היה דיווח בכנס Uptime day 4, שאורגן על ידי ITSumma, אתה יכול לראות בערוץ Uptime Community.

חוסן של הארכיטקטורה הפיזית

החלק הציבורי של ענן MCS מבוסס כעת בשני מרכזי נתונים Tier III, ביניהם יש סיב כהה משלו, השמור ברמה הפיזית במסלולים שונים, עם תפוקה של 200 Gbit/s. שכבה III מספקת את הרמה הדרושה של סובלנות תקלות עבור התשתית הפיזית.

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

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

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

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

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
חוסן של תשתית פיזית

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

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

ExaBGP הוא שירות המיישם מספר פונקציות באמצעות פרוטוקול הניתוב הדינמי מבוסס BGP. אנו משתמשים בו באופן פעיל כדי לפרסם את כתובות ה-IP שלנו ברשימת ההיתרים שדרכן משתמשים ניגשים ל-API.

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

יישום API — אפליקציית אינטרנט הכתובה ב-python, שבעזרתה המשתמש מנהל את התשתית שלו ואת השירות שלו.

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

ארכיטקטורת יישומי OpenStack סטנדרטית

רוב השירותים שפותחו עבור OpenStack מנסים לפעול לפי פרדיגמה אחת. שירות מורכב בדרך כלל מ-2 חלקים: API ו-workers (מנהלי backend). ככלל, API הוא יישום WSGI ב-python, אשר מושק כתהליך עצמאי (דימון), או באמצעות שרת אינטרנט מוכן של Nginx או Apache. ה-API מעבד את בקשת המשתמש ומעביר הוראות נוספות ליישום העובד לביצוע. ההעברה מתרחשת באמצעות מתווך הודעות, בדרך כלל RabbitMQ, האחרים נתמכים בצורה גרועה. כאשר ההודעות מגיעות למתווך, הן מעובדות על ידי העובדים ובמידת הצורך מחזירות תגובה.

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

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

שירותים מסוימים דורשים תיאום בתוך השירות כאשר פעולות רציפות מורכבות מתרחשות בין ממשקי API ועובדים. במקרה זה, נעשה שימוש במרכז תיאום יחיד, מערכת אשכולות כגון Redis, Memcache, וכו', המאפשרת לעובד אחד לומר לאחר שהמשימה הזו מוטלת עליו ("נא לא לקחת אותה"). אנו משתמשים ב- etcd. ככלל, עובדים מתקשרים באופן פעיל עם מסד הנתונים, כותבים וקוראים מידע משם. אנו משתמשים ב-mariadb כמסד נתונים, אשר ממוקם באשכול רב מאסטר.

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

נקודת התורפה בכל התוכנית היא RabbitMQ ו-MariaDB. הארכיטקטורה שלהם ראויה למאמר נפרד במאמר זה אני רוצה להתמקד בסובלנות לתקלות API.

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
ארכיטקטורת יישומי Openstack. איזון וסובלנות תקלות של פלטפורמת הענן

הפיכת האיזון HAProxy לסובלני תקלות באמצעות ExaBGP

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

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

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

סכימת ExaBGP+HAProxy

  1. אנו מתקינים את התוכנה הדרושה, ExaBGP ו-HAProxy, בשלושה שרתים.
  2. אנו יוצרים ממשק loopback בכל שרת.
  3. בכל שלושת השרתים אנו מקצים את אותה כתובת IP לבנה לממשק הזה.
  4. כתובת IP לבנה מפורסמת באינטרנט באמצעות ExaBGP.

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

במקרה של בעיות בתפעול HAProxy או כשל בשרת, ExaBGP מפסיקה להכריז על המסלול, והתעבורה עוברת בצורה חלקה לשרת אחר.

כך, השגנו סובלנות תקלות של המאזן.

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
סבילות לתקלות של מאזני HAProxy

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

איזון מבוסס על DNS פלוס BGP

הנושא של איזון עומסים עבור HAProxy שלנו נותרה בלתי פתורה. עם זאת, ניתן לפתור את זה בפשטות, כפי שעשינו כאן.

כדי לאזן שלושה שרתים תזדקק ל-3 כתובות IP לבנות ו-DNS ישן וטוב. כל אחת מהכתובות הללו נקבעת על ממשק ה-loopback של כל HAProxy ומפורסמת באינטרנט.

ב-OpenStack, לניהול משאבים, נעשה שימוש בספריית שירות, המציינת את ה-API של נקודת הקצה של שירות מסוים. בספרייה זו אנו רושמים שם תחום - public.infra.mail.ru, אשר נפתר באמצעות DNS על ידי שלוש כתובות IP שונות. כתוצאה מכך, אנו מקבלים חלוקת עומס בין שלוש כתובות באמצעות DNS.

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

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

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

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
איזון HAProxy על בסיס DNS + BGP

אינטראקציה בין ExaBGP ל-HAProxy

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

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

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

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
בדיקת בריאות HAProxy

HAProxy Peers: סנכרון הפעלות

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

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

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

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

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

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

ב-IaaS יש לנו שירות שנבנה באמצעות אותה טכנולוגיה. זֶה Load Balancer כשירות עבור OpenStack, אשר נקרא אוקטביה. הוא מבוסס על שני תהליכי HAProxy וכולל בתחילה תמיכה בעמיתים. הם הוכיחו את עצמם מצוינים בשירות הזה.

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

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
HAProxy Peers (סנכרון הפעלה)

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

הגבלת מספר הבקשות בו-זמנית מאותו לקוח

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

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

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

איך זה נראה בפועל? יש לנו לקוחות שמשתמשים בממשקי ה-API שלנו לקנה מידה אוטומטי כל הזמן. הם יוצרים כמאתיים עד שלוש מאות מכונות וירטואליות בבוקר ומוחקים אותן בערב. עבור OpenStack, יצירת מכונה וירטואלית, גם עם שירותי PaaS, דורשת לפחות 1000 בקשות API, שכן אינטראקציה בין שירותים מתרחשת גם דרך ה-API.

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

כיצד לעדכן את בסיס הקוד שלך מבלי שהמשתמשים ישימו לב

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

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

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

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

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

  1. המפתח מרכיב חבילת קוד חדשה (עבורנו זה RPM), בודק אותו בסביבת ה-dev, בודק אותו בשלב ומשאיר אותו במאגר השלבים.
  2. המפתח מגדיר את המשימה לפריסה עם התיאור המפורט ביותר של "החפצים": גרסת החבילה החדשה, תיאור הפונקציונליות החדשה ופרטים נוספים על הפריסה במידת הצורך.
  3. מנהל המערכת מתחיל בעדכון. משיק את ספר המשחקים של Ansible, אשר בתורו עושה את הפעולות הבאות:
    • לוקח חבילה ממאגר השלב ומשתמש בה כדי לעדכן את גרסת החבילה במאגר המוצרים.
    • מרכיב רשימה של חלקים אחוריים של השירות המעודכן.
    • מכבה את השירות הראשון שיעודכן ב-HAProxy וממתין לסיום התהליכים שלו. הודות לכיבוי חינני, אנו בטוחים שכל בקשות הלקוח הנוכחיות יסתיימו בהצלחה.
    • לאחר הפסקת ה-API והעובדים לחלוטין, וה-HAProxy כבוי, הקוד מתעדכן.
    • Ansible מפעילה שירותים.
    • עבור כל שירות, נשלפות "ידיות" מסוימות, המבצעות בדיקות יחידה במספר בדיקות מפתח מוגדרות מראש. מתבצעת בדיקה בסיסית של הקוד החדש.
    • אם לא נמצאו שגיאות בשלב הקודם, הקצה האחורי מופעל.
    • בואו נעבור לחלק האחורי הבא.
  4. לאחר עדכון כל ה-backends, בדיקות פונקציונליות מופעלות. אם הם חסרים, המפתח בוחן כל פונקציונליות חדשה שהוא יצר.

זה משלים את הפריסה.

כיצד מיושמת ארכיטקטורת אינטרנט סובלנית לתקלות בפלטפורמת Mail.ru Cloud Solutions
מחזור עדכון שירות

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

מסקנה

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

  • סובלנות פיזית לתקלות;
  • סובלנות תקלות ברשת (איזונים, BGP);
  • סובלנות תקלות של התוכנה המשמשת ומפותחת.

זמן פעולה יציב לכולם!

מקור: www.habr.com

הוספת תגובה