הגדרת AWS DynamoDB לאחסון NoSQL

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

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

מדוע AWS DynamoDB מדרדר תחת עומס

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

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

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

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

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

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

האפקט של סכימת נתונים וגישה שנבנתה מחדש

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

זמן תגובה בשאילתות חמות

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

סוג הכשלים בכתיבה נעלם

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

עומס צפוי ורזרבה בתפוקה

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

גידול בנפח הנתונים בלי לבנות מחדש את האחסון

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

מצבי הפעולה של AWS DynamoDB ומתי הם מתאימים

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

השוואת האפשרויות

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

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

סדר העבודה: ביקורת סכימת הנתונים ומפתחות הגישה

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

  1. מפיקים פרופיל שאילתות — לפי הלוגים והקוד בודקים אילו פניות מתבצעות, באיזו תדירות, מה נכנס לתנאי השליפה ומה מוחזר במלואו.
  2. מנתחים את הסכימה הנוכחית: בודקים אם מפתח המחיצה מפזר את העומס באופן אחיד ואם מפתח המיון מחזיר את הטווחים הנדרשים בלי מעבר מלא.
  3. מתכננים אינדקסים לתבניות שליפה ספציפיות: מקומיים — בתוך מחיצה אחת, גלובליים — לשאר, ומקפידים שכל אינדקס לא ייקר את הכתיבה.
  4. מגדירים הרשאות: תפקיד נפרד לכל שירות, רק הפעולות הנדרשות ורק הטבלאות והאינדקסים הדרושים, בלי מפתחות גישה משותפים בקונפיגורציה.
  5. מבצעים בדיקת עומס: מריצים תבניות אמיתיות על הנפח המיועד, בוחנים השהיות ושיעור שגיאות בשיא, והתנהגות עם מיצוי הקיבולת המוקצית.
  6. מקבעים נוהל ומעבירים לצוות: סכימות הטבלאות והאינדקסים, תיאור התפקידים, כללי שמות, נקודות ניטור וסדר שינוי הסכימה.

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

סכימות טבלאות, מדיניות גישה ונוהלים

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

  • תיאורי טבלאות ואינדקסים — מפתח המחיצה והמיון, הרכב האינדקסים המשניים והנימוק לבחירה: שאילתות חדשות אינן מובילות לסריקה מלאה של הבסיס.
  • תפקידים ומדיניות גישה — תפקידים נפרדים לשירותים, למהנדסים ולצינורות בנייה, הרשאות לפי עיקרון הצורך המינימלי, והפרדה בין קריאה לכתיבה בין הסביבות.
  • הגדרות הצפנה — מה מוצפן במנוחה ובמעבר, היכן נשמרים המפתחות, ומי אחראי על הסבתם (rotation).
  • סכימת שכפול — אילו אזורים מקבלים עותק של הנתונים, מהי השהיית ההפצה, ולפי איזה כלל התעבורה מוסטת בעת כשל.
  • נוהל גיבוי ושחזור — לוח זמנים לצילומים, עומק השמירה, ובדיקה סדירה של השחזור במתחם בדיקות עם מדידת זמן.
  • סדר טיפול באירועים — מדדי השהיה וכשלים במעקב, ספי התראות, האחראים וסדר ההסלמה.
  • יומן שינויי סכימה — כיצד מתווספים מאפיינים ואינדקסים בלי לעצור את הכתיבה, ומי מאשר את השינוי.

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

לפני: חוסר איזון בין המחיצות וכשלים בשיא

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

בשיא זה התבטא בכשלי כתיבה ובניסיונות חוזרים, וזמן התגובה של הכתיבה ב"זנב" הגיע עד 900 מ״ש — הפרונט הציג שגיאות בהשלמת ההזמנה, ונדרשה סגירה ידנית של הזמנות.

אחרי: עומס מאוזן וגידול של פי שלושה בנפח

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

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

זמן התגובה של הכתיבה ב"זנב" ירד מ-900 ל-140 מ״ש, שיעור כשלי הכתיבה בשיא — מ-3.2% לאפס, ופיזור הצריכה בין המחיצות ירד מפי עשרה לפי שניים. נפח הנתונים באותה תקופה גדל פי שלושה: בלי החלפת פלטפורמה, בלי חלוקה ידנית למחיצות ובלי לכתוב מחדש את האפליקציה.

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

מה לעשות אם הטבלה כבר פרוסה ויש בה נתונים

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

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

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

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

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

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

ספקות ומגבלות: מפרקים לפי סעיפים

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

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

עד כמה מסובך להחליף אחר כך את מצב הקיבולת?

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

מה מסוכן בסריקות מלאות של הטבלה?

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

האם סכימת המפתחות תספיק לגידול?

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

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

מי אחראי על הפרדת ההרשאות?

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

נדון במשימה: מה נדרש מכם ואיך נתחיל

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

מה כדאי לשלוח או לספר בשיחה:

  • פרופיל עומס: עוצמת שאילתות ממוצעת ובשיא, זינוקים יומיים ושבועיים, גידול נפח צפוי;
  • תרחישי קריאה וכתיבה: אילו שאילתות שולטות, לפי אילו מפתחות מחפשים, והאם נדרשות שליפות לפי טווח ואגרגציות;
  • דוגמאות לישויות או הסכימה הנוכחית: שדות, קשרים, גדלי רשומות ותקופות השמירה שלהן;
  • דרישות לזמינות גבוהה: זמן אי-זמינות מותר, האם נדרשים גיבויים ושחזור לנקודת זמן (point-in-time);
  • הרשאות גישה וסביבות: כמה סביבות, מי וכיצד פונה לבסיס הנתונים, והאם יש מגבלות בהפרדת תפקידים;
  • מגבלות: חלונות לשינויים, סדר אישורים, והאם נדרשת מיגרציה של נתונים קיימים.

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