المؤلف: روب هوارد ترجمة: الأسماك الاستوائية
تتناول هذه المقالة:
· أسرار أداء ASP.NET العامة
· نصائح وحيل مفيدة لتحسين أداء ASP.NET
· توصيات لاستخدام قواعد البيانات في ASP.NET
· التخزين المؤقت ومعالجة الخلفية في ASP.NET
إن كتابة تطبيق ويب باستخدام ASP.NET أمر بسيط للغاية. الأمر بسيط جدًا لدرجة أن العديد من المطورين لا يأخذون الوقت الكافي لبناء تطبيقاتهم لتحقيق أداء جيد. في هذه المقالة، أوصي بـ 10 نصائح لكتابة تطبيقات ويب عالية الأداء. لن أقصر مناقشتي على تطبيقات ASP.NET، لأن تطبيقات ASP.NET ليست سوى مجموعة فرعية من تطبيقات الويب. ليس المقصود من هذه المقالة أن تكون دليلاً نهائيًا لتحسين أداء تطبيقات الويب - يمكن لكتاب كامل أن يفعل ذلك بسهولة. وبدلا من ذلك، ينبغي لنا أن نعتبر هذه المقالة نقطة انطلاق جيدة.
قبل أن أصبح مدمنًا للعمل، كنت أذهب لتسلق الصخور كثيرًا. قبل القيام بأي تسلق، أفضل إلقاء نظرة على الطرق في دليل السفر وقراءة توصيات الأشخاص الذين ذهبوا إلى القمة. ولكن بغض النظر عن مدى جودة كتابة الدليل الإرشادي، فأنت بحاجة إلى تجربة تسلق فعلية قبل محاولة تحقيق هدف صعب. وبالمثل، لا يمكنك تعلم كيفية كتابة تطبيقات ويب عالية الأداء إلا عندما تواجه مشكلة إصلاح مشكلات الأداء أو تشغيل موقع عالي الإنتاجية.
تأتي تجربتي الشخصية من العمل كمدير برنامج أساسي في فريق ASP.NET في Microsoft، وصيانة وإدارة www.asp.net ، ومساعدة مهندس Community Server، أحد تطبيقات ASP.NET العديدة المعروفة (منتديات ASP.NET) و.Text وnGallery متصلان بمنصة واحدة). أنا متأكد من أن بعض هذه النصائح التي ساعدتني ستكون مفيدة لك أيضًا.
يجب أن تفكر في فصل تطبيقك إلى عدة طبقات منطقية. ربما تكون قد سمعت عن بنية ثلاثية الطبقات (أو طبقة n). عادةً ما يتم وصف هذه الأنماط الهيكلية التي تقسم الأعمال و/أو الأجهزة فعليًا إلى أقسام وظيفية. إذا كان النظام يتطلب نطاقًا أكبر، فيمكن إضافة المزيد من الأجهزة بسهولة. ومع ذلك، سيؤدي ذلك إلى تدهور الأداء المرتبط بالأعمال والقفزات في الآلات، لذا يجب علينا تجنب ذلك. لذلك، كلما أمكن، حاول تشغيل صفحة ASP.NET والمكونات المرتبطة بالصفحة في نفس التطبيق.
وبسبب فصل التعليمات البرمجية والحدود بين الطبقات، فإن استخدام خدمات الويب أو الاتصال عن بعد يمكن أن يقلل الأداء بنسبة 20% أو أكثر.
تختلف طبقة البيانات قليلاً لأنه من الأفضل عادةً أن يكون لديك أجهزة مخصصة لقاعدة البيانات. ومع ذلك، فإن تكلفة عملية الانتقال إلى قاعدة البيانات لا تزال مرتفعة، لذا يجب أن يكون الأداء في طبقة البيانات هو الاعتبار الأول عند تحسين التعليمات البرمجية الخاصة بك.
قبل الاستثمار في إصلاح مشكلات أداء تطبيقك، تأكد من تحليل تطبيقك لاكتشاف السبب الجذري للمشكلة. تعد عدادات الأداء الرئيسية (مثل تلك التي تشير إلى النسبة المئوية للوقت المستغرق في تنفيذ عملية جمع البيانات المهملة) مفيدة جدًا أيضًا في معرفة المكان الذي يقضي فيه التطبيق معظم وقته. على الرغم من أن تلك الأماكن التي يتم فيها قضاء الوقت غالبًا ما تكون أقل بديهية.
أناقش في هذه المقالة طريقتين لتحسين الأداء: التحسينات واسعة النطاق، مثل استخدام التخزين المؤقت لـ ASP.NET، والتحسينات صغيرة الحجم، والتي تتكرر غالبًا. أحيانًا تكون هذه الأجزاء الصغيرة من التحسين هي الأكثر إثارة للاهتمام. سيتم استدعاء التغيير البسيط الذي تجريه على الكود الخاص بك آلاف المرات. قم بتحسين الأجزاء الكبيرة وقد تجد قفزة كبيرة في الأداء العام. من خلال التحسين في أجزاء صغيرة، قد تقتطع بضع ميكروثانية من طلب معين، ولكن بشكل تراكمي عبر جميع الطلبات يوميًا، ستحصل على تحسن غير متوقع في الأداء.
الأداء في طبقة البيانات
عندما تبدأ في تحسين أداء أحد التطبيقات، هناك اختبار حاسم يمكنك تحديد أولوياته: هل يحتاج الكود إلى الوصول إلى قاعدة بيانات؟ إذا كان الأمر كذلك، كم مرة قمت بزيارتها؟ لاحظ أنه يمكن أيضًا تطبيق هذا الاختبار على التعليمات البرمجية التي تستخدم خدمات الويب أو التحكم عن بعد، لكنني لن أغطي تلك الموجودة في هذه المقالة.
إذا كان طلب قاعدة البيانات مطلوبًا في مسار تعليمات برمجية معينة في التعليمات البرمجية الخاصة بك، وعثرت على أماكن أخرى تريد تحديد أولويات التحسينات فيها، مثل معالجة السلسلة، فقم بإيقاف الاختبارات المهمة وتنفيذها أولاً. ما لم تكن لديك مشكلة أداء سيئة للغاية للتعامل معها، فمن الأفضل قضاء وقتك في تحسين الوقت المستغرق للاتصال بقاعدة البيانات، وكمية البيانات التي يتم إرجاعها، والعمليات التي تقوم بها من وإلى قاعدة البيانات.
الآن بعد أن قمت بتغطية المعلومات بشكل عام، دعنا نلقي نظرة على 10 نصائح لمساعدة تطبيقك على الأداء بشكل أفضل. سأبدأ بتلك التي لها التأثير الأكثر وضوحًا على تحسين الأداء.
نصيحة 1 - إرجاع مجموعات نتائج متعددة
قم بإلقاء نظرة على كود قاعدة البيانات الخاصة بك لمعرفة ما إذا كان لديك مسارات طلب تصل إلى قاعدة البيانات أكثر من مرة. تقلل كل رحلة ذهابًا وإيابًا من عدد الطلبات التي يمكن أن يخدمها تطبيقك في الثانية. من خلال إرجاع مجموعات نتائج متعددة في طلب قاعدة بيانات واحد، يمكنك تقليل الوقت الإجمالي الذي يستغرقه اتصال قاعدة البيانات. بعد تقليل عدد الطلبات التي يتعين على خادم قاعدة البيانات الخاصة بك إدارتها، يمكنك أيضًا جعل نظامك أكثر قابلية للتوسع.
بشكل عام، يمكنك استخدام عبارات SQL الديناميكية لإرجاع مجموعات نتائج متعددة، أفضل استخدام الإجراءات المخزنة. من المثير للجدل ما إذا كان يجب عليك وضع منطق الأعمال في إجراء مخزن، ولكن أعتقد أنه إذا كان المنطق الموجود في الإجراء المخزن يمكن أن يحد من البيانات التي يتم إرجاعها (يقلل من حجم مجموعة البيانات، والوقت المستغرق في اتصال الشبكة، ويلغي الحاجة إلى تصفية بيانات الطبقة المنطقية)، فهذا أمر جيد.
باستخدام مثيل SqlCommand وأسلوب ExecuteReader الخاص به لإنشاء فئة أعمال مكتوبة بقوة، يمكنك تحريك مؤشر مجموعة النتائج للأمام عن طريق استدعاء NextResult. يوضح الشكل 1 جلسة نموذجية تستخدم فئة محددة لإنشاء عدة قوائم ArrayLists. سيؤدي إرجاع البيانات التي تحتاجها من قاعدة البيانات فقط إلى تقليل طلبات الذاكرة على الخادم الخاص بك بشكل كبير.
1//قراءة مجموعة النتائج الأولى
2reader = Command.ExecuteReader();
3
4//قراءة البيانات من تلك النتائج
5بينما (reader.Read()) {
6 موردين.إضافة(PopulateSupplierFromIDataReader(reader));
7}
8
9//اقرأ مجموعة النتائج التالية
10reader.NextResult();
11
12// اقرأ البيانات من مجموعة النتائج الثانية
13بينما (reader.Read()) {
14 منتجًا.إضافة(PopulateProductFromIDataReader(reader));
15}
16
17
نصيحة 2 - الوصول إلى البيانات المرقّمة
توفر DataGrid الخاصة بـ ASP.NET قدرة رائعة: دعم ترحيل البيانات. عند إعداد ترقيم الصفحات في DataGrid، سيتم عرض عدد محدد من النتائج في المرة الواحدة. بالإضافة إلى ذلك، يتم عرض واجهة مستخدم الترحيل للتنقل بين النتائج في الجزء السفلي من DataGrid. تسمح لك واجهة المستخدم المرقّمة بالتنقل للأمام أو للخلف عبر البيانات المعروضة، مع عرض عدد محدد من النتائج لكل صفحة.
ولكن هناك مشكلة صغيرة. عند استخدام DataGrid للترحيل، يجب ربط كافة البيانات بالجدول. على سبيل المثال، ستحتاج طبقة البيانات الخاصة بك إلى إرجاع جميع البيانات، ثم ستحتاج DataGrid إلى ملء جميع السجلات ليتم عرضها استنادًا إلى الصفحة الحالية. إذا تم إرجاع 100.000 سجل عند استخدام ترقيم الصفحات DataGrid، فسيتم تجاهل 99.975 سجلًا لكل طلب (بافتراض أن سعة كل صفحة هي 25 سجلاً). عندما يزداد عدد السجلات، يتأثر أداء التطبيق بشكل كبير لأنه يجب إرجاع المزيد والمزيد من البيانات مع كل طلب.
إحدى الطرق لكتابة رمز ترقيم الصفحات بشكل أفضل هي استخدام الإجراءات المخزنة. يوضح الشكل 2 نموذجًا لإجراء مخزن يقوم بصفحات جدول بيانات الطلبات في قاعدة بيانات Nothwind. في الأساس، كل ما عليك فعله هنا هو تمرير فهرس الصفحة وسعة الصفحة. تقوم قاعدة البيانات بحساب مجموعات النتائج المناسبة وإرجاعها.
1 إنشاء إجراء northwind_OrdersPaged
2(
3 @PageIndex int،
4 @ حجم الصفحة int
5)
6AS
7ابدأ
8DECLARE @PageLowerBound int
9DECLARE @PageUpperBound int
10DECLARE @RowsToReturn int
11
12--قم أولاً بتعيين عدد الصفوف
13SET @RowsToReturn = @PageSize * (@PageIndex + 1)
14SET ROWCOUNT @RowsToReturn
15
16--ضبط حدود الصفحة
17SET @PageLowerBound = @PageSize * @PageIndex
18SET @PageUpperBound = @PageLowerBound + @PageSize + 1
19
20--إنشاء جدول مؤقت لتخزين النتائج المحددة
21 إنشاء جدول #PageIndex
إثنان وعشرون(
23 معرف الفهرس int IDENTITY (1، 1) ليس فارغًا،
24 معرف الطلب int
25)
26
27--أدخل في الجدول المؤقت
28 أدخل في #PageIndex (معرف الطلب)
29حدد
30 معرف الطلب
31من
32 أوامر
33الطلب حسب
34 معرف الطلب DESC
35
36--إرجاع العدد الإجمالي
37حدد عدد (معرف الطلب) من الطلبات
38
39--إرجاع النتائج المقسمة إلى صفحات
40حدد
41 س.*
42من
43 الطلبات
44 # فهرس الصفحات PageIndex
45 أين
46 O.OrderID = PageIndex.OrderID AND
47 PageIndex.IndexID > @PageLowerBound AND
48 PageIndex.IndexID < @PageUpperBound
49الطلب حسب
50 PageIndex.IndexID
51
52 نهاية
53
54
خلال فترة خدمة المجتمع، قمنا بكتابة عنصر تحكم خادم الترحيل للقيام بترحيل البيانات هذه. ستلاحظ أنني استخدمت الفكرة التي تمت مناقشتها في النصيحة 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 Buffering API
أول شيء يجب مراعاته قبل البدء في كتابة السطر الأول من التعليمات البرمجية في التطبيق الخاص بك هو تصميم طبقة التطبيق لتحقيق أقصى استفادة من ميزات التخزين المؤقت لـ ASP.NET.
إذا كان المكون الخاص بك يعمل ضمن تطبيق ASP.NET، فما عليك سوى الرجوع إلى System.Web.dll في مشروع التطبيق الخاص بك. عندما تحتاج إلى الوصول إلى ذاكرة التخزين المؤقت، استخدم خاصية HttpRuntime.Cache (يمكن أيضًا الوصول إلى هذا الكائن من خلال Page.Cache وHttpContext.Cache).
هناك العديد من الإرشادات لاستخدام البيانات المخزنة مؤقتًا. أولاً، إذا كان من الممكن استخدام البيانات عدة مرات، فإن تخزينها مؤقتًا يعد خيارًا جيدًا. ثانيًا، إذا كانت البيانات عامة وليست خاصة بطلب أو مستخدم معين، فإن تخزينها مؤقتًا يعد خيارًا رائعًا. إذا كانت البيانات خاصة بالمستخدم أو الطلب ولكن لها عمر طويل، فيمكن تخزينها مؤقتًا ولكن لا يجوز استخدامها بشكل متكرر. ثالثًا، هناك مبدأ غالبًا ما يتم التغاضي عنه وهو أنه في بعض الأحيان يمكنك تخزين كمية كبيرة جدًا من البيانات في ذاكرة التخزين المؤقت. عادةً على جهاز x86، لتقليل احتمال حدوث أخطاء نفاد الذاكرة، ستحتاج إلى تشغيل عملية لا تستخدم أكثر من 800 ميجابايت من البايتات الخاصة. لذلك، يجب أن يكون التخزين المؤقت محدودًا. بمعنى آخر، قد تحتاج إلى إعادة استخدام نتيجة عملية حسابية واحدة، ولكن إذا كانت هذه العملية الحسابية تتطلب عشرة معلمات، فقد تحتاج إلى محاولة تخزين 10 تبديلات مؤقتًا، وقد يؤدي ذلك إلى وقوعك في مشكلة. تعد أخطاء نفاد الذاكرة بسبب التخزين المؤقت الزائد هي الأكثر شيوعًا في ASP.NET، خاصة مع مجموعات البيانات الكبيرة.
يحتوي التخزين المؤقت على العديد من الميزات الرائعة التي تحتاج إلى معرفتها. أولاً، تطبق ذاكرة التخزين المؤقت خوارزمية أقل استخدامًا مؤخرًا، مما يسمح لـ ASP.NET بفرض مسح ذاكرة التخزين المؤقت - إزالة العناصر غير المستخدمة من ذاكرة التخزين المؤقت تلقائيًا - عندما تعمل الذاكرة بكفاءة أقل. ثانيًا، تدعم ذاكرة التخزين المؤقت التبعيات منتهية الصلاحية والتي يمكن إجبارها على الانتهاء. تتضمن هذه التبعيات الوقت والمفاتيح والملفات. غالبًا ما يتم استخدام الوقت، ولكن مع ASP.NET 2.0، تم تقديم نوع إبطال جديد وأكثر قوة: إبطال ذاكرة التخزين المؤقت لقاعدة البيانات. يشير إلى حذف العناصر الموجودة في ذاكرة التخزين المؤقت تلقائيًا عندما تتغير البيانات الموجودة في قاعدة البيانات. لمزيد من المعلومات حول إبطال ذاكرة التخزين المؤقت لقاعدة البيانات، راجع العمود Dino Esposito Cutting Edge في إصدار يوليو 2004 من مجلة MSDN. لفهم بنية ذاكرة التخزين المؤقت، انظر الشكل 3.
نصيحة 5 - التخزين المؤقت لكل طلب
لقد ذكرت سابقًا في هذه المقالة أن التحسينات الصغيرة على مسارات التعليمات البرمجية التي يتم اجتيازها بشكل متكرر يمكن أن تؤدي إلى مكاسب كبيرة في الأداء بشكل عام. من بين هذه التحسينات الصغيرة، أحدها بالتأكيد هو المفضل لدي وأسميه التخزين المؤقت لكل طلب.
تم تصميم واجهات برمجة تطبيقات التخزين المؤقت لتخزين البيانات مؤقتًا لفترة أطول من الوقت، أو حتى يتم استيفاء شروط معينة، ولكن التخزين المؤقت لكل طلب يعني تخزين البيانات مؤقتًا لمدة هذا الطلب فقط. لكل طلب، يتم الوصول إلى مسار تعليمات برمجية محدد بشكل متكرر، ولكن يتم استخراج البيانات أو تطبيقها أو تعديلها أو تحديثها مرة واحدة فقط. يبدو هذا نظريًا بعض الشيء، لذا دعونا نعطي مثالًا ملموسًا.
في تطبيق منتدى خادم المجتمع، يتطلب كل عنصر تحكم خادم مستخدم في الصفحة بيانات تخصيص لتحديد المظهر الذي سيتم استخدامه، وجدول النمط الذي سيتم استخدامه، وبيانات التخصيص الأخرى. يمكن تخزين بعض هذه البيانات مؤقتًا على المدى الطويل، ولكن يتم جلب بعض البيانات مرة واحدة فقط لكل طلب ثم يتم إعادة استخدامها عدة مرات أثناء هذا الطلب، مثل مظهر عنصر التحكم.
لتحقيق التخزين المؤقت لكل طلب، استخدم ASP.NET HttpContext. لكل طلب، يتم إنشاء مثيل HttpContext ويمكن الوصول إليه من أي مكان داخل خاصية HttpContext.Current أثناء الطلب. تحتوي فئة HttpContext على خاصية خاصة لمجموعة العناصر؛ ويتم تخزين الكائنات والبيانات المضافة إلى مجموعة العناصر هذه مؤقتًا فقط طوال مدة الطلب. تمامًا كما يمكنك استخدام التخزين المؤقت لتخزين البيانات التي يتم الوصول إليها بشكل متكرر، يمكنك أيضًا استخدام HttpContext.Items لتخزين البيانات التي يتم استخدامها فقط على أساس كل طلب. المنطق الكامن وراء ذلك بسيط للغاية: تتم إضافة البيانات إلى مجموعة HttpContext.Items عندما لا تكون موجودة، وفي عمليات البحث اللاحقة، يتم إرجاع البيانات الموجودة في HttpContext.Items فقط.
نصيحة 6 - معالجة الخلفية
يجب أن يكون المسار إلى التعليمات البرمجية في أسرع وقت ممكن، أليس كذلك؟ قد تكون هناك أوقات تجد فيها أنك تقوم بمهمة كثيفة الاستخدام للموارد يتم تنفيذها بناءً على كل طلب أو كل طلب n. ومن الأمثلة على ذلك إرسال رسائل البريد الإلكتروني أو تحليل البيانات الواردة والتحقق من صحتها.
عند تحليل منتديات ASP.NET 1.0 وإعادة تصميم المحتوى الذي يشكل خادم المجتمع، اكتشفنا أن مسار التعليمات البرمجية لنشر المشاركات الجديدة كان بطيئًا للغاية. في كل مرة يتم نشر منشور جديد، يحتاج التطبيق أولاً إلى التأكد من عدم وجود منشورات مكررة، ثم يجب عليه تحليل المنشور باستخدام مرشح "الكلمات السيئة"، وتحليل الرموز التعبيرية لشخصية المنشور، ووضع علامة على المنشور وفهرسته، وإضافة العلامة قم بالنشر عند الطلب عند الطلب، أضف إلى قائمة الانتظار المناسبة، وتحقق من صحة المرفق، وأخيرًا أرسل إشعارًا بالبريد الإلكتروني إلى جميع المشتركين فور نشر المنشور. من الواضح أن هناك الكثير من الأمور.
بعد البحث، وجد أن معظم الوقت تم إنفاقه على منطق الفهرسة وإرسال رسائل البريد الإلكتروني. تعد فهرسة المنشورات عملية تستغرق وقتًا طويلاً للغاية وقد تم اكتشاف أن وظيفة System.Web.Mail المضمنة تتصل بخادم SMTP ثم ترسل رسائل البريد الإلكتروني بشكل مستمر. مع زيادة عدد المشتركين في منشور أو موضوع معين، تستغرق وظيفة 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 (حتى فقط لاستخدام ذاكرة التخزين المؤقت للنواة)
إذا لم تكن تستخدم 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.) لا يمكن العثور على أفضل طريقة لحل مشكلة أداء معينة إلا من خلال تجربتك الخاصة. ومع ذلك، يجب أن تمنحك هذه النصائح بعض الإرشادات الجيدة في رحلتك. في تطوير البرمجيات، هناك عدد قليل من الأمور المطلقة؛ كل تطبيق فريد من نوعه.
راجع الشريط الجانبي "أساطير الأداء الشائعة".
روب هوارد هو مؤسس شركة Telligent Systems، المتخصصة في تطبيقات الويب عالية الأداء، وإدارة قاعدة المعرفة، وأنظمة التعاون. كان Rob يعمل سابقًا لدى Microsoft، حيث ساعد في تصميم البنية الأساسية لـ ASP.NET 1.0 و1.1 و2.0. للتواصل مع روب، يرجى زيارة [email protected] .
الرابط الأصلي: http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/default.aspx