מדוע Neon serverless PostgreSQL נתקל במגבלות חיבורים
מודל ה-Serverless של Neon מפתה בכך שמסד הנתונים מתאים את עצמו לעומס ואינו דורש ניהול ידני.
צוואר הבקבוק מתגלה לא במצב הממוצע, אלא בשיאים: כאשר מגיעות בו-זמנית בקשות ממשתמשים, מעיבוד רקע ומדוחות, האפליקציה נתקלת במגבלת החיבורים למסד הנתונים, אף שמשאבי המחשוב שלו עדיין נותרו בעתודה.
המלכודת טבועה במאגר החיבורים עצמו. כל מופע של האפליקציה מחזיק את הסשנים שלו, ובהרחבה אופקית מספרם גדל באופן ליניארי: עשרה מופעים עם עשרה חיבורים כל אחד — אלו כבר מאה חיבורים.
ברגע שמאגר החיבורים הכולל עובר את הגבול המותר, בקשות חדשות אינן פותחות סשן, אלא נופלות עם שגיאת חיבור — בעוד השירות כשיר לחלוטין.
התרחיש השני — השהיית מסד הנתונים בזמן חוסר פעילות. בלילה או בעונה שקטה התעבורה יורדת, צומת המחשוב עובר למצב שינה, והבקשה הראשונה שלאחר ההפסקה ממתינה להתעוררות במקום לקבל תשובה. המשתמש מקבל שגיאה או השהיה מורגשת, והתמיכה — התראת שווא "המסד אינו זמין".
שני התרחישים מתרחשים באותן שעות — בשיא, כאשר הכנסה תלויה בשנייה של תשובה. חוסר בחיבורים אצל האפליקציה מפעיל ניסיונות חוזרים, אלו מגבירים את העומס, וחלק מהבקשות נקטעות בגלל פסק זמן.
להלן נבחן כיצד סוגרים זאת באמצעות הגדרת מאגר חיבורים, מצב התעוררות והפרדת תפקידים — בלי לוותר על גישת ה-serverless.
ענפי Neon: מסדי נתונים מבודדים לפיתוח, בדיקות ובחינות
ענף של מסד נתונים ב-Neon הוא שכפול לפי עקרון copy-on-write: בעת ההסתעפות מועברים לא השורות עצמן, אלא הפניות לעמודים, ולכן מסד הבת נוצר בתוך שניות ללא תלות בנפח. לאחר מכן השינויים נכתבים רק בו, ומחיקת ענף משחררת רק את אותם עמודים שאכן נערכו בו.
מודל כזה מספק סביבות פיתוח מבודדות לכל משימה, בדיקה או ניסוי. מיגרציות ושאילתות כבדות מורצות על עותק של נתוני הייצור, בלי לפגוע במסד הראשי, ומצב בזמן מבוקש משוחזר בהסתעפות חוזרת מכל נקודה.
זמן הכנת הסביבה יורד משעות של פריסת dump לשניות: המפתח והבודק מקבלים עותק עם סכימה עדכנית, בלי להמתין להתפנותו של מתחם משותף. בדיקות מקבילות מתנהלות בו-זמנית ואינן חוסמות זו את זו.
חימום המסד לפני עומס מפסיק להיות הליך נפרד: מרימים את הענף מראש, מריצים שאילתות טיפוסיות כדי שתוכניות הביצוע ומטמון העמודים יגיעו למצב עבודה, ורק אז מבצעים מדידות. בלי חימום, הפניות הראשונות פועלות לפי תוכניות קרות ומעוותות את התמונה.
משך ההשבתה של השירות בעת שחרור גרסה מצטמצם הודות לכך שהמיגרציות נבדקו על נפח נתונים ריאלי, ולא על סכימה ריקה. אם משהו השתבש, החזרה לאחור היא מעבר לענף הקודם, ולא שחזור מגיבוי.
השוואת אפשרויות החיבור: ישיר, דרך מאגר ודרך פרוקסי
פונקציות serverless וקונטיינרים פותחים חיבור בכל הפעלה, ו-PostgreSQL משרת כל חיבור בתהליך נפרד. בשיא, לקוחות קצרי-חיים ממצים את מגבלת החיבורים, והאפליקציה מקבלת סירוב במקום תשובה. בחירת מצב החיבור היא פשרה בין מספר הלקוחות בו-זמנית לבין תאימות לקוד המוכר.
בפועל יש שלוש אפשרויות: חיבור ישיר למסד, מאגר חיבורים ושכבת חיבורים מתווכת. הן אינן סותרות זו את זו — עבור מיגרציות ומשימות רקע סביר להחזיק מחרוזת חיבור נפרדת.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| חיבור ישיר למסד | מיגרציות, משימות רקע, שאילתות אנליטיות ארוכות, דיבוג | לקוח אחד — תהליך אחד בשרת; מגבלת החיבורים מתמצה במהירות |
| מאגר חיבורים, מצב טרנזקציוני | בקשות web וקריאות לפונקציות serverless: הרבה פעולות קצרות | החיבור מוצמד רק למשך הטרנזקציה — ביטויים מוכנים (prepared statements), advisory locks, LISTEN/NOTIFY וטבלאות זמניות של הסשן אינם זמינים |
| מאגר חיבורים, מצב סשן | קוד שמחזיק מצב סשן וביטויים מוכנים | החיבור תפוס עד לניתוק הלקוח, ולכן הרווח במספר הלקוחות קטן יותר |
| שכבת חיבורים מתווכת | מחשוב בקצה, שבו כל חיבור חדש יקר | בקשה אחת לקריאה, בלי טרנזקציות אינטראקטיביות וקורסורים |
בחירת מצב החיבור נקבעת לפי פרופיל העומס: למשימות ארוכות — חיבור ישיר, לבקשות האפליקציה — מאגר במצב טרנזקציוני, לקריאות קצרות בקצה — שכבת חיבור מתווכת. מחרוזות החיבור נבדלות בפרמטרים, ולכן החלפת מצב אינה מחייבת לכתוב מחדש את קוד האפליקציה.
סדר העבודה: מביקורת שאילתות ועד מסירת נהלים
את העבודה מתחילים בביקורת, ולא בהגדרה: אוספים סטטיסטיקה על תוכניות ביצוע של שאילתות, מחפשים סריקות עוקבות (sequential scans) על טבלאות גדולות וחיבורים שנמשכים זמן רב יותר משאילתה טיפוסית של האפליקציה.
במקביל בוחנים את סכימת הנתונים — סוגי שדות, אילוצי שלמות, היסטוריית מיגרציות: חלק מהירידות בביצועים אינו טמון בשאילתות, אלא במבנה הטבלאות.
-
ביקורת שאילתות וסכימת נתונים. אוספים את השאילתות המובילות לפי זמן ותדירות, מסמנים את אלו שזמנן גדל באופן ליניארי עם נפח הנתונים, מתעדים את גדלי הטבלאות והאינדקסים ומגבלות החיבורים.
-
תכנון סכימת המסד. מיישרים את סוגי הנתונים לנתונים בפועל, מוסיפים אינדקסים ואילוצים חסרים, ומפרידים בין פעולות חמות לפעולות אנליטיות, כדי ששאילתות כבדות לא יתחרו בבקשות המשתמשים.
-
הגדרת הסביבה. קובעים את גודל צומת המחשוב ומדיניות ההשהיה, את מאגר החיבורים ואת הרפליקות לקריאה; עבור פיתוח ובדיקות מקימים ענפי מסד נפרדים ב-Neon — הניסויים אינם נוגעים במסד העבודה.
-
בדיקת כשל. מריצים עומס שיא, כשל צומת, ניתוק חיבורים ושחזור לנקודת זמן; מתעדים את זמן השחזור ואת השאילתות שמדרדרות ראשונות.
-
נוהל מיגרציות. מתארים את יישום שינויי הסכימה בלי נעילות ארוכות, את סדר ההחזרה לאחור ואת בדיקת השלמות לאחר כל מיגרציה.
-
מסירה לתפעול. מוסרים קונפיגורציות, סכימה, מטריקות לניטור, הנחיות לשחזור וסדר הסלמה, ועוברים על הכול עם צוות הלקוח.
בתום העבודה נותרת בידי הצוות קונפיגורציה ניתנת לשחזור ונהלים, ולא פעולות ידניות שנשמרות בראשו של מהנדס אחד.
מה מוסרים לידיים: סכימות, תפקידים, מדיניויות, נהלים
מסירת מסד נתונים אינה מתן גישה לקונסולה, אלא מערכת שלפיה הצוות שלכם יריץ בעצמו עותק של המתחם, יטיל מיגרציה וישחזר נתונים בלי להתכתב איתנו. להלן מה שאנו מתעדים במפורש במאגר הפרויקט ובתיעוד: מתיאור הסכימה ועד נוהל הגיבוי.
ענף ב-Neon לבדיקת מיגרציות נוצר מצילום (snapshot) — הבדיקה מתבצעת על עותק של נתוני הייצור, ולא על מסד ריק.
- סכימת נתונים ומיגרציות — קבצי SQL מגורסנים לפי סדר היישום, תרחישים נפרדים לפריסה נקייה ולפריסה על מסד קיים, ויומן גרסאות שיושמו בטבלת מערכת.
- קונפיגורציית חיבור של האפליקציה — פרמטרים של מחרוזת החיבור עבור המאגר ועבור חיבורי מערכת, הפרדה בין קריאה לכתיבה, משתני סביבה לכל מתחם, ודרישות לפסקי זמן ולניסיונות חוזרים בעת ניתוק.
- מדיניויות גישה ותפקידים — רשימת התפקידים: בעל הסכימה, האפליקציה, אנליטיקה בקריאה בלבד, תורן; גבולות ההרשאות ברמת טבלאות ורצפים, ואיסור על חשבונות משותפים.
- נוהל גיבוי — לוח זמנים לצילומים, תקופת שמירה, סדר בדיקת השחזור ונקודת אובדן הנתונים המותרת לכל מערך.
- תיעוד המסד — תיאור הישויות והקשרים, ייעודן של טבלאות מערכת, רשימת השאילתות הכבדות והאינדקסים עבורן, ומגבלות ידועות.
- תרחיש שחזור — הוראות שלב-אחר-שלב עם בדיקת שלמות והחזרה לצילום הקודם, שנבדקו על מתחם.
- מפת נראות (observability) — אלו מדדים של חיבורים, השהיות ושגיאות מאותתים על מה, ולמי.
כל סעיף אנו מסיימים יחד עם המהנדס שלכם: הוא עובר על הרשימה, מרים בעצמו את המתחם מתוך הקבצים שלנו ומשחזר את המסד. אם משהו אינו משוחזר לפי התיעוד — הסעיף אינו סגור.
מקרה בוחן: הפרדנו סביבות והסרנו כשלים בעומס שיא
לפני ההפרדה, סביבות הייצור, הבדיקות והתצוגה המקדימה חיו במסד אחד: סכימה משותפת, מגבלת מחשוב משותפת ומאגר חיבורים אחד. מיגרציות של משימת בדיקות שינו טבלאות שכבר היו בשימוש הלקוחות, ובשיא של הערב חלק מהבקשות נפלו בגלל פסק זמן.
במהלך רבעון הצטברו כ-40 אירועים, והשחזור לאחר שחרור גרסה כושל ארך 40-60 דקות: לפרוס dump, להשוות סכימה, ולהשלים נתונים.
מה שינינו
הגדרנו את Neon כך שכל סביבה תקבל ענף מסד נפרד: ייצור, בדיקות וענף לכל משימה בפיתוח. הענף נוצר בשכפול מצב ברמת האחסון — בלי ייצוא וייבוא של dump, ולכן סביבת הבדיקה מתרוממת בתוך דקות.
המחשוב מתאים את עצמו לעומס ונעצר בענפים לא פעילים, ומאגר החיבורים נשמר בצד השירות ואינו מתבזבז על חיבורים קצרים.
ההרשאות הופרדו לפי תפקידים: את ענף הייצור רואה רק המשמרת התורנית, והמיגרציות עוברות דרך מערך נפרד עם גיבוי הענף לפני ההרצה.
מה התקבל
לאחר חודשיים של תפעול: כשלים בגלל פסק זמן בשיא — אפס במקום 5-6 בשבוע, שיעור הבקשות המוצלחות עלה מ-97.2% ל-99.98%. זמן השחזור לאחר תקלה הצטמצם בערך פי 20 — מ-40-60 דקות ל-2-3: חזרה למצב הענף הקודם במקום פריסת dump. הכנת סביבה למשימה — 5 דקות במקום יומיים של המתנה והרכבה ידנית.
סביבת הבדיקה כעת משחזרת את הייצור בנתונים ובסכימה, ולכן פערים בין הבדיקות לייצור חדלו להיות מקור להפתעות. הסכימה עמדה בשיא עונתי בתעבורה גבוהה פי שלושה מהרגיל, בלי הרחבת התשתית.
במה נבדל מסד מנוהל ממופע שנפרס ידנית
ההבדל אינו ב-PostgreSQL עצמו — המנוע הוא אותו מנוע. ההבדל הוא במי שמחזיק את המערך התפעולי: מסד מנוהל לוקח על עצמו את העמידות בתקלות, הגיבויים, העדכונים והתאמת קנה המידה לעומס, ואילו מופע עצמאי משאיר זאת בידי הצוות.
מערך מנוהל מנצח במקום שבו יש יותר מסביבה אחת: הסתעפות המסד מספקת עותק נתונים נפרד לכל משימה, וסביבות לא פעילות נרדמות מעצמן. לדוגמה, Neon במצב serverless מסיר מהמהנדס את הרכבת מתחמי הבדיקות — הם נוצרים מענף בתוך דקות.
| אפשרות | מי אחראי על התשתית | מאמץ עבודה |
|---|---|---|
| שירות מנוהל | הספק: עותקים, עמידות בתקלות, עדכונים | שעות בחודש |
| מופע על שרת שכור | הצוות: פאצ'ים, רפליקציה, עותקים, ניטור | תורנויות וחלונות מתוכננים |
| אשכול עצמאי | הצוות ומחלקת התשתיות | תפקיד נפרד בכוח האדם |
תחזוקת מסד באופן עצמאי אינה הגדרה חד-פעמית, אלא מחזור מתמשך: עדכוני אבטחה, בדיקת שחזור מעותק, בקרת גדילת טבלאות ומקום בדיסק, וניטור ההדרדרות של שאילתות. כל סעיף בנפרד קטן, אך יחד מדובר בעומס קבוע שאינו מסתיים לאחר ההשקה.
אזור האחריות של הספק בכל אפשרות הוא אחד: סכימת הנתונים, האינדקסים, השאילתות האיטיות, מיגרציות בלי השבתה והרשאות הגישה. משתנה רק מי אחראי על השכבה שמתחת — השירות והחומרה. הבחירה כאן אינה בשאלת האיכות, אלא בשאלה היכן הצוות מוכן לשאת באחריות קבועה.
ספקות במעבר: תאימות, מיגרציה, חזרה לאחור
ספקות בעת העברה קשורים לעיתים נדירות לגישת ה-serverless עצמה — חשוב יותר לא לאבד נתונים עובדים ולהיות עם נתיב חזרה צפוי. לפני ההחלפה אנו מתעדים שלושה דברים: כיצד מועבר המסד, מה עם ההרחבות ואילו הרשאות נשארות לאפליקציה.
כיצד להעביר מסד עובד עם השבתה מינימלית?
המסלול העיקרי — רפליקציה לוגית: מסד היעד נכנס לזרם השינויים ומדביק את המקור, והתעבורה מוחלפת רק לאחר מכן. את הפיגור מבקרים עד לרמת שניות, לאחר מכן משווים את מספר השורות בטבלאות המפתח ואת סכומי הבקרה. הכתיבה נעצרת לדקות — לצורך ההשלמה הסופית והחלפת מחרוזות החיבור.
האם ההרחבות הנדרשות נתמכות?
מגוון ההרחבות הזמין בשירות מנוהל מצומצם מזה של שרת עצמאי. לפני המיגרציה משווים את ההרחבות המותקנות לרשימת הנתמכות: מה שאינו נתמך — מעבירים לאפליקציה או משאירים באשכול מנוהל. בנפרד בודקים את החיפוש הטקסטואלי המלא ואת הטיפוסים שההרחבות מחליפות בטיפוסים משלהן.
האם לאפליקציה יישארו הרשאות לשנות את הסכימה?
מפרידים את ההרשאות: האפליקציה פועלת בתפקיד עם גישה לנתונים, ואת הסכימה משנה תפקיד מיגרציה נפרד. המיגרציות מיושמות באופן מגורסן ומורצות על עותק של המסד לפני הייצור — השירות אינו מתקן טבלאות בעת העלייה ואינו שובר את התאימות לגרסת הקוד הקודמת.
מה אם נצטרך לחזור אחורה?
תוכנית החזרה לאחור מתועדת לפני תחילת העבודה: המסד המקורי נשאר פעיל, והרפליקציה ההפוכה חיה כל עוד הפלטפורמה החדשה לא עברה מחזור עומס מלא. נקודת האל-חזור היא ניתוק הזרם ההפוך: עד אליה החזרה אורכת כמו המעבר הישיר, ואחריה — שחזור מעותק.
נדון במשימה: נבנה סכימה ונחזור עם הערכה ותוכנית
כדי לחזור עם הערכת זמנים ותוכנית עבודה למסד, אין לנו צורך בגישה מלאה לכל הפרויקט — די בנתוני הפתיחה שקובעים את ארכיטקטורת האחסון. להלן רשימה קצרה: אם סעיף כלשהו עדיין אינו מנוסח, נדון במשימה ונסלים את החסר יחד.
- סכימת הנתונים והנפח: הטבלאות העיקריות, הקשרים ביניהן, מספר השורות המשוער בטבלאות הגדולות ביותר וקצב גידולן.
- פרופיל העומס: תדירות שיא וממוצעת של בקשות קריאה וכתיבה, מספר החיבורים בו-זמנית, דרישות לזמן התגובה במסכים הקריטיים.
- תרחישי גישה: מהיכן מגיעים החיבורים — אפליקציית שרת, משימות רקע, דיווח, סקריפטים אדמיניסטרטיביים; האם נדרשת הפרדה בין תפקידים והרשאות.
- עבודה עם גרסאות הסכימה: היכן נשמרות המיגרציות, כיצד מיושמות, והאם קיים סדר מגובש לחזרה למצב הקודם.
- דרישות לשימור הנתונים: עומק השחזור לנקודת זמן שרירותית, תדירות בדיקת הגיבויים, וחלון אי-הזמינות המותר בעת שחזור.
- פריסה וגישות: היכן נמצאים המשתמשים והשירותים, והאם נדרשים עותקי מסד נפרדים לפיתוח, לבדיקה לפני שחרור ולחקירת אירועים.
אנחנו חוזרים לא עם הערכה "במילים בלבד": מציגים את תרשים הפריסה, את הגדרת מאגר החיבורים ואת מצב ההשהיה של מסד לא פעיל, את תוכנית המיגרציות ואת סדר הבדיקה לאחר ההחלפה.
עבור פרויקטים על Neon נפרט בנפרד כיצד ענפי המסד וההתאמה האוטומטית נשענים על פרופיל העומס שלכם — מזה תלויים גם הסכימה וגם לוחות הזמנים.
תארו את המשימה — ונחזור עם הערכה ותוכנית עבודה.







