שימוש ב- AlwaysOn להרמת Readable Secondary–איך זה יכול להשתבש ומה אפשר לעשות

18 בMarch 2017

תגיות: ,
אין תגובות

לאורך השנים, עבר SQL Server לא מעט שלבים באבולוציה של פתרונות שהמטרה שלהם לתת HA/DR מסוגים שונים. בשנים האחרונות, אחד הפתרונות המרכזיים שבו עושים שימוש הוא AlwaysOn. אחד הדברים החזקים ב- AlwaysOn הוא הגמישות שלו וההתאמה שלו למגוון (יחסית רחב) של תרחישים.
אחד הדברים המעניינים שזה מאפשר, הוא הרמת read-only replica. הרעיון הוא replica מעודכנת, שמקבלת את כל המידע ומשמשת בד”כ לשליפות שונות – כאשר אפשר למשל להריץ עליה תהליכי reporting, לעשות בה שימוש לשאילתות ad-hoc וכו’ – מבלי להפריע לאפליקציה המרכזית.

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

התרחיש

התרחיש שאליו אני מתייחס הוא שרת Primary שמולו מתבצעת העבודה, התשאול והשאילתות. כאשר קיים שרת Secondary למטרת תחקור בלבד. כלומר, ההנחה היא ששרת ה- secondary לא אמור לשרת אף מטרה של failover, הוא לא משרת תרחישי DR – וכל אלה מקבלים מענה בצורה אחרת..
במקרה כזה – המטרה שלנו מאד פשוטה: להחזיק שרת שמשמש לקריאות מסוגים שונים, שלא פוגע בשום מצב בשרת ה-primary  (שהוא זה שעושה עדכונים, ומשרת למשל את השימושים הקריטיים) ובזמינות שלנו, אלא רק עוזר לו (בכך שאנחנו מסיטים workloads מה- primary ל- secondary המדובר.
בתרחיש עליו מדובר מוגדר Availability Group  שחברים בו ה- primary וה- secondary, כאשר ה- secondary מוגדר עם Asynchronous-commit וכמובן גם Manual failover (ברגע שזה async commit זה הכרחי).

למה זה טוב?

לפני שאני אתחיל להתייחס לדברים שיכולים להשתבש, אני רוצה להתייחס לנקודה מרכזית אחת לפני הכל – במקרים שזה תורם, החסרונות הפוטנציאליים מתגמדים לעומת היתרונות הרבים. בין היתר – אנחנו יכולים להתייחס ביתרונות ל”סוג-של” scale-out. אמנם לא scale-out אמיתי, אבל בהחלט כזה שמאפשר לנו (במחיר של שכפול מידע) להרים עוד nodes שמשרתים בקשות שונות שיכולות לעבוד עם נתונים שהם אולי קצת בפיגור לעומת הנתונים האמיתיים (פיגור של sub-second במקרה של LAN).
מעבר להגדלת ה- capacity באמצעות הפניית שאילתות תחקוריות ו-ad-hoc-יות לשרת נפרד (ולמעשה, ביצוע offloading של חלק מהעומס) יש עוד כמה יתרונות:

  • הפחתת “התנגשויות” בין readers ל- writers: גם אם מסיבה כלשהי ב- primary שלכם אתם לא עושים שימוש ב- RCSI (Read Committed Snapshot Isolation), מאחורי הקלעים ה-isolation level שמופעל על שליפות מול ה- secondary יהיה תמיד ב- RCSI – גם בין השליפות לבין עצמן (כמובן) וגם מבחינת ההתנהגות כשלוקחים בחשבון את ה-workload שרץ על ה- primary.
  • סטטיסטיקות שמתאימות ל- workload של הקריאה: מאחורי הקלעים SQL Server מייצר סטטיסטיקות שונות (אלא אם כן מנעתם את זה) שמתאימות לשליפות שרצות מול ה- secondary. בהתאמה, זה מאפשר היווצרות של execution plans שמותאמות לקריאות
  • אופטימיזציה לאורך זמן של ה- buffer pool כך שיתאים ל-workload של הקריאה: ברגע שאתם מפרידים את השאילתות התחקוריות ל-node אחר, אתם מאפשרים ל- instance הזה לנהל למעשה את ה- buffer pool שלו, שמותאם לשליפות שמתבצעות מולו – וכך מונעים מצב שבו יש “תחרות” על מה נשמר ב- buffer pool ומה יורד ממנו ודורש גישה לדיסק

אז מה יכול להשתבש ב- Primary?

Transaction Log

כאשר עובדים בתצורה של Async-commit, manual failover – לכאורה לא אמרוה להיות השפעה על ה- primary. בפועל, יש כמה מקרים שהם לא “בעיות”, אלא קיימים by design שיכולים להפתיע ולגרור בעיות, ואפילו downtime, ל- primary. המרכזית שבהן, היא חוסר יכולת של ה- transaction log להתנקות.
בפועל, מה שקורה כאשר מופעל AlwaysOn בתצורה של Async-commit, הוא שפעולות מתבצעות מול ה- transaction log ב- primary, כאשר הרשומות של ה- transaction log “משונעות” ל- secondaries שמוגדרים. ב- primary מתבצע המעקב של מה ה- LSN האחרון ששונע ונקלט ב-secondary, ורק רשומות שקודמות ל- LSN הזה יכולות להתנקות. התהליך הוא א-סינכרוני במובן שלא ממתינים ל-ack מה- secondary על זה שהוא קיבל את רשומות הלוג כדי לתת ack לטרנזקציה שמתבצעת מול ה- primary, אבל כן ממתינים ל- ack מה-secondaries על כך שהם קיבלו ושמרו את הרשומות של ה- transaction log לפני  שה- primary יכלול את הרשומות הללו ב- BACKUP LOG הבא ויפנה אותן.
[בהקשר הזה חשוב להזכיר שעבודה עם AlwaysOn מחייבת שה- DB יהיה ב- Full recovery model – כלומר, נדרשת פעולת BACKUP LOG כדי לפנות רשומות מה- transaction log].

מה הבעייה בזה? אם נגמר המקום ב- transaction log של ה- primary, לא ניתן יהיה לבצע פעולות CRUD על סוגיהן ופעולות DDL מול ה- primary. וכמו שאמרנו – בעיות בקצב הפינוי של ה- transaction log ב- secondary יכולות לגרום לזה.

כמה דוגמאות למצבים שבהם זה יכול לקרות:

  • ה-Seconary למטה (או שיש בעיית תקשורת מולו)
    מובן שאם ה- secondary למטה, ה- primary “יאגור” ב- transaction log שלו את כל רשומות הלוג שמתעדות שינויים שהתרחשו ב-primary. למעשה, כל זמן שהן למטה – המידע ימשיך להיאגר.
  • חומרה חלשה ב- Secondary ביחס ל- Primary
    נניח שאתם מפעילים DB גדול מאד והשקעתם ב- primary כך שהוא רץ על מכונת high-end מטורפת, עובד מול מערך אכסון חזק – בקיצור, פאר היצירה. ועבור ה- secondary, שמיועד לשליפות ודו”חות ודברים שבאופן כללי אולי יכולים קצת להמתין (ואולי אפילו לא למערכות שלכם, אלא למשל משמש data scientists בגופים אחרים) – הקציתם VM מעפן עם 8 ליבות ומערך אכסון חלש.  נניח שעכשיו אתם מריצים פעולת הכנסה מאסיבית של מידע על ה- primary, וה- secondary פשוט לא עומד בקצב.
    הוא יכול לא לעמוד בקצב בכמה אספקטים: גם מבחינת I/O וגם מבחינת CPU. יכול להיות שהוא טוחן CPU בגלל שאילתות כבדות שמורצות מולו, ואז ל- REDO thread(ה-thread ש-“מנגן” את הלוג ב- secondary) מתחרה על זמן ריצה. יכול להיות שקצב הכתיבה לדיסק איטי, – או לחלופין שהדיסקים לא עומדים בעומס המשולב שנוצר מהכתיבות (של ה-REDO) ומהקריאות (השאילתות שרצות) וגורמות לקצב איטי. כל אלה יכול לגרום ל- transaction log להתנפח ב- primary- ולהגיע למצבים לא רצויים, עד כדי חסימה לפעולות.

    אגב, לפעמים אפשר להגיע ללופ של צרות שמזין את עצמו: למשל, דמיינו שנוצר פיגור ו-backlog ב- primary ב- transaction log. אבל הכל בסדר – מוגדרת גדילה אוטומטית של הלוג בדיוק למקרי החירום האלה ויש לכם מספיק מקום ב- partition. כידוע, גדילה של ה-transaction log דורשת כתיבת אפסים בשטח שמוגדל (בניגוד לגדילה של data files, שאם יש ל-account שמשמש את הסרביס של sql server הרשאות של Perform Volume Maintenence Tasks ב-group policy, יכול להתבצע באופן כמעט מיידי באמצעות sparse files). ברגע שמתבצעת ההגדלה, אז גם פעולת ההגדלה נכתבת ל-transaction log ומתבצעת ב- secondary. אבל מה קורה אם המערך אכסון של ה- primary שלכם מאפשר לכם לכתוב ב- 2GB/sec ולכן הגדרתם גדילה של 50G מהבנה שזה ייקח 25 שניות, ואילו ב- secondary אתם כותבים ב-100MB/sec? הנה דוגמא לצרה שמזינה את עצמה. האיטיות של ה- secondary, גורמת ללוג של ה- primary להתנפח, וההתנפחות הזאת מותאמת לביצועים של ה- primary אבל “דופקת” את הביצועים של ה- secondary.

    מה המסקנה? נכון ש- AlwaysOn מאפשר לנו לעשות offloading, אבל בכל זאת יש השפעות הדדיות שיכולות להיגרם – וחומרה חלשה שמוקצית ל- secondary ביחס ל-primary היא מתכון לצרות

  • נעילות של ה- REDO Thread מול פעולות אחרות שרצות
    בסופו של דבר, ה- secondary “מציית” גם הוא לחוקים של נעילות בהקשרי דטאבייסים. אמנם ה- isolation level שמוגדר הוא מבוסס snapshots (לא כמו ה- READ COMMITTED הדיפולטי, אלא כמו ההתנהגות של SNAPSHOT Isolation Level או של Read Committed Snapshot Isolation Level- שאפשר לקרוא עליהם יותר לעומק פה) אבל זה עדיין לא אומר שאין נעילות.
    למשל, דמיינו שאתם מריצים איזשהו maintenence plan שגרתי של REBUILDלאינדקס ב- primary. אתם אפילו עושים אותו ONLINE כדי למזער את ההשפעה שלו על הפעולות השוטפות שרצות מול הדטאבייס. כדי “לנגן” את הפעולות הללו ב- secondary, צריך לקחת Sch-M. נניח אבל שעכשיו רצה שליפה כבדה ב- secondary…. אז ה-REDO ממתין כדי לקבל את המנעול, ומאחור מתחיל להיווצר backlog ב- primary.
  • שינויים בקבצים של ה-DB
    אם נתיבי הקבצים (Data files) שונים בין ה- primary ל-secondary, כאשר מוסיפים קובץ חדש (למשל, מוסיפים data file) ל- primary, ההוספה שלו ל-secondary לא בהכרח תצליח (למשל, הנתיב לא קיים ב- secondary, או שאין מספיק מקום).  אפקט דומה יכול להיווצר גם בהגדלה של קבצים – מגדילים את הקבצים ב- primary, אבל ב- secondary אין להם מקום לגדול.  למעשה, אם נתיבי הקבצים שונים בין ה- primary ל- secondary, אז זה יכול להיות סרט בפני עצמו: כל הוספה של קובץ תיכשל, ותיקון הבעייה ככה”נ ידרוש הסרת ה- DB מה- availability group, והוספה שלו מחדש ע”י שחזור עם MOVE לקבצים.

    מה המסקנה? רצוי מאד לוודא תאימות בכוננים ובנתיבים בין ה- primary ל- secondary. אחרת, כדאי לזכור את זה וכל שינוי בקבצים לקחת בחשבון את ההשפעות שיהיו על ה- secondary.

  • מחסור בזיכרון בעת עבודה עם In-Memory OLTP
    אחד הפיצ’רים המגניבים (אם אתם לא מכירים) ב- SQL Server הוא In-Memory OLTP. אם אתם עושים בו שימוש, תשמחו לשמוע שהוא נתמך לחלוטין בעבודה עם AlwaysOn. נקודה אבל שחשוב לקחת בחשבון – גודל הזיכרון הזמין.
    In-memory OLTP מתבסס, כמובן משמו, על שמירת הנתונים של הטבלה בזיכרון. הנתונים הללו צריכים להיות בזיכרון גם ברפליקה. אם המפרט של הרפליקה שונה מהמפרט של ה- primary, ולמשל יש שם 64GB של זיכרון לעומת 512GB של זיכרון ב- primary, אז עלולים להגיע למצב לא נעים של Out of memory ברפליקה, שכאמור – הכשלונות הללו יכולים להשפיע על ה-transaction log של ה- primary ולגרום להצטברות מידע. זה מתחבר למה שנאמר מקודם, כאשר יש פער במפרט בין השרתים – רק מחדד את נושא כמות הזיכרון הזמינה כאשר ה-DB שאותו מרפלקים מכיל in-memory tables.

 

ואחרי שראינו דוגמאות – אני רוצה שנפיק מזה איזשהו לקח כללי: ברגע שעושים שימוש ב- AlwaysOn צריך לקחת בחשבון שה- transaction log עומד להתנפח על כל שטות ותקלה קטנה שקרתה מול ה- secondary. גם אם הכל תקין, הכל עובד טוב, יש לכם שרתים חזקים, ה-secondary בכלל נמצא לקישוט ואף אחד אף פעם לא מתחבר אליו מריץ שאילתות מולו (ולכן אין בעיות CPU וה- REDO thread לא ננעל) – תמיד יש סיכוי שיקרה משהו (בעיית תקשורת, שרת שנופל) – וכל דבר כזה בהכרח יגרום ל- transaciton log להתנפח.
ולכן צריך לקחת את זה בחשבון, להקצות מספיק מקום עודף ל-transaction log.
ככלל, אם קרתה לכם תקלה שגרמה להתנפחות ה-transaction log (כי המתנתם ל- secondary שיעלה או משהו כזה), והוא התנפח ב- 10GB, 20GB או 100GB מעבר לנורמה – אל תטרחו לעשות לו shrink אחרי שסידרתם את התקלה. כנראה שהגודל שהוא גדל אליו מייצג כמה שהוא יגדל עבור כל תקלה באורך דומה ובתזמון דומה (עם אותם דברים שרצים ברקע). אז כדאי שתשמרו עליו באותו הגודל, וכך תוכלו לקחת בחשבון את דרישות המקום הללו כשתוסיפו דברים חדשים לאותו הכונן (למשל transaction logs של דטאבייסים חדשים).

Full Recovel Model

אמנם זה קשור קצת לסעיף הקודם, אבל זה משהו שצריך לקחת בחשבון בפני עצמו – כדי להפעיל AlwaysOn חייבים לעבוד עם Full Recovery Model. המשמעות של זה היא שאם עבדתם קודם ב- Simple recovery model, תצטרכו לדאוג לתהליך שמבצע גיבוי ל-transaction log (או לכל הפחות ריקון ל-transaction log ע”י גיבוי ל-NUL). אם עבדתם ב- Bulk Recovery Model, אמנם דאגתם מקודם לגיבויי transaction log –אבל עכשיו לא תהנו יותר מ- minimal logging בפעולות רלוונטיות.

למי שלא מכיר, minimal logging, זאת אפשרות שקיימת כשעושים שימוש ב- simple recovery model או ב- bulk recovery model, ומאפשרת ל- SQL Server לכתוב ל-transaction log רק מידע הכרחי ל-recovery לנקודת הזמן האחרונה, ולא ל any point in time. או במילים אחרות, ע”י זה שמצמצמים את הדרישות (לא מאפשרים לשחזר לכל נקודה בזמן, אלא רק לנקודה העדכנית ביותר), אפשר לצמצם את המידע שנכתב ל-transaction log עבור פעולות מסויימות, ולצמצם אותו באופן משמעותי (כך שלמעשה יירשמו רק דברים הכרחיים – למשל אילקוצים).

אם אתם ב- Simple / Bulk-logged recovery model אתם מרגישים את ההשפעות של זה במקרים הבאים (עד כדי תנאים מסויימים): פעולות שעושות שימוש ב- BULK INSERT / (SqlBulkCopy), פעולות SELECT INTO, יצירת אינדקסים ו-REBUILD לאינדקסים ועוד כמה דברים.

אז למה אני מזכיר את זה בהקשר הזה? כי דברים יכולים להשתבש בשתי רמות: יכול להיות שדברים מסויימים יהיו איטיים יותר (כי הן ייצרו יותר IO של כתיבה ל- transaction log) ובוודאות פעולות שהיו קודם minimal logged ואחרי שתעברו ל- full לא יהיו – ייקחו יותר נפח ב- transaction log.

בעוד שמי שעושה הרבה הכנסות של מידע ושימוש אינטנסיבי ב-BULK INSERT כנראה מכיר את הכמויות שהוא מכניס, ואת הנפח שהן מייצרות ב- transaction log, נקודה שבה זה יכול “לתפוס בהפתעה” היא העבודה עם אינדקסים (CREATE, REBUILD וכו’) – שאם לא ידעתם קודם לכן, יכולות להיות מאד אינטנסיביות מבחינת כמות המידע שנכתב ל-transaction log, וזה כמובן מורגש יותר ככל שהטבלה גדולה יותר.
הרבה פעמים הנקודות שבהם זה מורגש הכי הרבה הוא איזשהו maintenence plan שבועי שעושה REBUILD לאינדקסים שצברו יותר מדי פרגמנטציה. אם נרצה להקטין את היקף הפעילות של ה-REBUILD לאינדקס, וכך גם להקטין את הגודל שנכתב ל-transaction log ואת זמן הריצה – כדאי מאד לחשוב על partitioning של טבלאות, תוך כמובן הקפדה (ככל הניתן) שאינדקסים יהיו aligned ל-partitioning שעושים – וכך אפשר להתאים את הסקריפטים כך שה-REBUILD יתבצע ברמת ה- partition הבודד שבו הפרגמנטציה גבוהה. בטבלאות שעיקר הכנסת המידע הוא “לסוף” (טבלאות של אירועים למינהם), אז בד”כ יהיה partition אחד “חם” (מבחינת ההכנסות) והאחרים “קרים” – שלא נדרשת מולם עבודת תחזוקה על האינדקסים.

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

Windows Server Failover Clustering (WSFC)

AlwaysOn עושה שימוש במנגנון ה- clustering של windows כדי לקבל שירותים שהכרחיים להתנהגות של cluster. בניגוד ל- clustering היותר וותיק של SQL Server, שעשה שימוש גם בפיצ’רים של shared disks (או mirrored disks), השימוש של AlwaysOn ב-WSFC הוא רק בשביל השירותים הבאמת בסיסיים: החזקת המשאבים המשותפים (ה- availability group), ניהול Quorum ומניעת brain-split והחזקת ה- listener (וקביעה אצל מי הוא נשמר).

מאחורי הקלעים, יש איזשהו DLL של SQL Server שמאורח ב- WSFC ומממש את הממשק שלו, ומתקשר מול ה-process של SQL Server כשנדרש. עם זאת, יש לזה מס’ השלכות: אם למשל תעשו ריסארט לסרביס של SQL Server כאשר מאופשר AlwaysOn – אתם תראו בלוג של SQL Servere הודעה שהוא לא מרים את הדטאבייסים שלוקחים חלק ב- AlwaysOn וממתין לטריגר מ-WSFC כדי להרים אותם. ה-“טריגר” הזה ניתן אחרי ש-WSFC מבין מה המצב שלו בהקשרי ה- cluster ומה התפקיד שלו, ואז אומר ל-SQL Server להרים את הדטאבייסים כנדרש.

אז מה יכול להשתבש?

  • הדטאבייס לא עולה כי אין Quorum
    כדי שה-cluster יתפקד, ויידע שהוא יתפקד, לכל חבר ב-cluster יש “קול”, ואחת לכמה זמן הוא שולח heartbeat לכל החברים ל- cluster ומספר להם שהוא בסדר ומרגיש טוב. כדי ש- node בודד ב- cluster יעבוד, הוא רוצה שיהיה לו quorum: כלומר שהוא מקבל את ה-“הצבעות” האלה ממספיק (נדבר עוד מעט על מה זה ‘מספיק’ –אבל ככלל מדובר ברוב של החברים ב- cluster) מהחברים ב- cluster. אם יש לו quorum, הוא יודע שהוא יכול לעלות ולהיות בטוח בתפקיד שלו (כלומר, להיות בטוח שהוא primary או secondary. בפרט, המטרה היא למנוע תרחיש של “brain-split”: מצב שבו יש שני nodes ששניהם חושבים שהם ה- primary. אם כל node צריך רוב של ה- cluster שיראה אותו ברגע נתון ויסכים איתו על התפקיד שלו, אז מצב של brain-split לא אמור לקרות, כי לפחות אחד מאלה שחושבים שהם ה- primary לא יהיה לו רוב שיסכים איתו והוא לא יעלה.

    אז איך זה יכול להשתבש? בגדול, בתרחיש שאמרנו – לא מעניין אותנו Quorum. הגדרנו cluster, יש לנו primary בודד, אין automatic failover אלא רק forced failover ולכאורה לא אמור להיות לנו אכפת מכל הסיפור. אולם, מכיוון שבתאוריה כן יכול להתבצע failover, אז כל החוקים של המנגנון הזה תקפים. וכן, יכול להיות שלא יהיה quorum, ובמקרה כזה הדטאבייס לא יעלה.

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

    • לא לעשות שימוש ב- Windows Server 2008 (R2)
      אם אתם משתמשים ב- Windows Server 2008 R2 – תשתדרגו. בלי קשר, הגיע הזמן. אתם לא יכולים לעבוד גם עם SQL Server 2016 (וחבל).
      וספיציפית, בהקשר הזה – אין לכם פיצ’ר חשוב שנקרא Dynamic quorum. בפרט זה אומר שאם אתם עם תרחיש של שני nodes (שמראש הוא לא בריא במיוחד – כי מס’ זוגי של votes הוא לא טוב) – אם אתם מורידים את ה- secondary לתחזוקה או שיש לו תקלה או משהו בסגנון – איבדתם quorum וה- primary לא יעבוד.
      זאת בניגוד ל- Windows Server 2012 ומעלה, עם הפיצ’ר של dynamic quorum, שמעדכן את ההצבעות לפי ה- nodes שחיים ברגע זה. כך שאם ה-secondary יורד (או אפילו אם יש כמה שרתים, והם יורדים אחד אחד) – ההצבעות מתעדכנות כך שהוא לא נספר במספר ההצבעות הכולל, מה שמאפשר לשמר quorum עד ל-“last man standing”, כלומר עד למצב שבו יש רק node אחד שחי (בתנאי כמובן שאין אף משאב הכרחי, כמו דיסק הכרחי, ב- nodes אחרים – מה שמתקיים בתרחיש שלנו).
    • לשים Witness (למשל, File share witness)
      כדי שה- cluster שלנו לא יהיה תלוי רק בשני nodes, וכדי להבטיח מצב שלא נגיע למצבים לא נעימים שבהם אין quorum ו-SQL Server לא עולה (למרות שהכל תקין), נרצה לצרף ל- cluster שלנו איזשהו witness, רצוי אחד ש(כמעט) תמיד למעלה, בעל זמינות גבוהה, שכל ה- members ב- cluster רואים אותו – והוא יוכל לסייע לזמינות ה- cluster. כל אחד מה- nodes יכתוב אליו את המידע, ועצם היכולת לראות אותו ולקרוא את המידע מהווה הצבעה שמאפשרת לשמר quorum.
      בתהליך ההגדרה של ה- cluster נרצה לבחור ב-quorum configuration שמבוסס על Node  and File Share majority ונרצה להגדיר share שרץ על תשתית שאנחנו סומכים עליה, רצוי איזשהו share שרץ על מערך אכסון שמהווה תשתית קריטית בארגון, כך שאנחנו יודעים שהוא בסבירות גבוהה מאד יהיה תמיד למעלה.
      בניגוד לגרסאות קודמות שבהם היו מצבים שהגדרת file share הייתה יכולה לשחק לרעתנו (למשל, לעבור ממספר אי זוגי להצבעות למספר זוגי), ב- Windows Server 2012 תמיד כדאי להגדיר – הוא יודע לבד מתי כדאי לעשות שימוש ב- share כ-witness פעיל ומתי לא.
    • לדעת איך להרים cluster בלי quorum
      למקרה שדברים משתבשים, בתרחיש שלנו אנחנו יודעים שאין automatic failover, ולכן אנחנו יכולים להרשות לעצמנו להרים את ה-primary (בהנחה שלא עשינו מאיזושהי סיבה manual failover ל- secondary) ולדעת ששום דבר לא נדפק – ואז לפתור את הבעיות שמונעות את ה- Quorum. לכן מומלץ לקרוא את ההוראות האלה, כדי לדעת ליישם אותם במקרה הצורך.
  • הדטאבייס ב- Resolving בגלל שהוא איבד Lease
    אחד המנגנונים שמשמשים את SQL Server כדי למנוע brain-split הוא תקשורת תמידית עם ה- WSFC. מה שקורה זה ש-SQL SERVER מקבל מ-WSFC פעם בזמן נתון “lease” שתקף לאיזשהו זמן (שעוד לפניו SQL SERVER מנסה לחדש אותו). אם הזמן הזה פג, וה- lease לא חודש, SQL Server מניח שקרה משהו לא תקין במערכת ומוריד את הדטאבייסים ב- AG הרלוונטי. לא נעים. אחרי שהכל חוזר להיות תקין, וה-lease מתקבל מחדש, יתבצע תהליך של recovery לדטאבייסים והם יחזרו לתקינות.

    על פניו, SQL Server נוקט בצעדים שלא יקרה סתם lease-timeout “בטעות”: פעם ברבע מהזמן שמוגדר ל- lease timeout, ה-thread שאחראי לחדש את ה- lease (שרץ גם ב-priority גבוהה יותר) רץ ומנסה לעשות את זה.  התהליך עצמו פשוט מאד, ולא כבד בכלל- מערב קריאה וכתיבה מ-shared memory. וגם את זה, יש לו הזדמנות לעשות כמה פעמים לפני שמגיע ה- lease timeout.

    אז תשאלו איך זה יכול להשתבש? הנה תרחיש שנתקלתי בו שבו דברים לא קרו כמצופה: SQL Server נתקל ב- assertion error, שגורר לקיחת dump ע”י פרוסס חיצוני ש- SQL Server מעלה. הפרוסס החיצוני הזה עושה pause לכל ה- threads של SQL Server ולוקח את ה- dump. בפרט, במצבים מסויימים כתיבת ה- dump הזה יכולה גם היא לקחת איזשהו זמן, והזמן הזה היה ארוך יותר מה- lease timeout (בדיפולט, 20 שניות). כשה- dump הסתיים, ה- threads חזרו לרוץ, אבל כמובן שברגע שהתבצעה בדיקה ל-lease timeout (כנראה עוד לפני שה-thread שאחראי על זה חידש את ה- lease)  הדטאבייסים כולם ירדו. כמובן שאז התחדש ה- lease, והם הועלו מחדש, אבל ה-recovery לקח עוד 2-3 דקות כי היו כמה דברים שרצו – והנה אנחנו מגיעים ל- downtime לא רצוי ל-primary, שבאופן רגיל לא היה קורה באותו האורך (היינו חווים 20 שניות של “תקיעה” כמובן, בזמן שה- dump נלקח, אבל הן לא היו מתפתחות ל-4-5 דקות).
    מה אפשר לעשות? תחת הגדרות ה- cluster, להיכנס ל-properties של ה- AG שמופיע שם, ושם תחת הטאב properties אפשר להעלות את ה- lease timeout ואת ה- health check timeout

    אגב, אם אתם משתמשים ב- AlwaysOn גם עבור automatic failover, ניתן לשלוט מה הטריגרים השונים של “מצב ה- instane” שגורמים ל-automatic failover ע”י בחירה בין הרמות השונות. ניתן לקרוא על זה כאן, תחת הפירוט ל- FAILURE_CONDTION_LEVEL.

  • ההרשאות של ה- Cluster account “נדפקו”
    צריך לקחת בחשבון שכאשר מוסיפים cluster, נוצר cluster account ב- ActiveDirectory, בדומה ל- machine accounts של מחשבים שמצורפים ל-AD. מומלץ בחום לוודא שה-cluster account הזה מקבל אותו יחס של חשבונות שרתים, ולמנוע מצב שבטעות מישהו מחק אותו או דפק אותו במסגרת “ניקיונות” תקופתיים.

סיכום

AlwaysOn הוא מנגנון מעולה, והאפשרות להשתמש בו להרמת readable secondary replica זה דבר שימושי מאד. עם זאת, על אף שמקריאה בסיסית על זה עלול להתקבל הרושם שכאשר מגדירים Asynchronous commit ו-Forced failover (חובה כאשר זה async commit) לא יכולות ולא יהיו השפעות על ה- primary בשום מצב – לא כך הדבר, ויש השפעות שיכולות להיות על ה-primary. המטרה שלי הייתה לסקור את הנקודות העיקריות שבהם זה יכול להשפיע, כדי שתדעו ותוכלו להיערך בהתאם בין אם ע”י צעדים מונעים, ובין אם ע”י ניטור שיוכל לספק התרה מראש על חלק מהבעיות.

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

בהצלחה!

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

Leave a Reply

Your email address will not be published. Required fields are marked *