In-memory OLTP החדש של SQL Server 2014 מאיץ ביצועים פי 100

15 במאי 2014

אין תגובות

imageמאת: דניאל רוקח פורת, מיקרוסופט ישראל

במסגרת אירוע ההשקה של של SQL Server 2014 ב-7.3.14 הציג שי אנגלברג יועץ בכיר בנושא SQL את הפיצ'ר המרכזי של הגירסה החדשה של SQL Server 2014 רכיב ה- In-memory OLTP או בשמו הפנימי – Project Hekaton. לאלו מכם שלא נכחו בהרצאה הנה עיקרי הדברים. תוכלו להוריד גם את המצגת הזו ומצגות אחרות מהאירוע – לחצו כאן

מה זה In-Memory OLTP?

ה- In-memory OLTP הינו מנוע חדש של SQL Server, שפותח במשך 5 שנים ומאפשר האצת ביצועים פי 100 עבור OLTP Workloads ע"י שימוש בזיכרון גדול ומעבדים מרוביי ליבות וזאת תוך שמירה על הקונסיסטנטיות של הנתונים. יש לציין שלמרות שמדובר במנוע חדש לגמרי, הוא מוטמע בתוך SQL Server ו"שקוף" למפתח ולמנהל בסיס הנתונים.

האם זהו רק בסיס נתונים רגיל שיושב בזיכרון לשליפה מהירה?

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

הסרת צווארי בקבוק עם ארכיטקטורה חדשה

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

  • IO של הדיסק
  • נעילות לגישה בו זמנית
  • Latches (נעילות זיכרון)
  • Logging
  • אינטרפרטציה של פרוצדורות

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

  • אינדקסים מותאמים לשימוש בזכרון המרכזי
  • הסרת נעילות ו- latchים
  • קומפילציה של הבקשות ל- native code להורדת הזמן הדרוש לכל שאילתה

צוואר בקבוק 1 – Disk IO

אין ספק שכל קריאה לדיסק לוקחת זמן ומהווה צוואר בקבוק מבחינת ביצועים. המטרה אם כן היא לבטל את הקריאות לדיסק לחלוטין ע"י שמירת הנתונים על גבי הזיכרון. כמובן שזו לא חוכמה גדולה וכבר היום ניתן להגדיר טבלאות שיישבו בזיכרון לשליפה מהירה. אלא שכאמור In-memory OLTP לוקח את זה כמה צעדים קדימה ומציעה גישה שהיא לא רק In-memory, אלא Memory Optimized.

מה זה אומר?

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

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

Clustered Index – במקום שמירה של נתונים ב- clustered index, ה- data עצמו לא נמצא יותר באינדקס. ליתר דיוק, האינדקס לא מכיל נתונים בכלל אלא רק פוינטרים לשורה הראשונה שמכילה את הערך הזה והשורות אחר כך מקושרת אחת לשניה.

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

buffer pool – במקום שמירה של פייג'ים עם נתונים באזור buffer לשליפה "מהירה", היום אין בכלל buffer pool.

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

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

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

כיצד ה- In-memory OLTP החדש של SQL Server 2014 מסיר את כל צווארי הבקבוק בדרך למהירות פי 100

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

צוואר בקבוק 2 – נעילות

באופן מסורתי נעילות נועדו לשמור על אמינות הנתונים. אך במצב שבו יש לנו כל הרבה ליבות שפועלות בו זמנית אין זה הגיוני שיהיה צורך לחכות לנעילות, אלא צריך לאפשר כתיבה וקריאה מקבילית של נתונים, תוך שמירה על אמינותם. ה- In-memory OLTP מציג גישה חדשה הנקראת Optimistic Multi-version Concurency Control.  לפי גישה זו אין נעילות (כותבים אינם חוסמים כותבים + קוראים וכמובן שקוראים אינן חוסמים כותבים).

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

צוואר בקבוק 3 – Latches (נעילות זיכרון)

כל עוד צווארי הבקבוק האחרים היו קיימים צוואר בקבוק זה לא היה מורגש, אבל כעת בסביבה עם ריבוי ליבות אנו לא רוצים לחכות לנעילות אזוריות של קוד ונתונים מפני גישה מקבילית. ה-  In-memory OLTP כולל מנגנון ייחודי הנקרא Lock-Free Mechanism, אשר מונע נעילות והופך את האזורים הללו לנגישים.

צוואר בקבוק 4 – Logging

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

  • פעולות אינדקס אינן נכתבות
  • המידע שישמש אותנו למקרה שנצטרך לבצע Undo אינו נכתב רק טרנזקציות commited
  • כל טרנזקציה נכתבת לרשומת לוג אחת גדולה על מנת לצמצם את כמות רשומות ה- Log
  • המנגנון מנסה לקבץ מספר רב ככל האפשר של רשומות לוג ל- IO יחיד גדול.

צוואר בקבוק 5 – Procedure Interpretation

על מנת לצמצם את זמן ההמתנה לעיבוד הבקשות, In-memory OLTP עושה שימוש ב- natively compiled stored procedures. מתוך הכרה שהמעבדים לא הופכים יותר מהירים אלא הארכיטקטורות הולכות לכיוון של ריבוי מעבדים וליבות, הרי שיש לצמצם את כמות ההוראות הדרושות לעיבוד שאילתות וביצוע לוגיקות עסקיות. המעבר ל- Native Mode מאפשר עבודה יותר יעילה על ידי:

  • ביצוע קומפילציה אחת ושכפול ה- execution של workloadים (compile once and execute many times)
  • ה- stored procedures עובדים עם טבלאות In-memory OLTP בלבד.
  • הפרוצדורות עוברות דרך אופטימיזר ולאחר מכן מתורגמות ל- C ועוברות קומפילציה לDLL
  • המנגנון אינו מבצע בדיקות runtime

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

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

למידע נוסף – לחצו כאן

להורדת ה- white paper – לחצו כאן

להסבר על איך להתחיל להשתמש – לחצו כאן

להתנסות ב- SQL Server 2014 – לחצו כאן

דניאל רוקח פורת הינה מנהלת השיווק לתחום ה- Application Platform.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *