The Buffer Cache - ilDBA Portal

The Buffer Cache

08/06/2011 | פורסם על ידי

מה זה בכלל buffer cache?

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

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

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

איך מנהלים דבר כזה?

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

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

הפתרון של אורקל הוא ניהול המבוסס על מנגנון הנקרא Least Recently Used או בקצרה LRU. הרעיון הבסיסי של מנגנון כזה הוא להתבסס על מה שקרה בעבר כדי להשליך על העתיד. אם כל ה- buffer cache שלי מלא ואני צריך לכתוב אליו בלוק חדש, זה אומר שאני צריך לזרוק בלוק קיים החוצה. מנגנון KRU קובע שהבלוק שיעוף מהזכרון יהיה זה שלא השתמשו בו הכי הרבה זמן, ומכאן השם Least Recently Used. אבל זה לא ממש מספיק, אם יש בלוק שלא השתמשו בו הרבה זמן, אבל בסך הכל קראו אותו המון פעמים, ולעומתו יש בלוק שהשתמשו בו יחסית לאחרונה אבל קראו אותו רק פעם אחת, האם בהכרח עדיף לזרוק מהזכרון את הבלוק הראשון? לא בטוח.

וככה מסתבך המנגנון.

LRU? MRU?

אז כמו שאמרנו, אורקל משתמש במנגנון LRU. כדי להסביר איך זה עובד נדמיין את ה- buffer cache כשורה אחת ארוכה של בלוקים. השורה הזאת היא ה- LRU שלנו, הבלוקים בשורה ממויינים כך שהבלוק שהשתמשו בו אחרון יהיה בצד השמאלי של השורה (צד שנקרא Most Recently Used או MRU בקצרה), והבלוק שלא השתמשו בו הכי הרבה זמן יהיה בצד הימני (שנקרא LRU).

במודל הראשוני והפשוט שהצגנו כאשר תהליך קורא בלוק וצריך לרשום אותו ל- buffer cache (בהנחה שה- buffer cache מלא) הוא יוציא מהרשימה את הבלוק הימני ביותר (בצד ה- LRU) וירשום את הבלוק החדש שלו בצד השמאלי של הרשימה (MRU). כאשר תהליך קורא בלוק שכבר נמצא ב- buffer cache הוא צריך לנתק אותו מהמקום שלו ברשימה ולחבר אותו מחדש בצד הכי שמאלי של הרשימה. בדרך זו בלוק שלא משתמשים בו, יעבור עם הזמן ימינה ברשימה וכאשר הוא יהיה האחרון ברשימה הוא יצא מהזכרון.

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

המימוש של אורקל הוא ברשימת LRU כמו שראינו, כאשר על כל בלוק נשמרת עוד פיסת מידע, כמה פעמים קראו את הבלוק, נקרא לחלק הזה touch count לצורך ההסבר. כאשר תהליך קורא בלוק והבלוק נמצא כבר בזכרון, כל מה שהתהליך עושה הוא לקדם את ה- touch count באחד וזהו, בלי שינוי של הרשימה. אם הבלוק לא נמצא בזכרון התהליך צריך לפנות בלוק מהזכרון ולהכניס את החדש במקום. כדי לפנות בלוק ישן, הוא ילך לקצה הימני של הרשימה (ה- LRU) ויבדוק מה ה- touch count. אם הוא גבוה (כלומר בלוק פופולרי), הוא יעביר את הבלוק לקצה השמאלי של הרשימה (ה- MRU) ויבדוק את הבא בתור. כאשר הוא יגיע לבלוק עם touch count נמוך, זה יהיה הבלוק שיצא מהזכרון. את הבלוק החדש התהליך לא יכניס לקצה השמאלי של הרשימה (ה- MRU) אלא לאמצע הרשימה, וב- touch count שלו התהליך ירשום את הערך 0.

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

כמה רכיבי buffer cache יש לנו?

אחרי שהבנו איך עובד המנגנון, בואו נראה כמה רכיבי buffer cache יש לנו ומה מטרת כל אחד.

בכל בסיס נתונים של אורקל חייב להיות לפחות buffer cache אחד שנקרא default. גודלו מוגדר באמצעות הפרמטר db_cache_size וגודל הבלוק שלו נקבע לפי הפרמטר db_block_size. בנוסף אליו קיימים באורקל שני רכיבי buffer cache נוספים בעלי אותו גודל בלוק, הם מוגדרים על ידי הפרמטרים db_keep_cache_size ו- db_recycle_cache_size ובהתאמה נקראים keep buffer cache ו- recycle buffer cache. כאשר יש לנו 2 רכיבים או יותר, אנחנו יכולים להגדיר לכל טבלה ואינדקס לאיזה buffer cache הם יעלו. אגב, כמו שאמרתי, חייב להיות default buffer cache. אם רוצים להגדיר עוד אפשר להגדיר את ה- keep או ה- recycle או שניהם, הם לא תלויים אחד בשני.

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

וכאן בא חלק שחשוב מאד להבין, כי לדעתי זאת אחת הטעויות הנפוצות ביותר באורקל. המטרה של ה- keep וה- recycle היא לאפשר לנו משחק נוסף עם הזכרון, אבל חשוב לדעת שכל שלושת רכיבי ה- buffer cache מתנהגים בדיוק באותה צורה ועובדים אותו דבר, ההסבר של ה- LRU שתארנו למעלה נכון לכל השלושה ללא שום הבדל. כלומר, הניהול שלהם הוא באחריותנו הבלעדית – עלינו לשים לב טוב מהו הגודל שאנחנו מגדירים, מכיוון שאם לא נגדיר נכון אנחנו עלולים להרע את הביצועים במקום לשפרו.

לדעתי הבעיה היא בשמות שאורקל נתנו, תמיד תחשבו על זה לא כ- keep ו- recycle אלא כ- buffer cache 1 ו- buffer cache 2 ואולי זה יעזור לכם להתנתק מהשמות המבלבלים.

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

עד כאן ראינו שלושה רכיבים: default buffer cache, keep buffer cache ו- recycle buffer cache. לאלה מצטרפים עוד ארבעה. באורקל גודל בלוק יכול להיות 2K, 4K, 8K, 16K או 32K. החל מגרסא 9.2 ניתן ליצור tablespace בעל גודל בלוק שונה מהגודל המוגדר ב- db_block_size. על מנת ליצור tablespace כזה צריך buffer cache בעל אותו גודל בלוק המוגדר על ידי הפרמטר db_nk_cache_size כאשר ה- n הוא 2, 4, 8, 16 או 32, לפי גודל הבלוק הרצוי. מכאן שיש לנו חמש אפשרויות לגודל בלוק של buffer cache אבל אחד מהם הוא ה- default ולכן נשארים עוד ארבעה.

כך שסך הכל אפשר ליצור עד שבעה רכיבי buffer cache באורקל, שלושה בגודל בלוק ה- default וארבעה בגדלים אחרים.

חשוב לזכור מספר דברים:

–          כל רכיבי ה- buffer cache מתנהגים בדיוק באותה שיטה ובאמצעות אותו מנגנון LRU.

–          עוד רכיבי  buffer cache באים על חשבון ה- default buffer cache. האם באמת צריך ליצור רכיבים חדשים או שפשוט עדיף להשאיר את המקום הזה ל- default ולתת לאורקל לנהל אותו?

–          Keep ו- recycle הם סתם שמות שאורקל נתנו, אין להם באמת משמעות והם לא מתנהגים שונה אחד מהשני. כדי ש- keep באמת יהיה keep אנחנו צריכים להגדיר אותו גדול מספיק ולא להעלות אליו יותר מדי טבלאות ואינדקסים.

–          גם buffer cache של גודל בלוק שונה יכול לגרום לבעיות ביצועים אם הוא קטן מדי וב- tablespace הרלוונטי יש הרבה מידע. במקרה זה הוא יתנהג כמו ה- recycle.

–          כאשר מגדירים tablespace בגודל בלוק שונה חייבים buffer cache בשבילו, החסרון הוא שאין לנו יכולת משחק עם המידע שנמצא ב- tablespace. הוא ורק הוא יכול להשתמש רק ב- buffer cache הזה.

מקווה שנהניתם.
נתראה ברשומה הבאה !
לירון אמיצי.

ניתן ליצור קשר עם לירון דרך עמוד האודות שלו: אודות

The following two tabs change content below.
ירון אמיצי הוא סמנכ"ל שירותי מומחה בחברת בריליקס ו-DBA בכיר בעל נסיון של למעלה מ- 15 שנים. ללירון תואר Oracle Ace ומתמחה בנושאי ביצועים, תשתיות, פתרונות זמינות גבוהה, גיבויים ושחזורים. ללירון יש גם בלוג עצמאי בכתובת: https://amitzil.wordpress.com

השאר תגובה:

שם (חובה):
אימייל (לא יפורסם) (חובה):
תגובה (חובה):

*



מאמרים קשורים

Baruch Osoveskiy

תיקון מהיר לדיסק איטי

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

OS Background operations

אורי לרנר בטיפ קצר ושימושי על העברת פעולות לרקע במערכת [...]
רשימת

רשימת הפיצ'רים החדשים של אורקל 12.1

אורקל פרסמו את הספרות הרשמית לגרסה 12.1 שיצאה לאחרונה וזמינה להורדה. בין שאר הספרים (החשובים כל אחד שלעצמו), פורסם הספר המסקרן ביותר בעיני – Oracle Database 12c Release 1 (12.1) New Features. זהו ספר שראוי שכל DBA [...]
גרסת

גרסת אורקל 12c זמינה להורדה

בשעה טובה ולאחר המתנה סופר ארוכה, גרסת אורקל 12c (גרסה 12.1) זמינה סוף סוף להורדה רשמית מהאתר של אורקל. הגרסה החדשה מנסה לתת פתרונות לעולם ה"ענן" – ומוסיפה פיצ'רים חדשים שבאים לתת מענה בדיוק [...]
Copyright 2019 ilDBA Portal. Brought to you by Brillix - Israel Leading DBA company. Sponsored by: DBSnaps - Database Video Tutorialss
Website Security Test
%d בלוגרים אהבו את זה: