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

למה הראשי באמת ממתין

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

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

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

רוחב פס אינו השהיית הלוך ושוב

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

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

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

קראו את מצב הרפליקה לפני שאתם משנים משהו

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

SELECT ag.name AS ag_name, drs.database_id, drs.synchronization_state_desc,
       drs.log_send_queue_size, drs.redo_queue_size, drs.secondary_lag_seconds
FROM sys.dm_hadr_database_replica_states AS drs
JOIN sys.availability_groups AS ag ON ag.group_id = drs.group_id;

SELECT ar.replica_server_name, ar.availability_mode_desc, ar.failover_mode_desc
FROM sys.availability_replicas AS ar;

התוצאה הראשונה מפרידה בין הובלת לוג ל-redo. log_send_queue_size עולה בזמן ש-redo_queue_size נשאר שטוח פירושו שהלוג לא הגיע; ההפך פירושו שהוא הגיע ושההרצה החוזרת מפגרת. רק המקרה הראשון יושב על מסלול הקומיט.

התוצאה השנייה מאשרת אילו רפליקות באמת מוגדרות כפי שאתם מניחים, כי מצב ששונה באירוע קודם נוטה להישאר משונה ובלי תיעוד. קראו את השורה שמעניינת אתכם ולא את ברירת המחדל של הקבוצה: availability_mode_desc ו-failover_mode_desc הם לכל רפליקה. secondary_lag_seconds קיים רק ב-SQL Server 2016 ואילך, כך שגרסה ישנה יותר משאירה לכם רק את עמודות תור השליחה וה-redo.

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

IF OBJECT_ID('dbo.CommitProbe') IS NULL
    CREATE TABLE dbo.CommitProbe (probe_id int PRIMARY KEY, touched_at datetime2(3));
IF NOT EXISTS (SELECT 1 FROM dbo.CommitProbe WHERE probe_id = 1)
    INSERT INTO dbo.CommitProbe (probe_id) VALUES (1);
SET STATISTICS TIME ON;
BEGIN TRANSACTION;
UPDATE dbo.CommitProbe SET touched_at = SYSUTCDATETIME() WHERE probe_id = 1;
COMMIT TRANSACTION;
SET STATISTICS TIME OFF;

מה קומיט אסינכרוני קונה, ומה הוא עולה

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

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

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

בחרו תיקון שתוכלו להגן עליו אחר כך

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

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

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

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