הגדרת MaxScale: היכן נשבר מאגר החיבורים ל-MySQL
התמונה האופיינית נראית כך: היישום פותח חיבור עבור כל שאילתה וסוגר אותו מיד לאחר התשובה — בשיא מדובר במאות סשנים קצרים בשנייה. ה-backend נתקל ב-max_connections, תור ההמתנה בכניסה מתמלא, חלק מהשאילתות חוזרות עם דחייה, ומטפלי היישום מחזיקים תהליכים בהמתנה למקום שהתפנה.
מבחוץ זה נראה כמו "הבסיס נתקע", אף שצוואר הבקבוק אינו השאילתות אלא הדרך שבה הן מגיעות לשרת.
העלאת max_connections — דרך ללא מוצא. כל חיבור מקצה זיכרון למחסנית התהליך ולמאגרי המיון והחיבורים, ולכן המגבלה נתקלת בזיכרון לפני שהיא נתקלת במעבד, והחלפת ההקשר בין מאות תהליכים פעילים אוכלת את הרווח.
הבעיה היא גם שרוב החיבורים האלה עומדים בטלים בכל רגע נתון: היישום כבר פתח אותם, אבל שאילתה דרכם טרם יצאה.
MaxScale עומד בין היישום ל-MySQL כשכבת פרוקסי וממחזר חיבורי backend: בזמן בטלה סשני הלקוח חולקים את אותם החיבורים לשרת, במקום לתפוס חיבור משלהם.
הפרמטר max_connections בסעיף service קובע כמה חיבורים ל-backend הפרוקסי מחזיק בו-זמנית, ו-multiplex_timeout — כמה הוא ממתין לפני החזרת חיבור שהתפנה למאגר המשותף. הגדרת MaxScale מצטמצמת לכך שתורי החיבורים ייווצרו בכניסה לפרוקסי, במקום שבו אפשר למדוד אותם, ולא כדחיות בתוך הבסיס.
בנפרד אנו מסנכרנים את הזמנים: wait_timeout ו-back_log בשרת צריכים להיות לא קצרים מ-connection_timeout ו-multiplex_timeout בפרוקסי, אחרת MaxScale מחזיר חיבור שה-backend כבר סגר, והלקוח מקבל שגיאה על לא עוול בכפו. להלן נבחן כיצד מגדירים זאת.
מה נותן מאגר חיבורים מנוהל בפועל
מאגר חיבורים פועל כמאגר ביניים בין היישום לבסיס: השירותים מחזיקים קבוצה קטנה של ערוצים לפרוקסי, והפרוקסי עצמו — חיבורים שכבר הוקמו לצמתים. במקום שכל תהליך יפתח ערוץ משלו, התעבורה ממחזרת ערוצים מוכנים. בשירות טיפוסי מספר החיבורים בו-זמנית לבסיס יורד פי כמה בהיקף שאילתות זהה.
בשיא האפקט בולט ביותר. שאילתה חדשה מקבלת חיבור באופן מיידי, בלי תיאום ואימות מחדש, ולכן פרץ תעבורה אינו הופך לתור לחיבור. הבסיס רואה זרימה אחידה גם בשעות שקטות וגם בשיא — מדרגת מאות החיבורים בו-זמנית נעלמת.
סעיף נפרד הוא החלפת צמתי הבסיס. בעת כשל של רפליקה או תחזוקה מתוכננת, הפרוקסי עצמו מפנה טרנזקציות חדשות לצומת חי, והיישום ממשיך לעבוד עם אותה כתובת. אין צורך בשינויים בקונפיגורציות השירותים ובהפעלה מחדש.
מכאן נעלם סוג שלם של כשלים: שגיאות חריגה ממגבלת החיבורים, פרצי השהיה בעת חיבור מחדש המוני, וניתוקים בזמן החלפת צמתים ידנית. כדאי לבדוק את התוצאה לפי שלושה מספרים — כמה חיבורים הבסיס רואה בשיא, כמה נמשכת ההחלפה, וכמה שגיאות חיבור נותרו במשך יממה. MaxScale מכסה את כל הנקודות האלה ברמת הפרוקסי, בלי שינויים בקוד היישומים.
אפשרויות איזון ומצבי ניתוב שאילתות
ניתוב ואיזון פותרים משימות שונות: הראשון קובע לאן תפנה שאילתה מסוימת, והשני מפזר עומס בין הצמתים. ב-MaxScale עושים זאת מודולים: readwritesplit מנתח את סוג השאילתה ומפנה קריאה מהרפליקות, readconnroute מחלק חיבורים בשלמותם, ו-hintrouter מאפשר ליישום לקבוע יעד ישירות בהערה לשאילתה.
בחירת המצב קובעת את התנהגות הטרנזקציות, הטבלאות הזמניות, וקריאת רשומות עצמיות לאחר כתיבה. בנפרד נקבע היכן להחזיק את מאגר החיבורים — בפרוקסי, בדרייבר, או בלי מאגר כלל.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| מאגר חיבורים חיצוני בפרוקסי | יישומים הטרוגניים, חיבורים קצרים רבים | מעבר רשת נוסף; לבדוק תאימות לביטויים מוכנים מראש |
| מאגר בדרייבר היישום | יישום אחד, עומס יציב, חשובה השהיה מינימלית | המגבלות נספרות לפי תהליך, אין חלוקה מחדש משותפת |
| פרוקסי ברמת היישום | נדרשים כללי ניתוב משלך | תמיכה ובדיקות משלך, פיגור אחרי שינויים ב-DBMS |
| חיבור ישיר לרפליקות | מעט צמתים, אין דרישות נוקשות לרעננות הנתונים | פיגור הרפליקות והחלפה בעת כשל — בצד הקוד |
בפועל משלבים מצבים: כתיבה הולכת למאסטר, שאילתות דיווח — לרפליקות, ושאילתות הרגישות לרעננות הנתונים מפנות למאסטר בציון מפורש. לפני ההפעלה אנו מריצים תרחישים עם החלפת סכימה בסשן, משתני סשן וביטול טרנזקציות — בהם איזון שקוף נשבר לרוב.
שלבי הגדרת MaxScale: מביקורת עומס ועד מסירה
העבודה מתנהלת לצד סביבת הייצור, ולכן הסדר כאן חשוב מהמהירות: כל שלב משאיר את המערכת במצב צפוי. להלן — המסלול מהמדידה הראשונה ועד המסירה למשמרת התורנית.
- ביקורת עומס הבסיס. מתעדים פרופיל חיבורים אמיתי: שיאים במשך יממה ושבוע, התפלגות לפי יישומים, שיעור סשנים קצרים וארוכים. בתוצר — גודל מאגר מבוסס ולא ערך "בערך".
- סכימת ניתוב. ב-MaxScale מפרידים זרמים לקריאה ולכתיבה, קובעים הרכב רפליקות וסימן שלפיו צומת יוצא מהסבב בעת פיגור. הסכימה נקבעת לפני שינויי הקונפיגורציה.
- הגדרת מגבלות. קובעים גבול חיבורים בו-זמנית לכל צומת, זמן החזקת סשן בטל והתנהגות בעת הצפה — תור עם הגבלה או דחייה מהירה.
- העתק של סביבת הייצור. המתקן משחזר את הטופולוגיה ותפקידי הצמתים, ולכן תוצאות הבדיקות מועברות למערכת הייצור בלי התאמות.
- בדיקה תחת עומס. מריצים את הפרופיל שתועד ובנפרד שוברים את המערכת: מכבים רפליקה, מפעילים מחדש צומת, קוטעים חיבור באמצע שאילתה. בוחנים את משך הכשל ומהירות חזרת התעבורה.
- מסירה לתפעול. מוסרים מדדי המאגר והכשלים, ספי התראות, נוהל החלפות מתוכננות וסדר החזרה לסכימה הקודמת.
השלב נסגר לא לאחר ההרצה, אלא לאחר שהמשמרת התורנית ביצעה לפי הסכימה שלנו החלפה מתוכננת.
מה נמסר לידיים: קונפיגורציות, סכימות, נהלים
הפרויקט נסגר לא בדוח על העבודה שבוצעה, אלא בקבוצת ארטיפקטים שלפיהם הצוות שלכם מתפעל את מאגר החיבורים בלי השתתפותנו. להלן — מה שנשאר בידיים לאחר הגדרת MaxScale: קבצי עבודה, סכימות, הרשאות ונהלים, כל אחד עם הסבר למה הוא נחוץ ומה לשנות בו עם גידול העומס.
- קונפיגורציות עבודה של מאגר החיבורים — קבצי שירותים ומאזינים עם מגבלות חיבורים, זמני המתנה והתנהגות בעת מיצוי המאגר; הפרמטרים מתועדים בהערות כדי שהערך ישונה במודע.
- סכימות ניתוב — אילו צמתים מקבלים כתיבה, אילו קריאה, כיצד מתפזרות השאילתות בין הרפליקות ומה קורה כאשר רפליקה מפגרת או נופלת.
- כללי גישה לבסיס — חשבונות נפרדים לכל שירות, הפרדת הרשאות לקריאה ולכתיבה, סבב סיסמאות וסדר הענקת גישה לשירות חדש.
- קטלוג תקלות טיפוסיות — "המאגר מוצה", "צומת נפל מהאשכול", "הרפליקה מפגרת": סימפטום, סיבה סבירה, פעולת התורן, סימן ההתאוששות.
- הוראות למשמרת התורנית — תרחישים צעד-אחר-צעד לבדיקת בריאות הצמתים, החלפה ידנית לגיבוי וסדר הסלמה אם התרחיש לא עבד.
- נוהל תפעול — כיצד לשנות מגבלות מאגר, מתי להרחיב את מספר החיבורים, אילו מדדים לבדוק מדי יום ואילו ספים להיחשב מדאיגים.
- לוח מדדים והתראות — תפוסת המאגר, מספר כשלי חיבור, השהיית רפליקציה; ההתראות מוגדרות לפי ספים ולא לפי עצם הנפילה.
הקונפיגורציות נשמרות במאגר עם היסטוריית שינויים — החזרה למצב קודם אורכת דקות ואינה דורשת פענוח עיוור.
ניתוח מקרה הטמעה: שיא עומס ותורי חיבורים
הלקוח — שירות תשלומים עם תעבורה לא אחידה: לקראת הערב ובימי מבצעים מספר המשתמשים בו-זמנית גדל פי שלושה. היישום החזיק חיבורים לבסיס ישירות, לכל מופע היה מאגר משלו, ובשיא נפתחו לשרת עד תשע מאות חיבורים בתקרה של חמש מאות. ההמתנה למקום הגיעה לארבע שניות, חלק מהשאילתות נקטעו בשל פסק זמן, והתורן נודע על הבעיה מהמשתמשים.
הוצאנו את ניהול החיבורים לשכבה נפרדת — MariaDB MaxScale במצב קריאה-כתיבה: היישומים פונים לפרוקסי, והוא מחזיק מאגר משותף לבסיס, תוך חלוקה בין סשנים נכנסים לחיבורים ממשיים. החיבורים ממוחזרים בין שאילתות, ומיותרים נסגרים לפי בטלה, במקום להיתלות עד הפעלה מחדש של היישום.
מדדים לפני ואחרי
| מדד | לפני | אחרי |
|---|---|---|
| חיבורים לבסיס בשיא | ~900 | 120 |
| המתנה למקום חיבור | עד 4 שניות | עשיריות שנייה |
| שאילתות שנקטעו בשל פסק זמן | 6-7% | פחות מ-0,1% |
| כשל בצומת הבסיס | החלפה ידנית | אוטומטית, בתוך שניות |
כשל הצומת נבדק בנפרד: כיבינו רפליקה תחת עומס. הפרוקסי הסיר אותה מהאיזון, הסשנים החיים התחלקו מחדש — היישום לא ראה ניתוק, ולא נדרשו החלפות ידניות או חזרות על שאילתות.
במה שונה ריבוב חיבורים ממאגר חיבורים בקוד?
מאגר חיבורים ביישום פותר משימה אחת — לא לפתוח חיבור עבור כל שאילתה. החיבור חי בתוך התהליך, חוזר למאגר וממוחזר על ידי המטפל הבא. הגבול העליון נקבע מראש: כל כך חיבורים מחזיק עותק אחד של השירות, והוא גם זה שצורך אותם.
ריבוב חיבורים פועל ברמה אחרת — בין היישום לבסיס. הפרוקסי, במקרה שלנו MaxScale, מחזיק קבוצה משלו של סשנים לשרת ומחלק אותם בין חיבורי הלקוח. כל עוד שאילתה ממתינה לתשובה או שהיישום עסוק בחישובים, הסשן שלה בשרת נמסר ללקוח אחר — הבטלה מפסיקה לתפוס משאב של הבסיס.
ההבדל נעשה מורגש עם עותקים רבים של השירות. כל עותק עם המאגר שלו מחזיק קבוצת חיבורים נפרדת: התרחבות כלפי מעלה מגדילה את מספרם באופן ליניארי, הבסיס נתקל בכמות החיבורים המרבית ובזבז זיכרון על כל אחד. ריבוב מנתק את התלות הזו — מספר הסשנים לבסיס נקבע לפי העומס בו-זמנית, ולא לפי מספר עותקי השירות.
ההשוואה בין הגישות אינה מצטמצמת ל"אחד במקום השני". ריבוב אינו תואם למצב ברמת הסשן: טבלאות זמניות, משתני משתמש, נעילות וטרנזקציות דורשים קיבוע החיבור ללקוח למשך העבודה. הפרוקסי מקצה ללקוח כזה סשן נפרד, ולאחר סיומו מחזיר אותו למחזור המשותף. המאגר ביישום מסיר את התקורה של פתיחת חיבור, הריבוב — של הבטלה שלו, ולכן בסכימת עבודה הם עומדים יחד.
שאלות טכניות נפוצות על מאגר חיבורים
מאגר חיבורים נראה פשוט, עד שצומת נופל באמצע טרנזקציה. הספקות בדרך כלל אינם על המאגר עצמו, אלא על ההתנהגות בעת כשל ובעת העברת הכתיבה לרפליקה.
חלק מהשאלות נסגרות בקונפיגורציית הפרוקסי ובפרמטרי הדרייבר, והשאר דורש שינויים בקוד. להלן — מה שעולה לרוב לפני תחילת העבודה.
מה קורה לטרנזקציה פתוחה אם הצומת הפסיק להגיב?
הטרנזקציה אינה מועברת לצומת אחר: הפרוקסי קוטע את הסשן, היישום מקבל שגיאה וחוזר על הפעולה כולה. לכן קובעים זמן המתנה ומקפידים שהפעולות יהיו אידמפוטנטיות.
האם צריך לשנות את קוד היישום?
בדרך כלל לא: היישום מתחבר לכתובת הפרוקסי, והדרייב והשאילתות נשארים כשהיו. שינויים נדרשים אם השירות עצמו בוחר צומת לקריאה או מחזיק חיבור אחד לכל מחזור החיים.
כיצד הקריאה עוברת לרפליקות?
לפי כלל ניתוב: כתיבה הולכת למאסטר, קריאה — לרפליקות. בנפרד מגדירים את ההתנהגות בעת פיגור רפליקה, כדי שלאחר כתיבה היישום לא יקבל נתונים מיושנים.
כיצד לאבחן חיבורים ותורים שרידיים?
בפרוקסי רואים את מספר הסשנים לכל צומת, אורך התור וזמן ההמתנה בו. תור שאינו מתפזר לאחר החלפה — סימן שגודל המאגר אינו תואם את העומס.
האם אפשר לחזור מהשינויים?
הקונפיגורציה נמצאת במערכת ניהול גרסאות: חזרה לקבוצת הכללים הקודמת — פקודה אחת, בלי הפעלה מחדש של היישום.
נדון במשימה: נתאים סכימת מאגר לעומס שלכם
מאגר חיבורים אינו פרמטר אחד, אלא בחירת סכימה: כיצד התעבורה מתפזרת בין המאסטר לרפליקות, מה לעשות עם טרנזקציות ושאילתות ארוכות, וכיצד היישום מתנהג בעת כשל צומת. כדי לדון במשימה באופן ענייני, די לשלוח נתונים ראשוניים — את השאר נברר בעצמנו ונחזור עם הערכה.
מה לשלוח לניתוח ראשוני:
- יישומי לקוח: כמה יש, כיצד מתחברים, האם קיים מאזן חיצוני או שהחיבורים הולכים ישירות לבסיס;
- פרופיל עומס: שיעור קריאה וכתיבה, השאילתות הנפוצות והארוכות ביותר, חלונות שיא;
- טופולוגיה: מספר רפליקות, פיגור רפליקציה, דרישה לקרוא את הנתונים של עצמך מיד לאחר כתיבה;
- סימפטומים: ניתוקי חיבורים, גידול בסשנים רדומים, שגיאות בעת החלפת מאסטר;
- מגבלות: חלון תחזוקה, דרישות לזמינות, כללי גישה וביקורת.
אנו מחדדים את התאמת סכימת הניתוב: הפרדת קריאה וכתיבה, איזון חיבורים, קיבוע סשן לצומת, זמני המתנה והתנהגות בעת כשל מאסטר.
בתשובה תקבלו הערכה ותוכנית עבודה: טופולוגיה יעד, קונפיגורציית מאגר וניתוב, שלבי הטמעה בלי השבתה וקריטריוני קבלה — שיעור השאילתות שהופנו לרפליקות, זמן ההחלפה בעת כשל, ומספר החיבורים שנקטעו בשיא. בהמשך — ליווי הבסיס: ניטור מדדי המאגר ושינויים מתוכננים בהתאם לגידול העומס. תארו את המשימה — נחזור עם הערכה ותוכנית.







