إنه أمر لا يصدق مدى سهولة كتابة تطبيقات الويب باستخدام ASP.NET. وبسبب هذه البساطة، لا يأخذ العديد من المطورين الوقت الكافي لتنظيم تطبيقاتهم للحصول على أداء أفضل. في هذه المقالة، سأغطي 10 نصائح لكتابة تطبيقات ويب عالية الأداء. لكنني لا أقتصر على هذه الاقتراحات لتطبيقات ASP.NET، نظرًا لأن هذه التطبيقات ليست سوى جزء من تطبيق ويب. ليس المقصود من هذه المقالة أن تكون دليلاً نهائيًا لتطبيقات الويب لضبط الأداء، فلا يمكن لكتاب كامل أن يغطي هذا الموضوع بسهولة. اعتبر هذه المقالة نقطة انطلاق رائعة.
قبل أن أصبح مدمنًا للعمل، كنت أستمتع بتسلق الصخور. قبل أي تسلق كبير، أبدأ بالنظر بعناية إلى الطرق الموجودة في الكتيبات الإرشادية وقراءة التوصيات المقدمة من الزوار السابقين. ولكن بغض النظر عن مدى جودة الدليل، فأنت بحاجة إلى تجربة تسلق الصخور الحقيقية قبل محاولة التسلق الصعبة بشكل خاص. وبالمثل، لا يمكنك تعلم كيفية كتابة تطبيقات ويب عالية الأداء إلا عندما تواجه مشكلة إصلاح مشكلات الأداء أو تشغيل موقع عالي الإنتاجية.
تجربتي الشخصية تأتي من العمل كمدير برنامج البنية التحتية في قسم ASP.NET في Microsoft، حيث قمت بتشغيل وإدارة www.ASP.NET وساعدت في تصميم خوادم المجتمع، وهي واحدة من عدة خوادم معروفة.
تطبيقات ASP.NET (منتديات ASP.NET و.Text وnGallery مدمجة في نظام أساسي واحد). أنا متأكد من أن بعض النصائح التي ساعدتني ستساعدك أيضًا.
يجب أن تفكر في تقسيم تطبيقك إلى عدة طبقات منطقية. ربما تكون قد سمعت مصطلح البنية المادية ثلاثية الطبقات (أو الطبقة n). عادةً ما يتم وصف هذه الأساليب المعمارية التي تفصل الوظائف فعليًا بين العمليات و/أو الأجهزة. عندما يحتاج النظام إلى التوسع، يمكن إضافة المزيد من الأجهزة بسهولة. ومع ذلك، هناك نتيجة أداء مرتبطة بالعملية وقفزات الماكينة، ويجب تجنبها. لذا، إذا أمكن، حاول تشغيل صفحات ASP.NET والمكونات المرتبطة بها معًا في نفس التطبيق.
وبسبب فصل التعليمات البرمجية والحدود بين الطبقات، فإن استخدام خدمات الويب أو الاتصال عن بعد سيؤدي إلى انخفاض الأداء بنسبة 20% أو أكثر.
تختلف طبقة البيانات قليلاً لأنه من الأفضل عادةً أن يكون لديك أجهزة مخصصة لقاعدة البيانات. ومع ذلك، فإن تكلفة عملية الانتقال إلى قاعدة البيانات لا تزال مرتفعة، لذا فإن أداء طبقة البيانات هو المشكلة الأولى التي يجب عليك مراعاتها عند تحسين التعليمات البرمجية.
قبل أن تتعمق في إصلاحات الأداء لتطبيقك، تأكد أولاً من إنشاء ملف تعريف للتطبيق الخاص بك لتحديد المشكلات المحددة. تعتبر عدادات الأداء الرئيسية، مثل تلك التي تمثل النسبة المئوية من الوقت المطلوب لتنفيذ عملية تجميع البيانات المهملة، مفيدة أيضًا لمعرفة المكان الذي يقضي فيه التطبيق وقته الرئيسي. ومع ذلك، فإن مكان قضاء الوقت غالبًا ما يكون غير بديهي للغاية.
توضح هذه المقالة نوعين من تحسينات الأداء: التحسينات الكبيرة (مثل استخدام التخزين المؤقت لـ ASP.NET)، والتحسينات الصغيرة التي تكرر نفسها. أحيانًا تكون هذه التحسينات الصغيرة مثيرة للاهتمام بشكل خاص. يمكنك إجراء تغيير بسيط في التعليمات البرمجية الخاصة بك وتكسب الكثير والكثير من الوقت. مع التحسينات الكبيرة، قد ترى قفزة كبيرة في الأداء العام. من خلال التحسينات الصغيرة، قد توفر فقط بضعة أجزاء من الثانية لطلب معين، ولكن عند إضافتها عبر جميع الطلبات كل يوم، يمكن أن يكون ذلك بمثابة تحسن كبير.
أداء طبقة البيانات
عندما يتعلق الأمر بضبط أداء التطبيق، هناك اختبار مقياس يمكنك استخدامه لتحديد أولويات عملك: هل يصل الكود إلى قاعدة البيانات؟ إذا كان الأمر كذلك، على أي تردد؟ لاحظ أنه يمكن أيضًا تطبيق هذا الاختبار نفسه على التعليمات البرمجية التي تستخدم خدمات الويب أو الاتصال عن بعد، ولكن هذه المقالة لا تغطي هذه الخدمات.
إذا كان طلب قاعدة البيانات ضروريًا في مسار تعليمة برمجية معينة وتعتقد أنك بحاجة إلى تحسين المناطق الأخرى أولاً (مثل معالجة السلسلة)، فتوقف ثم قم بإجراء اختبار مقياس العمق هذا. إذا لم تكن مشكلات الأداء خطيرة، فمن الجيد قضاء بعض الوقت في تحسين الوقت المستغرق بالنسبة لقاعدة البيانات، وكمية البيانات التي يتم إرجاعها، وتكرار الرحلات ذهابًا وإيابًا من قاعدة البيانات وإليها.
ومع وضع هذه المعلومات العامة في الاعتبار، دعونا نلقي نظرة على عشر نصائح قد تساعد في تحسين أداء التطبيق. أولاً، سأتحدث عن التغييرات التي قد تُحدث الفارق الأكبر.
نصيحة 1 - إرجاع مجموعات نتائج متعددة
انظر بعناية إلى كود قاعدة البيانات الخاصة بك لمعرفة ما إذا كانت هناك مسارات طلبات متعددة في قاعدة البيانات. تقلل كل رحلة ذهابًا وإيابًا من عدد الطلبات التي يمكن للتطبيق تقديمها في الثانية. من خلال إرجاع مجموعات نتائج متعددة في طلب قاعدة بيانات واحد، يمكنك حفظ إجمالي المدة الزمنية المطلوبة للاتصال بقاعدة البيانات. وفي الوقت نفسه، فإنه يجعل النظام أكثر قابلية للتوسع من خلال تقليل عمل خادم قاعدة البيانات في إدارة الطلبات.
على الرغم من أنه من الممكن استخدام SQL الديناميكي لإرجاع مجموعات نتائج متعددة، إلا أن الطريقة المفضلة لدي هي استخدام الإجراءات المخزنة. هناك بعض الجدل حول ما إذا كان يجب أن يكون منطق الأعمال موجودًا في الإجراء المخزن، ولكن أعتقد أنه سيكون من الأفضل إذا كان المنطق الموجود في الإجراء المخزن يمكنه تقييد البيانات التي يتم إرجاعها (تقليل حجم مجموعة البيانات، وتقليل الوقت المستغرق في الشبكة، دون الاضطرار إلى التدقيق في بيانات الطبقة المنطقية)، فيجب تفضيل ذلك.
عند تعبئة فئة أعمال مكتوبة بقوة باستخدام مثيل SqlCommand وأسلوب ExecuteReader الخاص به، يمكنك تحريك مؤشر مجموعة النتائج للأمام عن طريق استدعاء NextResult. يوضح الشكل 1 جلسة نموذجية تستخدم فئات الكتابة لملء عدة قوائم ArrayLists. سيؤدي إرجاع البيانات التي تحتاجها فقط من قاعدة البيانات إلى تقليل تخصيص الذاكرة على الخادم.
الشكل 1: استخراج مجموعات نتائج متعددة من قارئ البيانات
// اقرأ مجموعة النتائج الأولى
Reader = Command.ExecuteReader();
// قراءة البيانات من مجموعة النتائج تلك
بينما (reader.Read()) {
الموردين.إضافة(PopulateSupplierFromIDataReader(reader));
}
// اقرأ مجموعة النتائج التالية
Reader.NextResult();
// قراءة البيانات من مجموعة النتائج الثانية
بينما (reader.Read()) {
Products.Add(PopulateProductFromIDataReader(reader));
}
نصيحة 2 - الوصول إلى البيانات المقسمة إلى صفحات
ASP.NET DataGrid يتمتع بميزة رائعة: دعم ترقيم الصفحات للبيانات. عند تمكين الترحيل في DataGrid، يتم عرض عدد ثابت من السجلات في المرة الواحدة. بالإضافة إلى ذلك، يتم عرض واجهة مستخدم الترحيل في الجزء السفلي من DataGrid لتسهيل التنقل بين السجلات. تمكنك واجهة مستخدم الترحيل من التنقل للأمام والخلف عبر البيانات المعروضة وتعرض عددًا ثابتًا من السجلات في المرة الواحدة.
هناك أيضًا تطور صغير. يتطلب ترقيم الصفحات باستخدام DataGrid ربط كافة البيانات بالشبكة. على سبيل المثال، إذا كانت طبقة البيانات الخاصة بك تحتاج إلى إرجاع جميع البيانات، فسوف تقوم DataGrid بتصفية جميع السجلات المعروضة بناءً على الصفحة الحالية. إذا تم إرجاع 100.000 سجل عند الترحيل عبر DataGrid، فسيتم تجاهل 99.975 سجلًا لكل طلب (بافتراض أن حجم الصفحة يبلغ 25 سجلاً). عندما يزيد عدد السجلات، يتأثر أداء التطبيق لأنه يجب إرسال المزيد والمزيد من البيانات مع كل طلب.
من الطرق الممتازة لكتابة كود ترقيم الصفحات ذو الأداء الأفضل هو استخدام الإجراءات المخزنة. يوضح الشكل 2 مثالاً على الإجراء المخزن لترحيل جدول الطلبات في قاعدة بيانات Northwind. باختصار، كل ما عليك فعله في هذه المرحلة هو تمرير فهرس الصفحة وحجم الصفحة. ثم يتم حساب مجموعة النتائج المناسبة وإعادتها.
الشكل 2: الترحيل من خلال جدول الطلبات
إنشاء إجراء northwind_OrdersPaged
(
@PageIndex int،
@PageSize int
)
مثل
يبدأ
أعلن @PageLowerBound int
قم بتعريف @PageUpperBound int
DECLARE @RowsToReturn int
- قم أولاً بتعيين عدد الصفوف
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn
- قم بتعيين حدود الصفحة
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
- إنشاء جدول مؤقت لتخزين النتائج المحددة
إنشاء جدول #PageIndex
(
معرف الفهرس int IDENTITY (1، 1) ليس فارغًا،
معرف الطلب int
)
- أدخل في الجدول المؤقت
إدراج في #PageIndex (معرف الطلب)
يختار
معرف الطلب
من
طلبات
الطلب حسب
OrderID DESC
- العدد الإجمالي للإرجاع
SELECT COUNT(OrderID) FROM Orders
- إرجاع النتائج المقسمة إلى صفحات
يختار
س.*
من
الطلبات يا,
# فهرس الصفحات فهرس الصفحات
أين
O.OrderID = PageIndex.OrderID AND
PageIndex.IndexID > @PageLowerBound AND
PageIndex.IndexID < @PageUpperBound
الطلب حسب
PageIndex.IndexID
END
في خادم المجتمع، قمنا بكتابة عنصر تحكم خادم الترحيل لإكمال جميع ترحيل البيانات. كما سترى، أنا أستخدم المفهوم الذي تمت مناقشته في النصيحة 1 لإرجاع مجموعتي نتائج من إجراء مخزن: إجمالي عدد السجلات والبيانات المطلوبة.
قد يختلف العدد الإجمالي للسجلات التي يتم إرجاعها وفقًا للاستعلام الذي تم تنفيذه. على سبيل المثال، يمكن استخدام جملة WHERE لتقييد البيانات التي يتم إرجاعها. من أجل حساب إجمالي عدد الصفحات المعروضة في واجهة المستخدم المقسمة إلى صفحات، يجب عليك معرفة إجمالي عدد السجلات التي سيتم إرجاعها. على سبيل المثال، إذا كان هناك إجمالي 1,000,000 سجل، وتريد استخدام عبارة WHERE لتصفيتها وصولاً إلى 1000 سجل، فإن منطق الترحيل يحتاج إلى معرفة العدد الإجمالي للسجلات لعرض واجهة مستخدم الترحيل بشكل صحيح.
نصيحة 3 — تجمع الاتصالات
يمكن أن يكون إعداد اتصال TCP بين تطبيق ويب وSQL Server عملية كثيفة الاستخدام للموارد. تمكن المطورون في Microsoft من استخدام تجمع الاتصالات لبعض الوقت، مما يسمح لهم بإعادة استخدام اتصالات قاعدة البيانات. بدلاً من إعداد اتصال TCP جديد لكل طلب، يقومون فقط بإعداد اتصال جديد في حالة عدم وجود اتصالات في تجمع الاتصال. عند إغلاق الاتصال، فإنه يعود إلى تجمع الاتصال حيث يحافظ على الاتصال بقاعدة البيانات بدلاً من تدمير اتصال TCP بالكامل.
وبطبيعة الحال، عليك أن تكون حذرا إذا قمت بتطوير اتصالات متسربة. عند الانتهاء من استخدام اتصالاتك، تأكد من إغلاقها. للتكرار: بغض النظر عما يقوله أي شخص حول جمع البيانات المهملة في Microsoft® .NET Framework، تأكد من الاتصال بشكل صريح بإغلاق أو التخلص من الاتصال عند الانتهاء من استخدامه. لا تثق في وقت تشغيل اللغة العامة (CLR) لمسح وإغلاق الاتصالات لك في أوقات محددة مسبقًا. على الرغم من أن CLR سيدمر الفئة في النهاية ويفرض إغلاق الاتصال، إلا أنه ليس هناك ضمان عند حدوث مجموعة البيانات المهملة للكائن بالفعل.
لاستخدام تجمع الاتصالات بطريقة مثالية، هناك بعض القواعد التي يجب اتباعها. قم أولاً بفتح الاتصال، وإجراء العملية، ثم إغلاق الاتصال. إذا كان عليك ذلك، فافتح الاتصال وأغلقه عدة مرات لكل طلب (يفضل تطبيق النصيحة 1)، ولكن لا تبقي الاتصال مفتوحًا طوال الوقت وقم بتمريره إلى الداخل والخارج باستخدام طرق مختلفة مختلفة. ثانيًا، استخدم نفس سلسلة الاتصال (ونفس معرف مؤشر الترابط في حالة استخدام المصادقة المتكاملة). إذا كنت لا تستخدم نفس سلسلة الاتصال، على سبيل المثال تخصيص سلسلة الاتصال بناءً على المستخدم الذي قام بتسجيل الدخول، فلن تحصل على نفس قيمة التحسين التي يوفرها تجمع الاتصال. إذا كنت تستخدم المصادقة المتكاملة وانتحال شخصية عدد كبير من المستخدمين، فستنخفض أيضًا كفاءة تجمع الاتصال بشكل ملحوظ. يمكن أن تكون عدادات أداء بيانات .NET CLR مفيدة عند محاولة تعقب أية مشكلات في الأداء تتعلق بتجميع الاتصالات.
عندما يتصل تطبيقك بمورد، مثل قاعدة بيانات تعمل في عملية أخرى، يجب عليك التحسين من خلال التركيز على الوقت الذي يستغرقه الاتصال بهذا المورد، والوقت الذي يستغرقه إرسال البيانات أو استردادها، وعدد الرحلات ذهابًا وإيابًا. يعد تحسين أي نوع من العمليات في تطبيقك هو النقطة الأولى للحصول على أداء أفضل.
تحتوي طبقة التطبيق على منطق الاتصال بطبقة البيانات وتحويل البيانات إلى مثيلات فئة ذات معنى وعمليات تجارية. على سبيل المثال، يقوم خادم المجتمع، حيث تريد ملء مجموعة المنتديات أو المواضيع، بتطبيق قواعد العمل (مثل الأذونات)، والأهم من ذلك، تنفيذ منطق التخزين المؤقت هناك.
نصيحة 4 - واجهة برمجة تطبيقات التخزين المؤقت لـ ASP.NET
قبل كتابة سطر من التعليمات البرمجية للتطبيق، أول ما يجب عليك فعله هو هيكلة طبقة التطبيق لتحقيق أقصى استفادة من إمكانات التخزين المؤقت لـ ASP.NET.
إذا كان المكون الخاص بك سيتم تشغيله في تطبيق ASP.NET، فأنت تحتاج فقط إلى تضمين مرجع إلى System.Web.dll في مشروع التطبيق. عندما تحتاج إلى الوصول إلى ذاكرة التخزين المؤقت، استخدم خاصية HttpRuntime.Cache (يمكن الوصول إلى هذا الكائن أيضًا من خلال Page.Cache وHttpContext.Cache).
هناك عدة قواعد للتخزين المؤقت للبيانات. أولاً، إذا كان من المحتمل أن يتم استخدام البيانات عدة مرات، فهذا بديل جيد لاستخدام التخزين المؤقت. ثانيًا، إذا كانت البيانات عامة وليست خاصة بطلب أو مستخدم محدد، فهذا أيضًا مرشح جيد للتخزين المؤقت. إذا كانت البيانات خاصة بالمستخدم أو الطلب، ولكن لها عمر طويل، فلا يزال من الممكن تخزينها مؤقتًا، ولكن قد لا يتم استخدامها كثيرًا. ثالثًا، هناك قاعدة غالبًا ما يتم التغاضي عنها وهي أنه في بعض الأحيان يمكنك تخزين كمية كبيرة جدًا من البيانات في ذاكرة التخزين المؤقت. عادةً على جهاز كمبيوتر x86، لتقليل احتمالية حدوث أخطاء نفاد الذاكرة، ستحتاج إلى تشغيل العمليات بما لا يزيد عن 800 ميجابايت من البايتات الخاصة. ولذلك يجب أن يكون لذاكرة التخزين المؤقت حد. بمعنى آخر، قد تتمكن من إعادة استخدام نتيجة عملية حسابية، ولكن إذا كانت هذه العملية الحسابية تستغرق 10 معلمات، فقد تحاول تخزين 10 تبديلات مؤقتًا، مما قد يسبب لك مشكلة. أحد الطلبات الأكثر شيوعًا لدعم ASP.NET هو أخطاء نفاد الذاكرة الناتجة عن التخزين المؤقت المفرط، خاصة بالنسبة لمجموعات البيانات الكبيرة.
يحتوي التخزين المؤقت على العديد من الميزات الرائعة التي تحتاج إلى معرفتها. أولاً، تطبق ذاكرة التخزين المؤقت خوارزمية أقل استخدامًا مؤخرًا، مما يسمح لـ ASP.NET بفرض تطهير ذاكرة التخزين المؤقت - إزالة العناصر غير المستخدمة تلقائيًا من ذاكرة التخزين المؤقت - عندما تعمل الذاكرة بكفاءة أقل. ثانيًا، تدعم ذاكرة التخزين المؤقت التبعيات منتهية الصلاحية والتي يمكن إجبارها على الانتهاء. تتضمن هذه التبعيات الوقت والمفاتيح والملفات. غالبًا ما يتم استخدام الوقت، ولكن مع ASP.NET 2.0، تم تقديم نوع إبطال جديد وأكثر قوة: إبطال ذاكرة التخزين المؤقت لقاعدة البيانات. يشير إلى حذف العناصر الموجودة في ذاكرة التخزين المؤقت تلقائيًا عندما تتغير البيانات الموجودة في قاعدة البيانات. لمزيد من المعلومات حول إبطال ذاكرة التخزين المؤقت لقاعدة البيانات، راجع عمود Dino Esposito Cutting Edge في مجلة MSDN الصادرة في يوليو 2004. لفهم بنية ذاكرة التخزين المؤقت، راجع الرسم البياني أدناه.
نصيحة 6 - معالجة الخلفية
يجب أن يكون المسار إلى التعليمات البرمجية في أسرع وقت ممكن، أليس كذلك؟ قد تكون هناك أوقات تشعر فيها أن المهمة التي يتم تنفيذها بناءً على كل طلب أو مرة واحدة لكل n طلب تتطلب الكثير من الموارد. ومن الأمثلة على ذلك إرسال رسائل البريد الإلكتروني أو تحليل البيانات الواردة والتحقق من صحتها.
عند تحليل منتديات ASP.NET 1.0 وإعادة تصميم المحتوى الذي يشكل خادم المجتمع، وجدنا أن إضافة مسارات تعليمات النشر الجديدة كانت بطيئة جدًا. في كل مرة تتم إضافة منشور جديد، يحتاج التطبيق أولاً إلى التأكد من عدم وجود منشورات مكررة، ثم يجب عليه تحليل المنشور باستخدام مرشح "الكلمات السيئة"، وتحليل رمز الشخصية المنشور، ووضع علامة على المنشور وفهرسته، وإضافة النشر عند الطلب انتقل إلى قائمة الانتظار المناسبة، وتحقق من صحة المرفق، وعند النشر النهائي، أرسل إشعارًا عبر البريد الإلكتروني إلى جميع المشتركين على الفور. من الواضح أن هناك الكثير من الأمور.
بعد البحث، وجد أن معظم الوقت تم إنفاقه على منطق الفهرسة وإرسال رسائل البريد الإلكتروني. تعد فهرسة المنشورات عملية تستغرق وقتًا طويلاً للغاية، وقد تم اكتشاف أن وظيفة System.Web.Mail المضمنة تتصل بخادم SMYP ثم ترسل رسائل البريد الإلكتروني بشكل مستمر. مع زيادة عدد المشتركين في منشور أو موضوع معين، تستغرق وظيفة AddPost وقتًا أطول وأطول للتنفيذ.
فهرسة البريد الإلكتروني ليست مطلوبة لكل طلب. من الناحية المثالية، نرغب في تجميع هذه العملية، أو فهرسة 25 منشورًا في المرة الواحدة أو إرسال جميع رسائل البريد الإلكتروني كل خمس دقائق. قررنا استخدام التعليمات البرمجية التي استخدمناها سابقًا لإنشاء نموذج أولي لإبطال ذاكرة التخزين المؤقت للبيانات التي تم استخدامها لما انتهى به الأمر في Visual Studio® 2005.
تعد فئة Timer في مساحة الاسم System.Threading مفيدة جدًا، ولكنها ليست معروفة جيدًا في .NET Framework، على الأقل بين مطوري الويب. بمجرد إنشائها، ستقوم فئة Timer هذه باستدعاء رد الاتصال المحدد في فاصل زمني قابل للتكوين لمؤشر ترابط في ThreadPool. وهذا يعني أنه يمكنك إعداد التعليمات البرمجية الخاصة بك للتنفيذ دون طلبات واردة إلى تطبيق ASP.NET، وهو مثالي لمعالجة الخلفية. يمكنك أيضًا إجراء عمليات مثل فهرسة أو إرسال رسائل البريد الإلكتروني في عملية الخلفية هذه.
ومع ذلك، هناك العديد من المشاكل مع هذه التكنولوجيا. إذا تم إلغاء تثبيت مجال التطبيق، فسيتوقف مثيل المؤقت هذا عن إطلاق أحداثه. أيضًا، نظرًا لأن CLR لديه معيار صارم لعدد سلاسل العمليات لكل عملية، فقد تكون هناك حالات يتم فيها تحميل الخادم بشكل كبير حيث قد لا يحتوي المؤقت على سلاسل رسائل لإكمالها، مما قد يؤدي إلى تأخير. يحاول ASP.NET تقليل فرصة حدوث ذلك عن طريق الاحتفاظ بعدد معين من سلاسل العمليات المتوفرة في العملية واستخدام جزء فقط من إجمالي سلاسل العمليات لمعالجة الطلب. ومع ذلك، قد يكون هذا مشكلة إذا كان لديك الكثير من العمليات غير المتزامنة.
لا توجد مساحة كافية هنا لهذا الرمز، ولكن يمكنك تنزيل مثال قابل للقراءة على www.rob-howard.net. تحقق من الشرائح والعروض التوضيحية من العرض التقديمي Blackbelt TechEd 2004.
نصيحة 7 - التخزين المؤقت لإخراج الصفحة والخوادم الوكيلة
ASP.NET هي طبقة العرض التقديمي الخاصة بك (أو يجب أن تكون طبقة العرض التقديمي الخاصة بك)؛ وتتكون من الصفحات، وعناصر تحكم المستخدم، وعناصر تحكم الخادم (HttpHandlers وHttpModules)، والمحتوى الذي يقومون بإنشائه. إذا كان لديك صفحة ASP.NET تقوم بإنشاء مخرجات (HTML أو XML أو صور أو أي بيانات أخرى)، وعندما تقوم بتشغيل هذا الرمز في كل طلب فإنه يولد نفس المخرجات، فإن لديك أداة يمكن استخدامها لـ بديل رائع للتخزين المؤقت لإخراج الصفحة.
أضف سطر المحتوى هذا إلى أعلى الصفحة <%@ Page OutputCache VaryByParams="none" Duration="60" %>
يمكنك إنشاء مخرجات لهذه الصفحة بكفاءة مرة واحدة ثم إعادة استخدامها عدة مرات لمدة تصل إلى 60 ثانية، وفي ذلك الوقت سيتم إعادة تنفيذ الصفحة وستتم إضافة المخرجات إلى ذاكرة التخزين المؤقت لـ ASP.NET مرة أخرى. يمكن أيضًا تحقيق هذا السلوك باستخدام بعض واجهات برمجة التطبيقات البرمجية ذات المستوى المنخفض. هناك العديد من الإعدادات القابلة للتكوين للتخزين المؤقت للمخرجات، مثل خاصية VaryByParams المذكورة للتو. يتم طلب VaryByParams فقط، ولكنه يسمح لك أيضًا بتحديد معلمات HTTP GET أو HTTP POST لتغيير إدخالات ذاكرة التخزين المؤقت. على سبيل المثال، ما عليك سوى تعيين VaryByParam="Report" للتخزين المؤقت للإخراج لـ default.aspx?Report=1 أو default.aspx?Report=2. يمكن تحديد معلمات إضافية عن طريق تحديد قائمة مفصولة بفاصلة منقوطة.
لا يعرف الكثير من الأشخاص أنه عند استخدام التخزين المؤقت للمخرجات، تقوم صفحات ASP.NET أيضًا بإنشاء بعض رؤوس HTTP الموجودة أسفل خادم التخزين المؤقت، مثل تلك التي يستخدمها Microsoft Internet Security وAcceleration Server أو Akamai. بعد تعيين رأس ذاكرة التخزين المؤقت لـ HTTP، يمكن تخزين المستندات مؤقتًا على موارد الشبكة هذه ويمكن تلبية طلبات العميل دون العودة إلى الخادم الأصلي.
ولذلك، فإن استخدام التخزين المؤقت لمخرجات الصفحة لن يجعل التطبيق الخاص بك أكثر كفاءة، ولكنه قد يقلل الحمل على الخادم لأن تقنيات التخزين المؤقت المتلقي للمعلومات تقوم بتخزين المستند مؤقتًا. بالطبع، قد يكون هذا مجرد محتوى مجهول؛ بمجرد انتقاله إلى المصب، لن ترى هذه الطلبات مرة أخرى، ولن تتمكن بعد ذلك من إجراء المصادقة لمنع الوصول إليه.
النصيحة 8 - تشغيل IIS 6.0 (فقط استخدمه للتخزين المؤقت لـ kernel)
إذا لم تكن تستخدم IIS 6.0 (Windows Server؟ 2003)، فإنك تفوت بعض تحسينات الأداء الرائعة في خوادم Microsoft Web. في النصيحة 7، ناقشت التخزين المؤقت للمخرجات. في IIS 5.0، تمر الطلبات عبر IIS ثم إلى ASP.NET. عندما يتعلق الأمر بالتخزين المؤقت، يتلقى HttpModule في ASP.NET الطلب ويعيد محتويات ذاكرة التخزين المؤقت.
إذا كنت تستخدم IIS 6.0، فستجد ميزة صغيرة لطيفة تسمى ذاكرة التخزين المؤقت لـ kernel والتي لا تتطلب أي تغييرات في التعليمات البرمجية لـ ASP.NET. عند تقديم طلب للتخزين المؤقت للإخراج بواسطة ASP.NET، تتلقى ذاكرة التخزين المؤقت لـ IIS kernel نسخة من البيانات المخزنة مؤقتًا. عندما يأتي طلب من برنامج تشغيل الشبكة، يتلقى برنامج التشغيل على مستوى kernel (بدون تبديل السياق إلى وضع المستخدم) الطلب، ويقوم بمسح البيانات المخزنة مؤقتًا إلى الاستجابة إذا تم تخزينها مؤقتًا، ثم يكمل التنفيذ. وهذا يعني أنه عند استخدام التخزين المؤقت لوضع kernel مع التخزين المؤقت لمخرجات IIS وASP.NET، ستشاهد نتائج أداء مذهلة. أثناء تطوير ASP.NET في Visual Studio 2005، كنت مدير البرنامج المسؤول عن أداء ASP.NET. يقوم المطورون بعمل محدد، لكن يمكنني رؤية جميع التقارير التي تجري كل يوم. تعد نتائج ذاكرة التخزين المؤقت لوضع Kernel هي الأكثر إثارة للاهتمام دائمًا. السمة الأكثر شيوعًا هي أن الشبكة مليئة بالطلبات/الاستجابات، بينما يعمل IIS عند استخدام وحدة المعالجة المركزية (CPU) بنسبة 5% فقط. هذا صادم! هناك بالطبع أسباب أخرى لاستخدام IIS 6.0، ولكن التخزين المؤقت في وضع kernel هو السبب الأكثر وضوحًا.
النصيحة 9 - استخدم ضغط Gzip
على الرغم من أن استخدام gzip ليس بالضرورة خدعة في أداء الخادم (كما قد ترى زيادة في استخدام وحدة المعالجة المركزية)، فإن استخدام ضغط gzip يمكن أن يقلل عدد البايتات التي يرسلها الخادم. يؤدي هذا إلى زيادة ملحوظة في سرعة الصفحة وتقليل استخدام النطاق الترددي. اعتمادًا على البيانات التي يتم إرسالها، ومقدار ضغطها، وما إذا كان متصفح العميل يدعمها (سيقوم IIS بإرسال المحتوى المضغوط بـ gzip فقط إلى العملاء الذين يدعمون ضغط gzip، مثل Internet Explorer 6.0 وFirefox)، يمكن أن يخدم الخادم الخاص بك المزيد من الطلبات. في الواقع، في كل مرة تقريبًا تقوم فيها بتقليل كمية البيانات التي يتم إرجاعها، فإنك تزيد من عدد الطلبات في الثانية.
ضغط Gzip مدمج في IIS 6.0، وأدائه أفضل بكثير من ضغط gzip المستخدم في IIS 5.0، وهذا خبر جيد. لسوء الحظ، عند محاولة تشغيل ضغط gzip في IIS 6.0، قد لا تتمكن من العثور على الإعداد في مربع حوار الخصائص الخاص بـ IIS. قام فريق IIS ببناء وظيفة gzip ممتازة في الخادم، لكنه نسي تضمين واجهة مستخدم إدارية لتمكينها. لتمكين ضغط gzip، يجب عليك البحث بعمق داخل إعدادات تكوين XML الخاصة بـ IIS 6.0 (حتى لا تصاب بالضعف). وبالمناسبة، يعود الفضل إلى Scott Forsyth من OrcsWeb لمساعدتي في إثارة هذه المشكلة مع خادم www.asp.net المستضاف على OrcsWeb.
لن تصف هذه المقالة الخطوات، يرجى قراءة مقالة براد ويلسون على IIS6 Compression. توجد أيضًا مقالة قاعدة معرفية حول تمكين الضغط لـ ASPX في Enable ASPX Compression in IIS. ومع ذلك، يجب ملاحظة أنه نظرًا لبعض تفاصيل التنفيذ، لا يمكن أن يتواجد الضغط الديناميكي والتخزين المؤقت لـ kernel في نفس الوقت في IIS 6.0.
نصيحة 10 — حالة عرض التحكم بالخادم
يعد عرض الحالة اسمًا مثيرًا للاهتمام لـ ASP.NET حيث يقوم بتخزين بعض بيانات الحالة في حقول الإخراج المخفية للصفحة التي تم إنشاؤها. عندما يتم نشر الصفحة مرة أخرى على الخادم، يمكن للخادم تحليل بيانات حالة العرض هذه والتحقق من صحتها وتطبيقها مرة أخرى على شجرة التحكم الخاصة بالصفحة. تعد حالة العرض ميزة قوية جدًا لأنها تسمح باستمرار الحالة مع العميل، ولا تتطلب ملفات تعريف الارتباط أو ذاكرة الخادم لحفظ هذه الحالة. تستخدم العديد من عناصر تحكم خادم ASP.NET حالة العرض للاستمرار في الإعدادات التي تم إنشاؤها أثناء التفاعلات مع عناصر الصفحة، مثل حفظ الصفحة الحالية التي يتم عرضها عند ترقيم البيانات.
ومع ذلك، فإن استخدام حالة العرض له أيضًا بعض العيوب. أولاً، يعمل على زيادة الحمل الإجمالي على الصفحة في كل مرة يتم تقديمها أو طلبها. يحدث الحمل الإضافي أيضًا عند إجراء تسلسل أو إلغاء تسلسل بيانات حالة العرض التي تم نشرها مرة أخرى إلى الخادم. وأخيرًا، تزيد حالة العرض من تخصيص الذاكرة على الخادم.
تميل العديد من عناصر تحكم الخادم إلى الإفراط في استخدام حالة العرض حتى عندما لا تكون هناك حاجة إليها، وأشهرها DataGrid. يتم تشغيل السلوك الافتراضي لخاصية ViewState، ولكن يمكنك إيقاف تشغيله على مستوى عنصر التحكم أو الصفحة إذا لم تكن بحاجة إليه. ضمن عنصر التحكم، ما عليك سوى تعيين الخاصية EnableViewState إلى false، أو تعيينها بشكل عام على الصفحة باستخدام الإعداد التالي:
<%@ الصفحة EnableViewState="false" %>
إذا لم تقم بنشر الصفحة مرة أخرى، أو قمت دائمًا بإعادة إنشاء عناصر التحكم على الصفحة عند كل طلب، فيجب عليك تعطيل حالة العرض على مستوى الصفحة.
لقد قدمت لك بعض النصائح التي أجدها مفيدة عند كتابة تطبيقات ASP.NET عالية الأداء. كما ذكرت سابقًا في هذه المقالة، هذا دليل أولي وليس الكلمة الأخيرة حول أداء ASP.NET. (للحصول على معلومات حول تحسين أداء تطبيق ASP.NET، راجع تحسين أداء ASP.NET.) لا يمكن العثور على أفضل طريقة لحل مشكلة أداء معينة إلا من خلال تجربتك الخاصة. ومع ذلك، يجب أن تمنحك هذه النصائح بعض الإرشادات الجيدة في رحلتك. في تطوير البرمجيات، هناك عدد قليل من الأمور المطلقة؛ كل تطبيق فريد من نوعه.