هل ترغب في تلقي إخطارات بالمحتوى الجديد؟
إلقاء نظرة متعمقة على السجلات
عندما التحقت بـ Amazon بعد إنهاء الدراسة الجامعية، كانت أول تدريبات التحاقي هو الحصول على خادم ويب amazon.com وتشغيله على سطح مكتب المطور الخاص بي. ولم أنجح في ذلك من المحاولة الأولى، ولم أكن متأكدًا من الخطأ الذي ارتكبته. فاقترح علي زميل متعاون البحث داخل السجلات لمعرفة الخطأ الذي وقعت فيه. وللقيام بذلك، أخبرني بأنه يجب علي «نشر ملف السجلات.» كنت مقتنعًا أنهم ينصبون لي فخًا ما أو أنهم يمزحون حول عمليات النشر التي لم أفهمها. فأثناء الدراسة، لم أكن استخدم في التجميع سوى Linux وعنصر التحكم بالمصادر ومحرر النصوص. لذا لم أكن أعرف أن كلمة «نشر» هي في الواقع أمر بطباعة ملف إلى المحطة الطرفية التي يمكنني تغذيتها ببرنامج آخر للبحث عن الأنماط.
أشار إليِّ زميلي بأدوات مثل cat، وgrep، وsed، وawk. وبعدما تزودت بمجموعة الأدوات الجديدة هذه، تعمقت أكثر في سجلات خادم ويب amazon.com في سطح مكتب المطور الخاص بي. وقد تم توجيه تطبيق خادم الويب بالفعل لحذف كل أنواع المعلومات المفيدة الموجودة داخل سجلاته. وقد أتاح لي هذا مراجعة التكوين الذي كنت أفتقده والذي منع خادم الويب من بدء التشغيل، وهو ما كشف لي مكان حدوث العطل، أوأشار إلى موقع انقطاع التواصل مع خدمة نقل البيانات. يتألف موقع الويب من العديد من الأجزاء المتنقلة، التي كانت بالنسبة لي في البداية بمثابة الصندوق الأسود. إلا أنني وبعد التعمق أكثر في النظام، تعلمت كيفية عمل الخادم وكيفية التفاعل مع التبعيات الخاصة به بمجرد النظر في مخرجات الأدوات.
لماذا الأدوات
ما الذي ستقيسه
لتشغيل الخدمات وفقًا للمقاييس العالية فيما يتعلق بزمن الوصول والتوافر، وباعتبارنا مالكي الخدمة، فإننا سوف نحتاج إلى قياس كيفية عمل النظام.
وللحصول على القياس عن بُعد اللازم، يقيس مالكي الخدمات الأداء التشغيلي من مواقع متعددة للحصول على جوانب متعددة حول كيفية عمل الأشياء بشكل شامل. وهذا أمر معقد حتى في البنية البسيطة. وبالتفكير في خدمة يستدعيها العملاء من خلال موازن الأحمال: فإن الخدمة تتحدث عن تخزين مؤقت عن بُعد وعن قاعدة بيانات عن بُعد. ونريد من كل مكون حذف المقاييس الخاصة بسلوكه. كما نريد أيضًا مقاييس حول كيفية فهم كل مكون لسلوك المكونات الأخرى. وعند جمع المقاييس من جميع هذه الجوانب معًا، يمكن لمالك الخدمة تعقب مصدر المشكلات بسرعة والوصول إلى السبب.
توفر العديد من خدمات AWS بشكل تلقائي رؤى تشغيلية حول مواردك. على سبيل المثال، توفر Amazon DynamoDB مقاييس Amazon CloudWatch حول نسب النجاح والخطأ وزمن الوصول، كما هو مُقاس من الخدمة. مع ذلك، عند إنشاء أنظمة تستخدم هذه الخدمات، فسنحتاج إلى رؤية أعمق لمعرفة كيفية عمل النظام. تتطلب الأدوات تعليمات برمجية صريحة تسجل المدة التي تستغرقها المهام الطويلة، وعدد مرات ممارسة بعض مسارات التعليمة البرمجية المحددة، والبيانات التعريفية حول ما كانت تعمل عليه المهمة، وما هي أجزاء المهام التي نجحت أو فشلت. إذا لم يضف فريقًا ما أدوات صريحة، فسيضطر لتشغيل خدماته الخاصة كصندوق أسود.
على سبيل المثال، إذا قمنا بتنفيذ عملية واجهة برمجة تطبيقات خدمة واستدعت معلومات المنتج حسب معرف المنتج، فستظهر التعليمة البرمجية كالمثال التالي. ستبحث التعليمة البرمجية عن معلومات المنتج في مكان التخزين المحلي المؤقت، ثم في مكان التخزين المؤقت عن بُعد وبعد ذلك قاعدة بيانات:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest request) {
// check our local cache
ProductInfo info = localCache.get(request.getProductId());
// check the remote cache if we didn't find it in the local cache
if (info == null) {
info = remoteCache.get(request.getProductId());
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {
info = db.query(request.getProductId());
localCache.put(info);
remoteCache.put(info);
}
return info;
}
فإذا كنت أشغّل هذه الخدمة، فسأحتاج إلى الكثير من الأدوات حول هذه التعليمة البرمجية لأتمكن من فهم سلوكها خلال الإنتاج. وسأحتاج إلى امتلاك القدرة على اكتشاف أخطاء الطلبات البطيئة أو المعطلة وإصلاحها، ومراقبة الاتجاهات والعلامات للتبعيات المختلفة التي تم قياسها أو التي لم تعمل بشكل صحيح. وهنا التعليمة البرمجية ذاتها، مذيلة ببعض الأسئلة التي أحتاج إلى الإجابة عنها حول نظام الإنتاج بشكل عام، أو فيما يتعلق بطلب معين:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest request) {
// Which product are we looking up?
// Who called the API? What product category is this in?
// Did we find the item in the local cache?
ProductInfo info = localCache.get(request.getProductId());
if (info == null) {
// Was the item in the remote cache?
// How long did it take to read from the remote cache?
// How long did it take to deserialize the object from the cache?
info = remoteCache.get(request.getProductId());
// How full is the local cache?
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {
// How long did the database query take?
// Did the query succeed?
// If it failed, is it because it timed out? Or was it an invalid query? Did we lose our database connection?
// If it timed out, was our connection pool full? Did we fail to connect to the database? Or was it just slow to respond?
info = db.query(request.getProductId());
// How long did populating the caches take?
// Were they full and did they evict other items?
localCache.put(info);
remoteCache.put(info);
}
// How big was this product info object?
return info;
}
التعليمة البرمجية للإجابة عن كل هذه الأسئلة (وأكثر) أكبر بقليل من منطق الأعمال الفعلي. يمكن أن تساعد بعض المكتبات في خفض مقدار التعليمة البرمجية للأدوات، ولكن سيظل المطور يطرح أسئلة حول الرؤية التي ستحتاجها المكتبات، لذا يجب أن يستهدف شبكة الأسلاك الموجودة بالأدوات.
عند اكتشاف مشكلة بطلب ما يتدفق من خلال نظام موزع، فسيكون من الصعب فهم ماذا حدث إذا نظرت فقط بالطلب هذا على أساس تفاعل واحد. ولحل اللغز، نجد أنه من المفيد تجميع القياسات معًا بموقع واحد لكل هذا الأنظمة. وقبل فعل هذا، يجب توجيه كل خدمة لتسجيل معرف التتبع الخاص بكل مهمة، ونشره لجميع الخدمات الأخرى المشاركة بهذه المهمة. يمكن جمع مجموعة الأدوات لجميع الأنظمة لمعرف تتبع محدد بعد معرفة الحقيقة كما هو مطلوب، أو بوقت فعلي قريب باستخدام خدمة مثل AWS X-Ray.
التعمّق
تمكّن الأدوات من اكتشاف المشكلات وإصلاحها على مستويات متعددة، من نظرة خاطفة على المقاييس لرؤية ما إذا كانت عيوب ذات دقة عالية ولتشغيل التنبيهات ولتنفيذ تحقيق لاكتشاف أسباب هذه العيوب.
وبمستوى أعلى، يتم تجميع الأدوات إلى مقاييس يمكنها تشغيل التنبيهات وعرضها على لوحات المعلومات. يسمح تجميع المقاييس هذه للمُشغلين بمراقبة معدل الطلب بالكامل، وزمن وصول عمليات استدعاء الخدمات ومعدلات الأخطاء. تسمح لنا هذه التنبيهات والمقاييس بمعرفة التغيرات والعيوب التي يجب تقصيها.
فبعد مراجعة عملية اكتشاف العيوب، نحتاج إلى تحديد سبب حدوث هذا الخلل. وللإجابة عن هذا السؤال، نعتمد على المقاييس التي توصلنا إليها ولو بمزيد من الأدوات. وبتوجيه الوقت المستغرق في تنفيذ أجزاء عدة من تقديم خدمة الطلب، يمكننا تحديد أي جزء أكثر بطئًا من الطبيعي بالعملية أو أخطاء التشغيل الأكثر حدوثًا.
أثناء تجميع المؤقتات والمقاييس التي قد تساعدنا في معرفة الأسباب أو إبراز منطقة التقصي، لأنهم غالبًا لا يقدمون تفسيرًا كاملًا. على سبيل المثال، قد نتمكن من خلال المقاييس من معرفة أن الأخطاء تأتي من عملية واجهة برمجة تطبيقات، لكن قد لا تظهر المقاييس خصائص معينة حول سبب فشل العملية. في هذه الحالة، ننظر في الصف، وبيانات السجل التفصيلية التي حذفت بواسطة الخدمة لهذا الإطار الزمني. وعندئذٍ ستظهر سجلات الصف مصدر المشكلة — إما الخطأ المحدد الذي يحدث، أو جوانب خاصة للطلب تعمل على تشغيل حالة التخزين المؤقت.
طريقة بناء الأدوات
تتطلب الأدوات الترميز. يعني هذا أنه عند تنفيذ وظيفة جديدة، نحتاج إلى وقت لإضافة رمز إضافي للإشارة لما حدث، سواء نجح هذا أم فشل، والوقت المستغرق. وحيث إن التوجيه هو المهمة الشائعة للترميز، فإن الممارسات التي ظهرت لدى Amazon عبر السنين للتعريف بالأنماط الشائعة: المعايرة لمكتبات بناء الأدوات والمعايرة لإعداد تقارير المقاييس على أساس السجلات المنظمة.
تساعد المعايرة مكتبات بناء أدوات المقاييس مؤلفي المكتبات من إعطاء عملاء المكتبات رؤية حول كيفية تشغيل المكتبة. على سبيل المثال، يشيع استخدام هذا مع عملاء HTTP المدمجين مع هذه المكتبات الشائعة، لذا في حالة قيام فريق خدمة باستدعاء لخدمة أخرى عن بُعد، فسيحصل على الأدوات بشكل تلقائي.
عند تشغيل تطبيق موجه وتنفيذ عمل، تُكتب بيانات القياس عن بُعد الناتجة بملف سجلات منظم. وبشكل عام، يتم الحذف في حالة إدخال سجل واحد لكل «وحدة عمل»، سواء كان هذا طلب لخدمة HTTP، أو رسالة سُحبت من قائمة الانتظار.
في Amazon، لا يتم تجميع عمليات التوجيه في التطبيق، كما أنها تفرغ بشكل دوري في نظام تجميع المقاييس. تيتم كتابة جميع المؤقتات والعدادات الخاصة بكل جزء من العمل بسجل ملفات. ومن هذه النقطة، تتم معالجة السجلات وتتم حوسبة مقاييس التجميع بعد معرفة الحقيقة بواسطة نظام آخر. وبهذه الطريقة، ننتهي من كل شيئ بداية من مقاييس التجميع عالية المستوى وحتى البيانات التفصيلية للكشف عن العيوب وإصلاحها، جميعها بنهج واحد حتى رمز التوجيه. نسجل أولًا في Amazon، ثم نخرِّج مقاييس التجميع لاحقًا.
بناء الأدوات من خلال السجلات
عادة ما نوجه خدماتنا عامة بحذف نوعين من بيانات السجل: بيانات الطلب وبيانات إصلاح الأخطاء. تتمثل بيانات سجل الطلب عادة كإدخال سجل منظم لكل وحدة عمل. تحتوي هذه البيانات على خصائص حول الطلب ومن قام بإنشاءه، وما سبب إنشاءه، وعدادات حول عدد مرات حدوث الأشياء ومؤقتات حول كم استغرقت الأشياء. يخدم سجل الطلب كسجل تدقيق وتتبع لكل شيئ حدث في الخدمة. تتضمن بيانات إصلاح الأخطاء بيانات غير مهيكلة وبيانات مهيكلة بصورة غير منضبطة لما قد تحذفه عملية إصلاح الأخطاء أيًا كانت للتطبيقات. عادة تكون هذه إدخالات سجل غير مهيكل مثل خطأ Log4j أو سطور سجل التحذيرات. في Amazon عادة يتم فصل هذين النوعين إلى ملفات سجل منفصلة، وبشكل جزئي لأسباب تاريخية، لكن أيضًا لأنها يمكن أن تكون ملائمة لإجراء تحليل بتنسيق إدخال سجل متجانس.
يعالج وكلاء مثل CloudWatch Logs Agent كلا النوعين من بيانات السجل بالوقت الفعلي كما يتم شحن السجلات إلى CloudWatch Logs. وعليه، يخرج عن CloudWatch Logs مقاييس تجميع حول الخدمة في الوقت الفعلي. تقرأ تنبيهات Amazon CloudWatch مقاييس التجميع كما تُشغِّل التنبيهات.
ورغم التكلفة العالية للتسجيل بمثل هذه التفاصيل حول كل طلب، نجد في Amazon أن ذلك مهم جدًا بطريقة لا تُصدق. بعد ذلك، نحتاج إلى تقصي نقرات التوافر أوقات ذروة زمن الوصول والمشكلات المتعلقة بالتقارير التي أعدها العميل. بدون السجلات التفصيلية، لا يمكننا إعطاء العملاء إجابات، كما أننا لن نتمكن من تحسين خدمتهم.
التعمق في التفاصيل
موضوع المراقبة والتنبيه أمر هام. في هذه المقالة، لن نُغطي موضوعات مثل إعداد حدود التنبيهات وضبطها، وتنظيم لوحات المعلومات التشغيلية، وقياس الأداء من جانب الخادم ومن جانب العميل، والتشغيل المتواصل لتطبيقات «canary»، واختيار النظام المناسب للاستخدام لتجميع المقاييس وتحليل السجلات.
تركز هذه المقالة على الحاجة إلى توجيه تطبيقاتنا لإنتاج بيانات قياس مناسبة جديدة. سنصف الأشياء التي تبذل الفِرق في Amazon جهدها لتضمينها (أو استبعادها) عند توجيه تطبيقاتها.
أفضل ممارسات سجل الطلبات
في هذا القسم سوف أصف العادات الجيدة التي تعلمناها مع مرور الوقت في Amazon حول تسجيل بياناتنا المنظمة «لكل وحدة عمل». يحتوي السجل الذي يفي بهذه المعايير على عدادات تمثل عدد مرات حدوث الأمور، ومؤقتات تحتوي على المدة التي استغرقتها الأمور، والخصائص التي تتضمن بيانات التعريف الخاصة بكل وحدة عمل.
• إصدار إدخال واحد من سجل الطلبات لكل وحدة عمل. عادة ما تكون وحدة العمل طلبًا استلمته خدمتنا أو رسالة تسحبها من قائمة انتظار. نحن نكتب إدخال سجل خدمة واحد لكل طلب تستلمه خدمتنا. ونحن لا نجمع وحدات عمل متعددة مع بعضها البعض. بهذه الطريقة، عندما نستكشف أخطاء طلب غير ناجح ونصلحها، يكون لدينا إدخال سجل واحد للنظر فيه. يحتوي هذا الإدخال على معلمات الإدخال المعنية حول الطلب لمعرفة ما كان يحاول إجراءه، ومعلومات حول هوية الوسيط، وجميع معلومات التوقيت والعداد في مكان واحد.
• إصدار ما لا يزيد عن إدخال واحد من سجل الطلبات لطلب معين. خلال تنفيذ خدمة غير محظورة، قد يبدو من الملائم إصدار إدخال سجل منفصل لكل مرحلة في مسار المعالجة. وبدلًا من ذلك، حققنا مزيدًا من النجاح في استكشاف الأخطاء بهذه الأنظمة وإصلاحها عن طريق تثبيت مؤشر على «كائن مقاييس» واحد بين المراحل في المسار، ثم سلسلة المقاييس في صورة وحدة بعد اكتمال جميع المراحل. إن وجود إدخالات سجل متعددة لكل وحدة عمل يجعل تحليل السجل أكثر صعوبة، ويزيد من تكلفة التسجيل الباهظة بالفعل بمضاعفتها. فإذا كنا نكتب خدمة جديدة غير محظورة، فإننا نحاول تخطيط دورة حياة تسجيل المقاييس مقدمًا، حيث يصبح من الصعب جدًا إعادة تشكيلها وإصلاحها لاحقًا.
• تقسيم المهام طويلة الأمد إلى عدة إدخالات سجل. خلافًا للتوصية السابقة، إذا كانت لدينا مهمة طويلة الأمد أو مكونة من عدة دقائق أو مكونة من عدة ساعات أو شبيهة بمسار عمل، فقد نقرر إصدار إدخال سجل منفصل بشكل دوري حتى نتمكن من تحديد ما إذا كان يجري إحراز تقدم أو تحديد مكان تباطئه.
• تسجيل تفاصيل حول الطلب قبل إجراء أمور مثل التحقق من الصحة. لقد اتضح لنا أنه لأجل استكشاف الأخطاء وإصلاحها وتسجيل عمليات التدقيق، فإنه من المهم تسجيل معلومات كافية حول الطلب حتى نعرف ما كان يحاول إنجازه من أجل مهام. كما اتضح لنا كذلك أنه من المهم تسجيل هذه المعلومات في أقرب وقت ممكن، قبل أن تتاح الفرصة لرفض الطلب من خلال عملية التحقق من الصحة أو المصادقة أو منطق التقييد. فإذا كنا نسجل المعلومات من الطلب الوارد، فإننا نحرص على تصحيح المدخلات (الترميز، والإلغاء، والاقتطاع) قبل تسجيله. على سبيل المثال، نحن لا نرغب في تضمين سلاسل طولها 1 ميجابايت في إدخال سجل الخدمة الخاص بنا إذا قام الوسيط بتمرير واحدة. لأن ذلك سيؤدي إلى المخاطرة بملء الأقراص الصلبة الخاصة بنا وتكلفتنا أكثر من المتوقع بشأن سعة تخزين السجل. ومن الأمثلة الأخرى على التصحيح هو تصفية أحرف التحكم ASCII أو تسلسل الإلغاء ذي الصلة بتنسيق السجل. فقد يكون الأمر مربكًا إذا مرر الوسيط إدخال سجل خدمة خاص به، وكان قادرًا على إدراجه في سجلاتنا! راجع أيضًا: https://xkcd.com/327/
• تخطيط طريقة للتسجيل بإسهاب متزايد. لاستكشاف بعض أنواع المشكلات وإصلاحها، لن يحتوي السجل على تفاصيل كافية حول الطلبات ذات المشكلات لمعرفة السبب وراء عدم نجاحها. قد تكون هذه المعلومات متاحة في الخدمة، ولكن قد يكون حجم المعلومات أكبر بكثير مما يبرر التسجيل طوال الوقت. وقد يكون من المفيد الحصول على مقبض تكوين يمكنك إدارته لزيادة إسهاب السجل بشكل مؤقت أثناء التحقيق بشأن إحدى المشكلات. فقد تدير المقبض على مضيفين فرديين، أو من أجل عملاء فرديين، أو عند معدل اختيار عينات عبر الأسطول. وعند الانتهاء لابد أن تتذكر إعادة المقبض لأسفل.
• إبقاء أسماء المقاييس قصيرة (ولكن ليست قصيرة للغاية). استخدمت Amazon نفس تسلسل سجل الخدمة لأكثر من 15 عامًا. في هذا التسلسل، يتم تكرار اسم كل عداد ومؤقت بنص عادي في كل إدخال سجل خدمة. وللمساعدة في تقليل النفقات العامة للتسجيل، فإننا نستخدم أسماء قصيرة، ولكنها وصفية، للمؤقتات. بدأت Amazon في اعتماد تنسيقات تسلسل جديدة تستند إلى بروتوكول تسلسل ثنائي يُعرف باسم Amazon Ion. وفي نهاية المطاف، من المهم اختيار تنسيق يمكن أن تفهمه أدوات تحليل السجلات ويكون فعالًا كذلك في إجراء التسلسل وإلغاء التسلسل والتخزين قدر الإمكان.
• التأكد من أن وحدات تخزين السجل كبيرة بما يكفي للتعامل مع التسجيل عند أقصى حد للإنتاجية. إننا نختبر قدرة تحمل خدماتنا بأقصى قدر من الحمل المستمر (أو حتى الحمل الزائد) لمدة ساعات. حيث نحتاج إلى التأكد من أنه عندما تتعامل خدمتنا مع حركة بيانات زائدة، تستمر الخدمة في التمتع بالموارد اللازمة لشحن السجلات خارج الصندوق بمعدل إنتاجها لإدخالات سجل جديدة، أم أن الأقراص الصلبة ستمتلئ في النهاية. يمكنك أيضًا تكوين التسجيل بحيث يحدث في قسم نظام ملفات مختلف عن القسم الجذر، حتى لا ينهار النظام في مواجهة عمليات التسجيل الزائدة. وسنناقش لاحقًا إجراءات تخفيف أخرى بشأن هذا، مثل استخدام عملية اختيار العينات الديناميكية التي تتناسب مع الإنتاجية، ولكن بغض النظر عن الاستراتيجية المتبعة، فمن المهم اختبارها.
• التفكير في سلوك النظام عند امتلاء الأقراص. عند امتلاء قرص أحد الخوادم، فسوف يتعذر التسجيل في القرص. وعندما يحدث ذلك، هل من المفترض أن تتوقف الخدمة عن قبول الطلبات أم تترك السجلات وتستمر في العمل دون مراقبة؟ إن العمل دون تسجيل أمر محفوف بالمخاطر، لذلك نختبر الأنظمة للتأكد من اكتشاف الخوادم التي تحتوي على أقراص ممتلئة بالكامل تقريبًا.
• مزامنة الساعات إن مفهوم «الوقت» في الأنظمة الموزعة معقد بشكل ملحوظ. ونحن لا نعتمد على مزامنة الساعات في اللوغاريتمات الموزعة، ولكنها تكون ضرورية لفهم السجلات. إننا ندير برامج خفية مثل Chrony أو ntpd لمزامنة الساعات، ونراقب الخوادم بحثًا عن انجراف للساعة. ولتسهيل ذلك، راجع Amazon Time Sync Service.
• إصدار تعدادات صفرية لمقاييس التوافر. رغم أن تعدادات الأخطاء مفيدة، إلا أن النسب المئوية للأخطاء يمكن أن تكون مفيدة هي الأخرى. للاستعانة بمقياس «النسبة المئوية للتوافر»، هناك استراتيجية وجدنا أنها مفيدة تتمثل في إصدار 1 عند نجاح الطلب و0 عند عدم نجاحه. عندئذ يكون الإحصاء «المتوسط» للمقياس الناتج هو معدل التوافر. إنّ إصدار نقطة بيانات تبلغ 0 عن عمد يمكن أن يكون مفيدًا في حالات أخرى كذلك. فعلى سبيل المثال، إذا أجرى أحد التطبيقات انتخابًا لقائد، فإن إصدار 1 بشكل دوري عندما تكون إحدى العمليات هي القائد، و0 عندما لا تكون العملية هي القائد يمكن أن يكون مفيدًا في مراقبة سلامة المتابعين. وبهذه الطريقة إذا توقفت عملية عن إصدار 0، فسيكون من السهل معرفة أنه قد حدث بها عطل، وأنها لن تكون قادرة على تولي زمام الأمور إذا حدث شيء للقائد.
• تسجيل مدى التوافر وزمن وصول التبعيات. لقد وجدنا هذا مفيدًا بشكل خاص في الإجابة على أسئلة «لماذا كان الطلب بطيئًا؟» أو «لماذا فشل الطلب؟» بدون هذا السجل، يمكننا فقط مقارنة الرسوم البيانية للتبعيات مع الرسوم البيانية للخدمة، وتخمين ما إذا كان ارتفاع واحد في زمن الوصول لخدمة تابعة قد أدى إلى فشل الطلب الذي نحقق فيه. تقوم العديد من أطر عمل الخدمات والعملاء بإدخال المقاييس تلقائيًا، ولكن الأطر الأخرى (مثل AWS SDK، على سبيل المثال)، تتطلب أدوات يدوية.
• الخروج بمقاييس التبعية لكل استدعاء، لكل مورد، لكل رمز حالة، إلخ. إذا تفاعلنا مع نفس التبعية عدة مرات في نفس وحدة العمل، فسنضمّن مقاييس لكل استدعاء على حدة، ونوضح المورد الذي كان يتفاعل معه كل طلب. على سبيل المثال، عند استدعاء Amazon DynamoDB، وجدت بعض الفرق أنه من المفيد إدراج مقاييس التوقيت وزمن الوصول لكل جدول، بالإضافة إلى رمز الخطأ، وحتى عدد مرات إعادة المحاولة. هذا يجعل استكشاف الحالات التي تكون فيها الخدمة بطيئة أسهل من إعادات المحاولة بسبب فشل عمليات التحقق المشروط وإصلاحها. كشفت هذه المقاييس أيضًا عن حالات كانت فيها الزيادات المتصورة من العملاء لزمن الوصول ناتجة فعليًا عن إعادات المحاولة أو ترقيم الصفحات من خلال مجموعة النتائج، وليس بسبب فقدان الحزمة أو زمن الوصول إلى الشبكة.
• تسجيل أعماق قائمة الانتظار بالذاكرة عند الوصول إليها. إذا تفاعل الطلب مع قائمة انتظار، وسحبنا كائنًا منه، أو وضعنا شيئًا ما فيه، فنحن بذلك نسجل عمق قائمة الانتظار الحالي في كائن المقاييس أثناء وجودنا فيه. بالنسبة لقوائم الانتظار في الذاكرة، تُعد هذه المعلومات رخيصة جدًا للحصول عليها. بالنسبة لقوائم الانتظار الموزعة، قد تتوفر بيانات التعريف هذه مجانًا في استجابات استدعاءات واجهة برمجة التطبيقات. سيساعد هذا التسجيل في العثور على تراكمات ومصادر زمن الوصول في المستقبل. بالإضافة إلى ذلك، عندما نأخذ الأشياء من قائمة الانتظار، فنحن نقيس بذلك المدة التي انتظرتها الأشياء في قائمة الانتظار. وهذا يعني أننا بحاجة إلى إضافة مقياس «وقت الإدراج» الخاص بنا إلى الرسالة قبل إدراجها في المقام الأول.
• إضافة عداد إضافي لكل سبب خطأ. النظر في إضافة رمز يحسب سبب الخطأ المحدد لكل طلب لم يحقق نجاحًا. سيتضمن سجل التطبيقات المعلومات التي أدت إلى الفشل، ورسالة استثناء مفصلة. ومع ذلك، فقد وجدنا أيضًا أنه من المفيد رؤية الاتجاهات في أسباب الخطأ في المقاييس بمرور الوقت دون الحاجة إلى استخراج تلك المعلومات في سجل التطبيقات. من السهل البدء بمقياس منفصل لكل فئة استثناء من الفشل.
• تنظيم الأخطاء حسب فئة السبب. إذا تم تجميع جميع الأخطاء في نفس المقياس، فسيصبح المقياس مشوشًا وغير مفيد. على الأقل، وجدنا أنه من المهم فصل الأخطاء التي كانت "خطأ العميل" عن الأخطاء التي كانت "خطأ الخادم". علاوة على ذلك، قد يكون المزيد من التقسيم مفيدًا. على سبيل المثال، في DynamoDB، يمكن للعملاء تقديم طلبات الكتابة المشروطة التي تُرجع خطأ إذا كان العنصر الذي يقوم بتعديله لا يتطابق مع الشروط المسبقة في الطلب. تعتبر هذه الأخطاء مدروسة ونتوقع حدوثها من حين لآخر. بينما تكون أخطاء "الطلب غير الصالح" من العملاء هي على الأرجح الأخطاء التي نحتاج إلى إصلاحها.
• تسجيل بيانات التعريف المهمة حول وحدة العمل. في سجل القياس المنظم، نقوم أيضًا بإدراج بيانات تعريف كافية حول الطلب حتى نتمكن لاحقًا من تحديد ممن كان الطلب وماذا كان الغرض وراء الطلب. يتضمن ذلك بيانات التعريف التي يتوقع العميل منا إدراجها في سجلنا عندما يتعاملون مع المشكلات. على سبيل المثال، تسجل DynamoDB اسم الجدول الذي يتفاعل معه الطلب، وبيانات التعريف مثل ما إذا كانت عملية القراءة متسقة أم لا. ومع ذلك، فإنه لا يسجل البيانات التي يتم تخزينها في قاعدة البيانات أو استعادتها منها.
• حماية السجلات من خلال التحكم في الوصول والتشفير. نظرًا لأن السجلات تحتوي على قدر من المعلومات الحساسة، فإننا نتخذ تدابير لحماية تلك البيانات وتأمينها. تتضمن هذه التدابير تشفير السجلات، وتقييد الوصول إلى المشغلين الذين يقومون باستكشاف الأخطاء وإصلاحها، وتحديد الأساس لذلك الوصول بشكل منتظم.
• تجنب وضع معلومات شديدة الحساسية في السجلات. تحتاج السجلات إلى احتواء بعض المعلومات الحساسة لتكون مفيدة. في Amazon، نجد أنه من المهم أن تشتمل السجلات على معلومات كافية لمعرفة من قدم طلب معين، ولكننا نتجاهل المعلومات الحساسة للغاية، مثل معلمات الطلب التي لا تؤثر على توجيه أو سلوك معالجة الطلب. على سبيل المثال، إذا كان الرمز يقوم بتحليل رسالة عميل، وفشل هذا التحليل، فمن المهم عدم تسجيل صافي الحمولة لحماية خصوصية العميل، كما قد يصعب ذلك من عملية استكشاف الأخطاء وإصلاحها لاحقًا. نحن نستخدم الأدوات لاتخاذ قرارات بشأن ما يمكن تسجيله بطريقة تجديد الاشتراك بدلًا من طريقة إلغاء الاشتراك، لمنع تسجيل معلمة حساسة جديدة تضاف لاحقًا. تسمح خدمات مثل Amazon API Gateway بتكوين البيانات التي سيتم إدراجها في سجل الوصول الخاص بها، والذي يعمل كآلية تجديد اشتراك جيدة.
• تسجيل معرف تتبع ونشره في الاستدعاءات الخلفية. من المحتمل أن ينطوي طلب معين من العملاء على العديد من الخدمات التي تعمل بالتعاون. قد يكون هذا قليلًا بقدر خدمتين أو ثلاث خدمات للعديد من طلبات AWS، إلى خدمات أكثر بكثير لطلبات amazon.com. لفهم ما حدث عند استكشاف أخطاء أحد الأنظمة الموزعة وإصلاحها، فإننا نقوم بنشر نفس معرف التتبع بين هذه الأنظمة حتى نتمكن من تجميع سجلات من أنظمة مختلفة لمعرفة مواطن حالات الإخفاق. إنّ معرّف التتبع هو نوع من معرف طلب التعريف الذي يتم ختمه على وحدة عمل موزعة بواسطة خدمة «الباب الأمامي» التي كانت نقطة الانطلاق لوحدة العمل. إنّ خدمة AWS X-Ray هي إحدى الخدمات التي تساعد من خلال توفير بعضًا من هذا الانتشار. وقد وجدنا أنه لابد من تمرير التتبع إلى التبعية لدينا. في بيئة متعددة الترابط، يصعب على إطار العمل القيام بهذا الانتشار نيابة عنا ويؤدي أيضًا إلى التعرض للخطأ، لذلك فقد اعتدنا على تمرير معرفات التتبع ومحتويات الطلب الأخرى (مثل كائن المقاييس!) في توقيعات طريقتنا. وقد وجدنا أيضًا أنه من السهل تمرير كائن سياق في توقيعات طريقتنا، بحيث لا نضطر إلى إعادة تكوين رد الفعل عندما نجد نمطًا مشابهًا لتمريره في المستقبل. وبالنسبة لفِرق AWS، فلا يقتصر الأمر على استكشاف أخطاء أنظمتنا وإصلاحها فحسب، بل يتعلق باستكشاف العملاء لأخطائهم وإصلاحها كذلك. يعتمد العملاء على عمليات تتبع AWS X-Ray التي يتم تمريرها بين خدمات AWS عندما تتفاعل مع بعضها البعض نيابةً عن العميل. يتطلب ذلك منا نشر معرفات تتبع AWS X-Ray للعملاء بين الخدمات حتى يتمكنوا من الحصول على بيانات التتبع الكاملة.
• تسجيل مختلف مقاييس زمن الاستجابة بناءً على رمز الحالة والحجم. غالبًا ما تكون الأخطاء سريعة - مثل استجابات رفض الوصول والتقييد وأخطاء عمليات التحقق. إذا بدأ العملاء في التعرض للتقييد بمعدل مرتفع، فقد يجعل ذلك زمن الاستجابة يبدوا جيدًا بشكل زائف. وتجنبًا لهذا الخطأ في المقياس، فإننا نسجّل مؤقتًا منفصلًا للاستجابات الناجحة، ونركز على هذا المقياس في لوحات المعلومات والتنبيهات بدلًا من استخدام مقياس وقت عام. وبالمثل، إذا كانت هناك عملية يمكن أن تتباطأ بناءً على حجم الإدخال أو حجم الاستجابة، فيمكن أن نسقط أحد مقاييس زمن الاستجابة المصنفة ضمن فئة مثل SmallRequestLatency وLargeRequestLatency. إضافة إلى ذلك، نحرص على تحديد الطلب والاستجابات لدينا بطريقة ملائمة تجنبًا لأوضاع انخفاض الطاقة والفشل، ولكن حتى في الخدمة المصممة بحرص، فبإمكان أسلوب تجميع حاويات المقاييس هذا أن يعزل سلوك العميل وإبقاء الضوضاء المشتتة خارج لوحات المعلومات.
أفضل ممارسات سجل التطبيقات
يتناول هذا القسم العادات الجيدة التي تعلمناها في Amazon بشأن تسجيل البيانات غير المهيكلة لسجل التصحيح.
• الحفاظ على خلو سجل التطبيق من البريد العشوائي. رغم عدم توافر البيانات الخاصة بسجل مستوى التصحيح والمعلومات بشأن مسار الطلب من أجل المساعدة في التطوير والتصحيح في بيئات الاختبار، إلا أننا ندرس تعطيل مستويات هذه السجلات في مرحلة الإنتاج. وبدلًا من الاعتماد على سجل التطبيق لطلب تتبع المعلومات، فإننا نرى سجل الخدمات باعتباره موقعًا يضم معلومات التتبع بحيث يسهل علينا إنتاج المقاييس ورؤية الاتجاهات الكلية بمرور الوقت. وبالرغم من ذلك، فلا توجد هنا قاعدة محددة. وبالتالي ننتهج مواصلة الاطلاع على السجلات لنرى ما إذا كانت بالغة الإزعاج (أو ليست مزعجة بما يكفي)، وتعديل مستويات السجل بمرور الوقت. على سبيل المثال، عندما نتعمق في السجلات، فغالبًا ما نعثر على بيانات سجلات شديدة الإزعاج، أو مقاييس نتمنى لو كانت لدينا. ولحسن الحظ فإن هذه التحسينات غالبًا ما تكون سهلة، وبالتالي اعتدنا أن نملأ عناصر متراكمة تتسم بسرعة المتابعة للحفاظ على نظافة السجلات.
• إدراج معرّف الطلب المطابق. عندما نستكشف خطئًا ونصلحه في سجل التطبيق، فغالبًا ما نريد أن نرى التفاصيل الخاصة بالطلب أو الوسيط الذي شغّل الخطأ. فإذا كان الطلبان كلاهما يتضمنان معرّف الطلب ذاته، فيمكننا عندئذ الانتقال من سجل إلى آخر. ستشطب مكتبات سجلات التطبيقات معرّف الطلب المطابق إذا تم تكوينه بطريقة صحيحة، ويتم تعيين معرّف الطلب في شكل ThreadLocal. إذا كان التطبيق متعدد الترابط، فينبغي اتخاذ الحيطة الواجبة لتعيين معرّف الطلب الصحيح عندما تبدأ السلسلة في العمل على الطلب الجديد.
• تقييد معدّل البريد العشوائي لأخطاء سجل التطبيق. لن تحذف الخدمة قدرًا كبيرًا من سجل التطبيق عادةً، ولكن إذا بدأ قدر كبير من الأخطاء في الظهور فجأة، فربما تبدأ الخدمة في شطب معدل كبير من إدخالات ذات حجم كبير في السجل وتتضمن عمليات تعقب فائضة. ومن ثم عثرنا على طريقة للحماية من ذلك وهي تقييد معدل مرات التسجيل لأداة تسجيل معينة.
• تفضيل سطور التنسيق على String#format أو تسلسل السطور. عمليات التشغيل لواجهة برمجة التطبيقات في سجلات التطبيقات القديمة تقبل الرسائل ذات السطر الواحد بدلًا من واجهة برمجة التطبيقات ذات سطر التنسيق log4j2's varargs. إذا صُممت التعليمات البرمجية باستخدام بيانات التصحيح، مع تكوين الإنتاج على مستوى الخطأ، فمن الممكن أن يتم فقد عمل التنسيق في السطور التي تم تجاهلها في رسالة التصحيح. بعض عمليات تشغيل واجهة برمجة التطبيقات الخاصة بالسجلات تدعم تمرير كائنات عشوائية تمتلك طرق toString() الخاصة بها ولا يتم استدعاؤها إلا في حالة شطب إدخال السجل.
• تسجيل معرفات الطلبات من استدعاءات الخدمات غير الناجحة. إذا تم استدعاء خدمة وكان الرد يتضمن خطئًا، فمن المحتمل أن تكون الخدمة أرجعت معرّف الطلب. ووجدنا أنه من المفيد إدراج معرّف الطلب في السجل لدينا بحيث إذا أردنا المتابعة مع مالك تلك الخدمة، تكون لدينا طريقة لنعثر بسهولة على إدخالات سجل الخدمة المطابقة الخاصة بذلك المالك. تصعّب أخطاء انقضاء المهلة ذلك بسبب أن الخدمة قد لا تكون أرجعت معرّف الطلب حتى الآن، أو ربما لم تحلله مكتبة العميل. ومع ذلك، إذا كان لدينا معرّف طلب راجع من الخدمة، فإننا نسجله.
أفضل الممارسات في خدمات معدلات الانتقال المرتفعة
بالنسبة للغالبية العظمى من الخدمات في Amazon، فتسجيل الدخول إلى كل طلب لا يفرض تكاليف غير معقولة. تدخل الخدمات ذات معدل الانتقال الأعلى إلى منطقة أكثر غموضًا، ولكن نظل نسجل الدخول إلى كل طلب. على سبيل المثال، من الطبيعي أن نفترض أن أداة DynamoDB، التي تخدم بمفردها في الذروة ما يفوق على 20 مليون طلب في الثانية من حركة المرور الداخلية في Amazon، لم تكن لتسجل قدرًا كبيرًا، ولكنها في الحقيقة تسجل كل طلب لأسباب ترجع إلى الامتثال والتدقيق واستكشاف الأخطاء وإصلاحها. وفيما يلي بعض الإرشادات عالية المستوى التي نستخدمها في Amazon لرفع كفاءة التسجيل لمعدل الانتقال في كل استضافة:
• تسجيل عينة. بدلًا من كتابة كل إدخال، فكّر في شطب كل إدخالات N. يتضمن كل إدخال كمية الإدخالات التي تم تخطيها وبالتالي تتمكن نظم تجميع المقاييس من تقدير حجم السجل الصحيح في المقاييس التي تحسبها. لوغاريتمات العينات الأخرى مثل عينة المخزونتوفر عينات ذات تمثيل أكبر. اللوغاريتمات الأخرى تبدّي أخطاء التسجيل أو الطلبات البطئية على الطلبات الناجحة السريعة. ولكن مع العينات، تُفقد إمكانية مساعدة العملاء واستكشاف أخطاء عمليات فشل معينة وإصلاحها. لا تسمح بعض متطلبات الامتثال بالموضوع بكامله.
• إفراغ التسلسل وتسجيل التفريغ في سلسلة منفصلة. هذا التغيير سهل وشائع الاستخدام.
• التدوير المتكرر للسجل. تدوير سجلات ملفات السجل كل ساعة قد يبدو مريحًا إذ يقل عدد الملفات التي تتعامل معها، ولكن تتحسن عدة أشياء بالتدوير كل دقيقة. على سبيل المثال، الوكيل الذي يقرأ ملف السجل ويضغطه سيقرأ الملف من ملفات تعريف الارتباط للصفحة بدلًا من القرص، وسيتم النشر على مدار الساعة لوحدة المعالجة المركزية والمدخلات/المخرجات من ضغط السجلات النسخ المتواصل لها بدلًا من تشغيلها في نهاية الساعة دائمًا.
• كتابة السجلات قبل الضغط. إذا كان وكيل النسخ المتواصل للسجلات يضغطها قبل إرسالها إلى خدمة الأرشفة، فستصل وحدة المعالجة المركزية والقرص للنظام إلى الذروة على فترات منتظمة. ومن الممكن أن يتم استهلاك هذه التكلفة، وتقل المدخلات/المخرجات على القرص إلى النصف، وذلك عن طريق تدفق السجلات المضغوطة إلى القرص. ولكن يأتي هذا مع بعض المخاطر. وجدنا أنه من المفيد استخدام لوغاريتم الضغط الذي يمكن أن يتعامل مع الملفات المتقطعة في حالة تعطل التطبيق.
• الكتابة على قرص ذاكرة الوصول العشوائي / tmpfs. قد يكون من الأسهل على الخدمة أن تكتب السجلات على ذاكرة حتى يتم تفريغها من الخادم بدلًا من كتابة السجلات على القرص. وفي تجربتنا، يكون هذا أفضل مع تدوير السجل كل دقيقة مقارنة بتدوير السجل كل ساعة.
• التجميع داخل الذاكرة. إذا كان من الضروري تناول مئات الآلاف من المعاملات في الثانية على جهاز واحد، فربما تكون كتابة إدخال سجل واحد لكل طلب باهظة التكلفة. ومع ذلك، تفقد قدرًا كبيرًا من قابلية الظهور عن طريق تخطي ذلك، وبالتالي وجدنا أنه من الأفضل عدم التحسين قبل الأوان.
• مراقبة استخدام الموارد. ننتبه إلى مدى اقترابنا من بعض حدود التحجيم. نقيس المدخلات/المخرجات ووحدة المعالجة المركزية لكل خادم، ومقدار استخدام هذه الموارد عن طريق تسجيل الوكلاء. عندما نجري اختبارات للحمل، فإننا نشغلها لمدة طويلة بما يكفي بحيث يمكننا التثبت من أن وكلاء النسخ المتواصل للسجلات بإمكانهم التماشي مع معدل الانتقال.
امتلاك الأدوات المناسبة لتحليل السجلات
في Amazon، نشغّل الخدمات التي نكتبها، وبالتالي كل ما نحتاج إليه هو أن نصبح خبراء في استكشاف أخطائها وإصلاح تلك الأخطاء. وهذا يتضمن إمكانية تحليل السجلات دون جهد. يوجد العديد من الأدوات في متناولنا، بداية من تحليل السجلات المحلية للنظر إلى عدد صغير نسبيًا من السجلات، وحتى تحليل السجلات الموزعة للتحري عن النتائج وتجميعها من حجم هائل من السجلات.
وجدنا أنه من الضروري أن نستثمر في الأدوات وسجلات التشغيل الخاصة بالفِرق من أجل تحليل السجلات. إذا كانت السجلات صغيرة الآن، ولكن يُتوقع أن يزيد حجم الخدمة مع مرور الوقت، فإننا ننتبه إلى الوقت الذي تتوقف فيه الأدوات الحالية عن التحجيم، بحيث يمكننا الاستثمار في تكييف حل تحليل السجلات الموزعة.
قد تتطلب عملية تحليل السجلات خبرة في مختلف استخدامات سطر الأوامر في نظام Linux. على سبيل المثال، الأمر الشائع «find the top talker IP addresses in the log» ببساطة عبارة عما يلي:
cat log | grep -P "^RemoteIp=" | cut -d= -f2 | sort | uniq -c | sort -nr | head -n20
ومع ذلك، توجد مجموعة أدوات أخرى مفيدة في الإجابة عن الأسئلة المعقدة بشأن سجلاتنا، ومنها ما يلي:
• jq: https://stedolan.github.io/jq/
• RecordStream: https://github.com/benbernard/RecordStream
يمكن استخدام أي خدمة لتحليل السجلات من أجل تحليل السجلات الموزعة (مثل Amazon EMR وAmazon Athena وAmazon Aurora وAmazon Redshift). ومع ذلك، تأتي بعض الخدمات مجهزة بأنظمة السجلات، مثل Amazon CloudWatch Logs.
• CloudWatch Logs Insights
• AWS X-Ray: https://thinkwithwp.com/xray/
• Amazon Athena: https://thinkwithwp.com/athena/
الخاتمة
بصفتي مالك خدمة ومطور برامج، فإنني أقضي قدرًا كبيرًا من وقتي في النظر إلى مخرجات مجموعات الأدوات - الرسومات البيانية على لوحات المعلومات، ملفات السجلات الفردية - واستخدام أدوات تحليل السجلات الموزعة مثل CloudWatch Logs Insights. هذه من الأشياء التي أفضل ممارستها. عندما أحتاج إلى أخذ راحة بعد إنجاز بعض المهام الصعبة، فإنني أشحن طاقتي وأكافئ نفسي ببعض التعمق في السجلات. أبدأ بأسئلة مثل «لماذا يصل هذا المقياس إلى الذروة هنا؟» أو «هل يمكن أن يكون زمن الاستجابة لهذه العملية أبطأ؟» عندما تنتهي أسئلتي إلى عدم وجود إجابة، فغالبًا ما استكشف بعض المقاييس التي يمكن أن تفيد في التعليمات البرمجية، وبالتالي أضيف مجموعة الأدوات والاختبار وأرسل التعليمات البرمجية كي يطلع عليها زملائي.
وعلى الرغم من حقيقة إتيان العديد من المقاييس بخدمات مدارة ونستخدمها، إلا أننا نحتاج إلى قضاء قدر كبير من الوقت على تحويل خدماتنا إلى أدوات بحيث نمتلك الرؤية التي نحتاج إليها كي نشغّل هذه الخدمات بكفاءة. وفي أثناء الفعاليات التشغيلية، فإننا نحتاج إلى السرعة في تحديد سبب المشكلة وما يمكننا فعله للتخفيف من وطأتها. امتلاك المقاييس المناسبة على لوحات المعلومات أمر بالغ الأهمية بحيث نتمكن من تشخيص المشكلة بسرعة. إضافة إلى ذلك، لأننا دائمًا ما نغيّر خدماتنا ونضيف ميزات جديدة ونغيّر طريقة تفاعلها مع من يعتمدون عليها، فإننا لا ننفك عن إجراء التحديثات والإضافة إلى مجموعات الأدوات المناسبة.
الروابط
• “Look at your data,” by former Amazonian John Rauser: https://www.youtube.com/watch?v=coNDCIMH8bk (بما في ذلك عند الدقيقة 13:22 حيث يطبع السجلات حرفيًا للحصول على نظرة أفضل عليها)
• “Investigating anomalies” by former Amazonian John Rauser: https://www.youtube.com/watch?v=-3dw09N5_Aw
• “How humans see data” by former Amazonian John Rauser: https://www.youtube.com/watch?v=fSgEeI2Xpdc
• https://www.akamai.com/uk/en/about/news/press/2017-press/akamai-releases-spring-2017-state-of-online-retail-performance-report.jsp
نبذة عن المؤلف
ديفيد ياناسيك هو كبير مهندسين يعمل في AWS Lambda. وعمل ديفيد مطورًا للبرمجيات في Amazon منذ عام 2006، وكان يعمل سابقًا في تطوير Amazon DynamoDB وAWS IoT، وكذلك أطر عمل خدمة الويب الداخلية وأنظمة التشغيل الآلي لعمليات الأسطول. ومن الأنشطة المفضلة لديفيد في العمل هي تحليل السجلات والتحري عن طريق المقاييس التشغيلية لإيجاد طرق لجعل الأنظمة تعمل بسلاسة أكثر بمرور الوقت.