افزايش كارآئی برنامه های وب در ASP.NET 2.0 ( بخش اول )
برنامه های وب با توجه به ماهيت و رسالت خود می بايست قادر به ارائه خدمات مورد نياز به صدها و يا هزاران متقاضی همزمان به سادگی و با سرعت مطلوب باشند. به عبارت ديگر ، همزمان با افزايش كاربران نمی بايست شاهد افت سرعت و كارآئی يك برنامه وب باشيم .
با ارائه فريمورك دات نت و به دنبال آن ASP.NET ، پياده سازی يك برنامه وب بطرز ناباورانه ای ساده شده است . همين موضوع باعث شده است كه طراحان و پياده كنندگان بيشتر در انديشه طراحی و پياده سازی سريع برنامه های وب باشند و به مسائل مربوط به كارآئی برنامه كمتر توجه نمايند .
پياده كنندگان برنامه های وب با استفاده از فناوری ASP.NET می بايست با بكارگيری مجموعه ای از ترفندها ، فناوری ها و رعايت برخی نكات كليدی اقدام به پياده سازی برنامه های وب با كارآئی بالا نمايند .
در اين مقاله و ساير مقالاتی كه در آينده منتشر خواهد شد قصد داريم به برخی از روش های موجود به منظور طراحی و پياده سازی يك برنامه وب كارآ اشاره نمائيم . بدين منظور بر روی سه محور اساسی زير متمركز خواهيم شد :
• طراحی برای كارآئی : در اين رابطه به مجموعه ای از نكات كليدی اشاره خواهيم كرد كه رعايت آنها در زمان طراحی می تواند زمينه پياده سازی يك برنامه وب كارآ را فراهم نمايد .
• تست برنامه قبل از عملياتی شدن آن : يكی از مسائل مهم در ارتباط با برنامه های وب ، عدم تست آنها با شرايط مشابه و يا نزديك به محيط واقعی است . در اين راستا می توان از نرم افزارها و يا ابزارهای مختلفی استفاده كرد تا بتوان عملكرد و سرويس دهی يك برنامه وب را قبل از زير بار رفتن واقعی مشاهده و بررسی نمود . شركت مايكروسافت در اين رابطه ابزارها و برنامه های متعددی را ارائه نموده است كه به بررسی آنها خواهيم پرداخت .
• پياده سازی سيستم caching : با پياده سازی سيستم caching در سطوح متفاوت و caching داده می توان كارآئی برنامه های وب را بطرز كاملا" محسوسی افزايش داد. در اين بخش به نحوه پياده سازی سيستم caching در برنامه های وب اشاره خواهيم كرد .
در ادامه بر روی اولين محور متمركز و به بررسی مسائل مرتبط با آن خواهيم پرداخت .
طراحی برای كارآئی
مكانيزم ترجمه كد در ASP.NET
زمانی كه اولين مرتبه يك كاربر صفحه ای را درخواست می نمايد ( و يا اولين مرتبه دستيابی پس از ايجاد تغييرات در صفحه ) ، يك تاخير قابل ملاحظه در زمان پاسخ به درخواست خود را مشاهده می نمايد ( تاخير ناشی از ترجمه صفحه ) . برای برخورد با اين موضوع می توان از روش precompilation استفاده نمود . با استفاده از روش فوق پس از استقرار صفحات بر روی سرويس دهنده وب ، بلافاصله امكان درخواست و بازيابی سريع آنها برای متقاضيان فراهم می گردد .
كنترل های سرويس دهنده
در برخی موارد ضرورتی به استفاده از كنترل های سرويس دهنده ASP.NET در يك صفحه وب نخواهيم داشت . به عنوان نمونه ، در صورتی كه دارای يك متن ايستا می باشيم كه هرگز ضرورتی به دستيابی و تغيير آن در زمان اجراء و از طريق كد نداريم ، لزومی به استفاده از كنترلی نظير label نخواهيم داشت . در چنين مواردی می توان به سادگی متن مورد نظر را با استفاده از امكانات HTML در فايل aspx. قرار داد . در ويژوال استوديو می توان از كنترل DIV ( موجود در بخش HTML ، منوی Toolbox) استفاده كرد. در واقع ما تكليف متن مورد نظر جهت نمايش در يك صفحه aspx . را نه در زمان اجراء بلكه در زمان طراحی مشخص كرده ايم .
يكی ديگر از نكات مهم در زمان استفاده از كنترل های سرويس دهنده در صفحات وب ، توجه به رفتار آنها در ارتباط با نگهداری داده پس از ارسال مجدد به سرويس دهنده می باشد . به صورت پيش فرض ، مقادير مرتبط با كنترل های سرويس دهنده نظير مقدار درج شده در يك TextBox ، پس از postback بطور اتوماتيك در view state ذخيره می گردد . در واقع ، view state مكانيزمی برای نگهداری داده كنترل های سرويس دهنده است كه هدف آن غلبه بر محدوديت پروتكل HTTP است ( ماهيت stateless ) .
view state ، يك نام مناسب برای ذخيره داده در يك فيلد ورودی مخفی درون صفحه است . پس از post back ( ارسال مجدد برای سرويس گيرنده ) يك صفحه ، سرويس دهنده قادر به بررسی مقادير نگهداری شده در view state و استفاده از آنها با توجه به شرايط حاكم بر برنامه می باشد . view state يك قابليت عالی است چراكه اجازه نگهداری وضعيت را با استفاده از امكانات سرويس گيرنده فراهم می نمايد و در اين رابطه از كوكی و حافظه سرويس دهنده برای ذخيره وضعيت استفاده نمی گردد .
تعداد زيادی از كنترل های سرويس دهنده ASP.NET از view state برای نگهداری تنظميات خود در زمان تعامل با عناصر موجود بر روی صفحه استفاده می نمايند ( مثلا" ذخيره صفحه جاری در زمان استفاده از ويژگی paging در كنترل سرويس دهنده gridview ) .
در زمان استفاده از view state توجه به موارد زير ضروری است :
• playload صفحه را در زمان درخواست و ارائه افزايش می دهد .
• افزايش overhead در زمان serializing و deserializing داده ذخيره شده در view state كه برای سرويس دهنده post-back شده است .
• افزايش تخصيص حافظه بر روی سرويس دهنده
كنترل های سرويس دهنده علاقه زيادی به استفاده از view state دارند حتی در مواردی كه به وجود آن نياز نمی باشد . به صورت پيش فرض viewstate فعال است و در صورت عدم نياز می بايست آن را در سطح صفحه و يا كنترل غيرفعال نمود . در رابطه با يك كنترل كافی است كه خصلت EnableViewState را false و يا می توان آن را به صورت سراسری و در سطح page غير فعال نمود . دستور زير نحوه انجام اين كار را نشان می دهد :
<%@ Page EnableViewState="false" %> |
برای غير فعال كردن view state در سطح صفحه و يا كنترل از قوانين زير می توان استفاده نمود :
• در صورتی كه در صفحه ای post back انجام نمی گيرد و يا صفحه می بايست همواره برای هر يك از كنترل های موجود بر روی صفحه و به ازاء هر درخواست مجددا" توليد گردد ، می بايست view state را در سطح page غير فعال نمود .
• در صورتی كه ضرورتی به نگهداری داده مرتبط با يك كنترل سرويس دهنده در view state نمی باشد می بايست آن را برای كنترل مورد نظر غير فعال نمود . بدين منظور لازم است كه مقدار EnableViewState مربوط به كنترل معادل False در نظر گرفته شود .
• در صورتی كه كنترل در زمان طراحی مقداردهی شده است و در زمان اجراء مقدار آن تغيير نمی يابد ، خصلت EnableViewState آن می بايست false در نظر گرفته شود .
• در صورتی كه كنترل با هر post back ، مجددا" خوانده شده و refresh می گردد و ضرورتی به نگهداری مقدار داده قبلی وجود نداشته باشد ، خصلت EnableViewState آن می بايست false در نظر گرفته شود .
• در صورتی كه لازم است انتخاب كاربر پس از postback صفحه بازيابی گردد ، می بايست view state را برای كنترل مورد نظر فعال كرد.
view state ، عموما" كند شدن سرويس دهنده را به دنبال نخواهد داشت بلكه حجم صفحه را افزايش داده و مدت زمان ارسال صفحه برای سرويس گيرنده را زياد خواهد كرد . در چنين مواردی كاربران اين برداشت را خواهند داشت كه برنامه كند و قادر به ارائه پاسخ سريع به آنان نمی باشد ، خصوصا" در مواردی كه ارتباط بين سرويس گيرنده و سرويس دهنده از طريق يك خط با سرعت پائين برقرار شده باشد .
عدم استفاده صحيح از view state در برخی موارد می تواند ادامه حيات موثر يك برنامه وب را با چالش جدی مواجه نمايد . اين موضوع در برنامه هائی كه از كنترل های زيادی در يك صفحه استفاده و حجم بالائی از داده را در خود نگهداری می نمايند، مضاعف می گردد. در چنين مواردی داده دو مرتبه به صفحه وب اضافه می گرد : مستقيما" در كد HTML مرتبط با كنترل و مجددا" در يك فيلد مخفی برای view state . داده فوق با هر post back بين سرويس گيرنده و سرويس دهنده مبادله می گردد .
با استفاده از page tracing می توان از تعداد بايتی كه view state مصرف می كند آگاهی يافت .
بحث خود را با معرفی سه محور اساسی زير آغاز و با تمركز بر روی اولين محور ادامه داديم .
• طراحی برای كارآئی : در اين رابطه به مجموعه ای از نكات كليدی اشاره خواهيم كرد كه رعايت آنها در زمان طراحی می تواند زمينه پياده سازی يك برنامه وب كارآ را فراهم نمايد .
• تست برنامه قبل از عملياتی شدن آن : يكی از مسائل مهم در ارتباط با برنامه های وب ، عدم تست آنها با شرايط مشابه و يا نزديك به محيط واقعی است . در اين راستا می توان از نرم افزارها و يا ابزارهای مختلفی استفاده كرد تا بتوان عملكرد و سرويس دهی يك برنامه وب را قبل از زير بار رفتن واقعی مشاهده و بررسی نمود . شركت مايكروسافت در اين رابطه ابزارها و برنامه های متعددی را ارائه نموده است كه به بررسی آنها خواهيم پرداخت .
• پياده سازی سيستم caching : با پياده سازی سيستم caching در سطوح متفاوت و caching داده می توان كارآئی برنامه های وب را بطرز كاملا" محسوسی افزايش داد. در اين بخش به نحوه پياده سازی سيستم caching در برنامه های وب اشاره خواهيم كرد .
در اين بخش همچنان بر روی اولين محور متمركز و به بررسی مسائل در ارتباط با بانك های اطلاعاتی و تاثير آنها در كارآئی يك برنامه وب اشاره خواهيم كرد .
دستيابی به بانك اطلاعاتی
قبل از بررسی اهم مطالب مرتبط با بكارگيری بانك های اطلاعاتی در برنامه های وب لازم است به اين نكته مهم اشاره گردد كه می بايست يك اتصال به بانك اطلاعاتی را صرفا" در زمانی كه به وجود آن نياز است ايجاد و در اولين فرصت ممكن آن را close كرد چراكه اولا" تعداد اتصالات به يك بانك اطلاعاتی محدود و ثانيا" مديريت آنها كار اضافه ای را نيز به سرويس دهنده تحميل خواهد كرد ( استفاده بهينه از يك منبع محدود ) .
با رعايت موارد زير می توان كارآئی برنامه های وب را بهبود بخشيد :
• استفاده از stored procedure : سيستم های مديريت بانك های اطلاعاتی رابطه ای نظير SQL server پيچيدگی های خاص خود را دارند . سيستم های فوق، قادر به انجام كارهای متنوعی هستند كه با استفاده از ASP.NET نمی توان آنها را انجام داد . بكارگيری اين نوع پتانسيل ها می تواند تاثيرات گسترده ای را بر روی برنامه های وب به دنبال داشته باشد . به عنوان نمونه ، استفاده از stored procedure در مقابل Query های توليد شده پويا می تواند تاثير غيرقابل انكاری بر روی كارآيی برنامه های وب داشته باشد چراكه stored procedure را می توان برای استفاده آتی ترجمه و بهينه سازی كرد . تاثير استفاده از stored procedure در مواردی كه لازم است چندين عمليات مرتبط به هم در يك لحظه انجام شود ، بسيار مشهود و ملموس می باشد .
• استفاده از پروفايلينگ و ايندكس : تعريف ايندكس ها بگونه ای كه با نوع جستجو و خواسته های مورد نياز در يك سيستم مطابقت نمايد ، می تواند نتايج مورد نظر را با سرعت قابل قبولی در اختيار كاربران قرار دهد . برای بهينه سازی بی عيب ايندكس ها در يك بانك اطلاعاتی لازم است كه آنها را با استفاده از يك ابزار profiling ارزيابی كرد ( نظير SQL Server Profiler ) . اين نوع ابزارها فعاليت بانك اطلاعاتی را در يك لاگ خاص ثبت می نمايند و در ادامه می توان آن را بررسی ، آناليز و بر اساس نتايج بدست آمده در ايندكس ها تجديد نظر نمود . ابزارهای فوق می توانند مسائلی نظير اجرای كند query را شناسائی و حتی مجموعه ای جديد از ايندكس ها را كه دارای كارآئی بمراتب بهتری می باشند ، پيشنهاد دهند . برای پروفايل بهتر بانك اطلاعاتی لازم است كه يك لود فرضی را بر روی برنامه شبيه سازی كرد.
• بازيابی صرفا" اطلاعات مورد نياز : يكی از ساده ترين روش هائی كه باعث بهبود هر نوع كد بانك اطلاعاتی می گردد ، كاهش حجم اطلاعات بازيابی شده از بانك اطلاعاتی است . اين كار باعث كاهش لود شبكه ، مدت زمان لازم برای باز شدن اتصال و حجم نهائی صفحه می گردد . به عنوان نمونه با استفاده از فيلترينگ مناسب در query ( نظير استفاده از تاريخ ) و بازيابی صرفا" فيلدهای ضروری ، می توان حجم داده بازيابی شده را حتی المقدور كاهش داد .
• استفاده از connection pooling : در يك برنامه وب عمومی ، سيستم مديريت بانك اطلاعاتی درخواست های بيشماری را از طرف سرويس گيرندگان برای صفحات وب متعدد دريافت می نمايد . معمولا" اين اتصالات برای مدت زمان كوتاهی فعال و ايجاد آنها يكی از مراحل وقت گير در زمان پياده سازی است . در صورتی كه هر صفحه وب از connection string مشابه استفاده نمايد ، بانك های اطلاعاتی نظير SQL server قادر به استفاده از connection pooling تعبيه شده در خود برای استفاده مجدد از يك اتصال برای بيش از يك سرويس گيرنده متوالی می باشند . بدين ترتيب امكان استفاده از connection string به دفعات فراهم می گردد. اين كار بطرز چشمگيری باعث بهبود سرعت می گردد . در چنين مواردی می توان از فايل web.config برای ذخيره connection string استفاده تا امكان بكارگيری آنها در صفحات متعدد يك برنامه وب فراهم گردد.
• استفاده از date binding : سريعترين روش بازيابی و نمايش اطلاعات از يك بانك اطلاعاتی ، استفاده از يك DataReader و يا Dataset و نسبت دهی مستقيم آن به يك كنترل داده است . رويكرد فوق ممكن است به عمليات بيشتری جهت استفاده از تمپليت های سفارشی نياز داشته باشد ولی اين وضعيت بمراتب بهتر از حالتی است كه بطور دستی بين سطرها ( ركوردها ) حركت و آنها را در صفحه مورد نظر قرار داد.
• استفاده از caching : در صورتی كه مجموعه ای خاص از داده متناوبا" درخواست و بندرت تغيير می يابد ، می توان آنها را جهت استفاده آتی cache نمود . با استفاده از سيستم caching ، در اولين مرتبه ای كه يك سرويس گيرنده درخواست اطلاعات را می نمايد ، اطلاعات درخواستی از بانك اطلاعاتی خوانده شده و در حافظه موقت قرار می گيرند . بدين ترتيب امكان استفاده مستقيم از اطلاعات cache شده بدون ضرورت دستيابی به بانك اطلاعاتی فراهم می گردد . در بخش های بعدی به بررسی Output caching و data caching خواهيم پرداخت .
session state
اگر صرفا" ID يك خريدار كالا را در session state ذخيره كرده باشيم، درگير مسائلی خاص نخواهيم شد . در چنين مواردی می توان يك سبد خريد كالای الكترونيكی را با ذخيره ليستی از محصولات انتخابی توسط خريدار ايجاد نمود . در صورتی كه قصد ذخيره حجم بالائی از اطلاعات نظير يك Dataset را داشته باشيم ، می بايست در اين رابطه دقت و تاثير آن را بر روی موفقيت برنامه بررسی كرد . به عنوان نمونه ، در صورتی كه هر session فضائی به ميزان يك مگابايت را استفاده نمايد ، يكصد session همزمان باعث استفاده 100 مگابايت از حافظه خواهد شد .
برای حل اين نوع از مشكلات ، در زمان طراحی می توان بر اساس يكی از دو گزينه های زير تصميم گيری نمود :
• ذخيره تمامی اطلاعات مورد نياز در يك ركورد بانك اطلاعاتی و ذخيره ID ركورد مورد نظر در يك session . روش فوق باعث صرفه جوئی در مصرف حافظه می گردد ولی سرعت برنامه را كاهش خواهد داد ( با توجه به فرآيند دستيابی به بانك اطلاعاتی كه يكی از عناصر مهم و تاثيرگذار در خصوص كارآئی برنامه های وب است ) .
• به عنوان يك راه حل بهتر می توان اطلاعات مورد نظر را در يك ركورد بانك اطلاعاتی ذخيره و در ادامه برخی از اطلاعات را در حافظه cache نمود . بدين ترتيب ، امكان بازيابی اطلاعات با سرعت بيشتری فراهم می گردد . در بخش های بعدی با data caching بيشتر آشنا خواهيم شد .
بهترين روش و يا گزينه برای ذخيره session ، استفاده از روش in-process است كه به صورت پيش فرض در نظر گرفته می شود . برای ذخيره session می توان از روش های ديگری نظير يك بانك اطلاعاتی SQL نيز استفاده نمود . استفاده از روش فوق پردازش های بيشتری را به سيستم تحميل و صرفا" در مواردی كه وب سايت مورد نظر در يك web farm به همراه چندين سرويس دهنده هاست شده باشد ، توصيه می گردد .
محور دوم : تست برنامه قبل از عملياتی شدن آن و يا پروفايلنگ ( Profiling )
برای قضاوت در خصوص تلاش های انجام شده در ارتباط با بهبود كارآئی يك برنامه وب ، می بايست قادر به سنجش كارآئی آن در عمل باشيم . در مواردی كه كارآئی يك برنامه كند و نااميد كننده است ، می بايست بر اساس اطلاعات كافی اقدام به شناسائی گره ها و عوامل تاثير گذار بر روی كارآئی برنامه های وب نمائيم تا از اين رهگذر بتوانيم مشكل و يا مشكلات را برطرف و يك برنامه وب كارآ را آماده استفاده عملياتی و نهائی نمائيم .
يكی از مسائل مهم در ارتباط با برنامه های وب ، عدم تست آنها با شرايط مشابه و يا نزديك به محيط واقعی است . در اين راستا می توان از نرم افزارها و يا ابزارهای مختلفی استفاده كرد تا بتوان عملكرد و سرويس دهی يك برنامه وب را قبل از زير بار رفتن واقعی مشاهده و بررسی نمود .
برای قضاوت در خصوص تلاش های انجام شده در ارتباط با بهبود كارآئی يك برنامه وب ، می بايست قادر به سنجش كارآئی آن در عمل باشيم . در مواردی كه كارآئی يك برنامه كند و نااميد كننده است ، می بايست بر اساس اطلاعات كافی اقدام به شناسائی گره ها و عوامل تاثير گذار بر روی كارآئی برنامه های وب نمائيم تا از اين رهگذر بتوان مشكل و يا مشكلات را برطرف و يك برنامه وب كارآ را آماده استفاده عملياتی و نهائی كرد .
شركت مايكروسافت در اين رابطه ابزارها و برنامه های متعددی را ارائه نموده است كه در ادامه به بررسی آنها خواهيم پرداخت .
Stress Testing
به عنوان مثال ، كاهش كارآئی يك برنامه وب ممكن است مربوط به سرعت پائين هارد ديسك ، تنظيمات ضعيف ASP.NET ، عدم طراحی صحيح بانك اطلاعاتی و يا عدم طراحی مناسب برنامه باشد . در واقع، تست كارآئی علم و دانش مختص به خود را دارد .
برای انجام اكثر تست های اوليه ، می توان از يك سرويس دهنده اختصاصی و مجموعه ای از سرويس گيرندگان استفاده نمود كه از طريق يك شبكه سريع ايزوله شده با سرويس دهنده وب تعامل برقرار می نمايند . بدين منظور می توان از يك ابزار توليد load كه بطور اتوماتيك مجموعه ای از صفحات را از سرويس دهنده درخواست می نمايد استفاده كرد تا يك لود سنگين شبيه سازی گردد . ACT ( برگرفته شده از Application Center Test ) و WAST ( برگرفته شده از Web Applications Stress Tool ) دو نمونه متداول در اين زمينه می باشند .
با استفاده از ابزارهای فوق می توان شرايط حاكم بر يك برنامه وب در دنيای واقعی را شبيه سازی نمود ( تداوم درخواست صفحات از طريق چندين اتصال همزمان ) . اكثر ابزارهای توليد load ، فعاليت ها و كارهائی را كه انجام می دهند ثبت می نمايند تا امكان بررسی آنها توسط طراحان و پياده كنندگان وجود داشته باشد .
علاوه بر برنامه های فوق ، می توان نتايج را با استفاده از Windows performance counters ثبت و مشاهده كرد .
performance counter
برای فعال كردن برنامه فوق می توان از مسير Settings|Control Panel |Administrative Tools |Performance استفاده كرد. اين برنامه به صورت پيش فرض صرفا" كارآئی پردازشگر اصلی سيستم و ديسك را اندازه گيری می نمايد .
پس از نصب ASP.NET ، مجموعه ای counter مفيد برای رديابی و ارزيابی كارآئی برنامه های وب نيز نصب می گردد . برای اضافه كردن counter ، با كليك (سمت راست) بر روی ليست counter و انتخاب properties ، می توان گزينه های مختلفی را پيكربندی نمود ( نظير تغيير شكل ظاهری نمودار و نحوه ثبت اطلاعات در قالب يك گزارش ) .
يكی از مهمترين گزينه ها بخش مربوط به Data است كه با استفاده از آن می توان به ليست موجود يك counter را اضافه و يا از آن حذف نمود . برای شروع ، می توان تمامی كانتر های پيش فرض را حذف و با استفاده از گزينه Add موارد دلخواه را به ليست اضافه نمود .
در جعبه محاوره ای Add Counter ، چندين ويژگی مهم از جمله امكان مشخص كردن نام كامپيوتر وجود دارد . به عبارت ديگر ، شما می توانيد كارآئی يك كامپيوتر راه دور را مانيتور نمائيد . مانيتورينگ كارآئی سرويس دهنده وب از طريق يك سرويس گيرنده ايده آل است چراكه احتمال تاثير عملكرد مانيتورينگ بر روی سرويس دهنده از بين خواهد رفت . ويژگی مهم بعدی ، performance object است كه با استفاده از آن می توان يك گروه counter را متناسب با شی مورد نظر انتخاب نمود . گروه ASP.NET اطلاعات كاملی را در خصوص كارآئی كلی برنامه های ASP.NET ارائه می نمايد . اين در حالی است كه گروه ASP.NET Application اطلاعاتی را در رابطه با يك برنامه وب خاص ارائه می نمايد .
برخی از انواع مفيد كانترها به همراه گروه ، نام counter و عملكرد هر يك از آنها در جدول 1 نشان داده شده است .
سطرهای ستاره دار، كانترهائی را مشخص می نمايد كه با استفاده از آنها می توان اشكال زدائی يك مسئله را انجام داد . ساير سطرها ، كانترهائی را نشان می دهد كه استفاده از آنها همواره مفيد می باشد .
گروه | counter | عملكرد |
processor | % CPU Utilization | درصد استفاده از CPUرا نشان می دهد . در صورتی كه استفاده از CPUدر يك بازه زمانی صرفنظر از loadسرويس گيرنده ثابت باقی بماند ، نشان دهنده انتظار يك برنامه برای استفاده از يك منبع محدود است . |
ASP.NET | Requests Queued | تعداد درخواست های در انتظار پردازش را مشخص می نمايد . از counterفوق برای مشخص كردن حداكثر loadسرويس دهنده وب استفاده می گردد . |
ASP.NET | * Application Restarts , | تعداد دفعاتی كه پردازه ASP.NETراه اندازی مجدد و يا resetمی گردد را مشخص می نمايد . اين counterنشاندهنده بروز مسائل ناخواسته است. |
ASP.NET Applications | Requests/Sec | حداكثر توان عملياتی برنامه وب را مشخص می نمايد . |
ASP.NET Applications | * Errors Total | تعداد خطاء توليد شده توسط يك برنامه وب را مشخص می نمايد . مقدار اين counterدر عمل می بايست صفر و يا نزديك به صفر باشد . |
ASP.NET Applications | Pipeline Instance Count | تعداد درخواست pipelineيك برنامه را مشخص می نمايد و از آن برای مشخص شدن حداكثر درخواست همزمانی كه می توان به آنها پاسخ داده شود ، استفاده می گردد . |
System | * Context Switches/sec | پارامتر فوق تعداد دفعات سوئيچينگ thread contextرا نشان می دهد . در صورتی كه مقدار اين پارامتر زياد باشد ، threadهای مختلف برای استفاده از يك منبع محدود با يكديگر رقابت می نمايند . |
جدول 1 : ليست برخی كانترهای مفيد
دستيابی به كلاس های performance counters از طريق كد
به عنوان نمونه می توان يك performance counter جديد را اضافه و يا مقدار متناظر با يك performance counter را بازيابی و در ادامه آن را در يك صفحه وب و يا يك برنامه desktop نمايش داد .
برای استفاده از پتانسيل فوق ، از namespace با نام System.Diagnostics استفاده می گردد . ليست برخی از كلاس های دات نت به منظور تعامل با performance counter در جدول 2 نشان داده شده است .
كلاس | عملكرد |
PerformanceCounter | ارائه يك counterخاص كه شامل اطلاعاتی نظير نام counterو نوع داده ئی است كه می بايست ثبت گردد . |
PerformanceCounterCategory | يك گروه counterرا كه شامل يك و يا چندين counterاست ، مشخص می نمايد . |
CounterCreationData | ارائه داده مورد نياز برای ايجاد يك counterجديد . |
CounterSample | ارائه مجموعه ای از اطلاعات ثبت شده توسط counter. |
جدول 2 : ليست برخی كلاس های دات نت برای كار با Performance counter
مثال : نمايش ظرفيت آزاد حافظه فيزيكی در يك صفحه وب
در كد فوق ، ظرفيت آزاد حافظه فيزيكی بر حسب مگابايت در صفحه وب نمايش داده می شود . برای انجام اين كار ، در ابتدا يك نمونه از كلاس PerformanceCounter به همراه نام گروه Memory و counter با نام Available MBytes ايجاد شده است . برای ايجاد يك نمونه از كلاس PerformanceCounter از كد زير استفاده شده است
Dim perfFreeMem as New PerformanceCounter("Memory", "Available MBytes") |
بدين ترتيب يك شی با نام perfFreeMem ايجاد كه Performance counter مورد نظر را ارائه می نمايد . برای خواندن مقدار جاری counter از متد NextValue استفاده می گردد تا مقدار بعدی Performance counter را برگرداند . با نسبت دادن مقدار برگردانده شده به خصلت Text كنترل سرويس دهنده Label ، امكان مشاهده آن در خروجی فراهم می گردد .
<%@ Import Namespace = System.Diagnostics %> |
مراحل انجام كار در مثال فوق به شرح زير است :
• مرحله اول : استفاده از namespace با نام System.Diagnostics در ابتدای برنامه
• مرحله دوم : ايجاد و مقداردهی مناسب يك نمونه از كلاس PerformanceCounter تا قادر به خواندن counter با نام Available MBytes از گروه Memory باشد .
• مرحله سوم : نسبت دادن مقدار برگردانده شده توسط متد NextValue به خصلت Text كنترل سرويس دهنده label با نام lblFreeMem
در اين بخش به بررسی امكانات caching در ASP.NET 2.0 خواهيم پرداخت .
مفاهيم اوليه Caching
امروزه از مفهوم Caching در زمينه های متعددی در سيستم های كامپيوتری و شبكه ای استفاده می گردد . پردازنده های كامپيوتر دارای cache اختصاصی برای داده و دستورالعمل ها می باشند . سيستم های عامل دارای بافرهای cache برای سيستم های فايل و درايوها می باشند . سيستم های فايل توزيع شده ( شبكه ای ) نظير NFS ( برگرفته شده از network file system ) و AFS ( برگرفته شده از Andrew File System ) برای بهبود كارآئی خود از cache استفاده می نمايند . روترهای بكارگرفته شده در ستون فقرات شبكه اينترنت مسيرهائی را كه اخيرا" از آنها استفاده كرده اند ، cache می نمايند . سرويس دهندگان DNS ، ماحصل فرآيند ترجمه نام به آدرس را جهت استفاد آتی cache می نمايند .
برنامه های كامپيوتری خصوصا" برنامه های وب نيز از اين فناوری در ابعاد گسترده ای استفاده می نمايند تا بتوانند با سرعت بيشتر پاسخگوی نياز كاربران و مخاطبان خود باشند . به عنوان نمونه ، مرورگر با ارائه پتانسل های لازم سمت سرويس گيرنده امكان caching متن و يا تصاوير را فر اهم می نمايد و در سمت سرويس دهنده با استفاده از امكانات متعددی می توان بهترين گزينه caching را به منظور افزايش كارائی انتخاب كرد.
در صورتی كه از روش هائی مناسب به منظور پياده سازی سيستم Caching در برنامه های كامپيوتری استفاده گردد ، كارائی و توانمندی آنها در جهت ارائه خدمات به كاربران بطرز محسوسی افزايش خواهد يافت .
روش های caching در ASP.NET
در ASP.NET از دو نوع سيستم caching استفاده می گردد . پياده كنندگان برنامه های وب می توانند و شايد بهتر باشد بگوئيم می بايست از دو سيستم فوق در جهت افزايش كارآئی برنامه های خود استفاده نمايند ، چراكه دو سيستم فوق مكمل يكديگر می باشند .
• Output caching ، ساده ترين روش caching است . صفحات aspx . بر اساس فرآيندی در سمت سرويس دهنده ترجمه و پس از اجراء ، ماحصل خروجی آنها به صورت يك صفحه html برای سرويس گيرنده ارسال می گردد . در اين روش يك نسخه نهائی از صفحه ترجمه شده html كه برای سرويس گيرنده ارسال شده است ، cache می گردد . بدين ترتيب ، زمانی كه سرويس گيرنده بعدی درخواست خود برای استفاده از اين صفحه را برای سرويس دهنده ارسال می نمايد ، در مقابل اجرای صفحه و توليد خروجی لازم ( انجام پردازش های سمت سرويس دهنده با توجه به ماهيت و جايگاه عملكردی يك صفحه در يك برنامه وب ) ، صفحه ترجمه شده html بطور اتوماتيك برای وی ارسال می گردد . بدين ترتيب ، مدت زمانی كه لازم است صفحه به همراه كد درون آن ترجمه و اجراء گردد بطور كامل حذف می گردد .
• Data caching : برای استفاده از اين روش می بايست بطور دستی و از طريق كد شرايط آن را فراهم نمود . پياده كنندگان می توانند بخش های مهمی از اطلاعات را كه زمان زيادی صرف ساختن آنها شده است ( نظير يك DataSet بازيابی شده از يك بانك اطلاعاتی ) را در cache ذخيره نمايند . در ادامه ، ساير صفحات می توانند وجود اين اطلاعات را بررسی و در صورت موجود بودن در cache از آنها استفاده نمايند . بدين ترتيب ، مراحل مورد نياز برای بازيابی اطلاعات حذف خواهد شد .
روش فوق از لحاظ مفهومی شباهت زيادی به استفاده از application state دارد ولی دارای قابليت های بيشتری در سمت سرويس دهنده است . به عنوان نمونه زمانی كه حجم داده بگونه ای زياد گردد كه كارآئی يك برنامه را تحت تاثير قرار دهد ، آيتم های موجود در cache بطور اتوماتيك از cache حذف خواهند شد . برای ذخيره آيتم ها در cache می توان يك تاريخ را مشخص تا پس از سپری شدن زمان مورد نظر بطور اتوماتيك از حافظه حذف گردند .
علاوه بر روش های كلی فوق ، دو نوع خاص ديگر از caching بر اساس مدل های اشاره شده نيز ايجاد شده است :
• Fragment caching : روش فوق نوع خاصی از output caching است و در مقابل caching كد Html برای تمامی صفحه ، صرفا" بخش هائی خاص از كد cache می گردد. در اين روش خروجی كد ترجمه شده Html مربوط به يك كنترل كاربر بر روی يك صفحه ذخيره می گردد . بدين ترتيب در صورت اجراء مجدد صفحه ، كد موجود در صفحه اجراء می گردد و ضرورتی به اجراء كد مرتبط با كنترل كاربر نخواهد بود .
• Data source caching : اين نوع caching بر اساس كنترل های منبع داده ايجاد و شامل كنترل های منبع داده ObjectDataSource ، SqlDataSource و XmlDataSource می باشد. از لحاظ فنی ، در روش فوق از data caching استفاده می گردد. تنها تفاوت موجود در اين رابطه ، عدم نياز به انجام پردازش های مورد نياز توسط پياده كننده است . بدين منظور لازم است كه برخی خصلت ها و پيام های كنترل منبع داده كه مسئوليت ذخيره و بازيابی caching را برعهده دارند ، توسط پياده كنندگان پيكربندی گردد.
در اين بخش و ساير بخش های بعدی به ترتيب به بررسی موارد زير خواهيم پرداخت :
• output caching
• data caching
• caching در كنترل های منبع داده
• SQL cache dependency
نحوه استفاده از output caching
برای آشنائی با نحوه عملكرد output caching ، كد زير را كه زمان و تاريخ جاری سيستم را در خروجی نشان می دهد ، بررسی می نمائيم .
<%@ OutputCache Duration="20" VaryByParam="None" %> |
متداولترين روش caching يك صفحه ASP.NET ، درج دايركتيو OutputCache در ابتدای فايل aspx . است . كد زير نحوه استفاده از دايركتيو فوق را نشان می دهد :
<%@ OutputCache Duration="20" VaryByParam="None" %> |
در دايركتيو فوق از دو خصلت Duration و VaryByParam استفاده شده است . خصلت Duration به ASP.NET اعلام می نمايد كه صفحه را به مدت 20 ثانيه cache نمايد. خصلت VaryByParam ميزان وابستگی فرآيند caching را به يك و يا چندين پارامتر مشخص می نمايد . در برخی موارد ممكن است اين وابستگی مهم نباشد و مقدار آن None در نظر گرفته شود ( همانند مثال فوق ) .
پس از ذخيره كد فوق در فايلی با نام CacheExample1.aspx و اجراء آن ، نتايج جالب و قابل توجه ای را مشاهده خواهيم كرد . اولين مرتبه ای كه صفحه درخواست می گردد ، تاريخ و زمان جاری در خروجی نمايش داده می شود .در صورتی كه پس از گذشت مدت زمان بسيار كوتاهی صفحه را refresh نمائيم ، خروجی صفحه بهنگام نخواهد شد . در مقابل ، ASP.NET بطور اتوماتيك خروجی نسخه cache شده را ارسال خواهد كرد . وضعيت فوق به مدت 20 ثانيه ادامه خواهد يافت و پس از اتمام تاريخ مصرف نسخه cache شده ، ASP.NET مجددا" كد صفحه را اجراء و يك نسخه جديد cache را ايجاد و از آن به مدت 20 ثانيه ديگر استفاده خواهد كرد .
شايد بنظر 20 ثانيه زمان زيادی نباشد ولی برای سايتی كه حاوی اطلاعات گسترده ای جهت ارائه به كاربران متعدد است ، اين موضوع می تواند كاملا" متفاوت باشد. به عنوان نمونه ، فرض كنيد می خواهيم ليستی از محصولات قابل عرضه به كاربران را در يك صفحه نمايش دهيم . با caching صفحه به مدت 20 ثانيه ، دستيابی به بانك اطلاعاتی محدود به سه عمليات در يك دقيقه می گردد . بدون caching ، برای هر كاربری كه متقاضی مشاهده ليست محصولات است ، می بايست فرآيند ارتباط با بانك اطلاعاتی و نمايش محصولات در يك ساختار نمايشی مناسب ( نظير Gridview ) انجام شود . بديهی است با caching صفحه به مدت 20 ثانيه امكان پاسخگوئی به ده ها درخواست در مدت زمان فوق و بدون نياز به دنبال كردن فرآيند ارتباط با بانك اطلاعاتی و نمايش داده انجام می شود .
توجه داشته باشيد كه اگر مدت زمان حضور يك نسخه cache در حافظه 20 ثانيه تعيين شده باشد ، اين بدان معنی نخواهد بود كه واقعا" در طی مدت زمان فوق نسخه cache شده در حافظه وجود خواهد داشت . صفحه مورد نظر ممكن است در اولين فرصتی كه سيستم به منظور انجام كارهای اساسی تر خود با كمبود حافظه مواجه شود از آن خارج گردد . بدين ترتيب ، پياده كنندگان می توانند با خيالی آسوده از cache استفاده نمايند بدون اين كه نگران تاخير در اجرای برنامه به دليل استفاده از عنصر حياتی حافظه توسط cache باشند.
زمانی كه يك صفحه cache شده مجددا" ترجمه می گردد ، ASP.NET بطور اتوماتيك صفحه را از cache خارج می نمايد . بدين ترتيب از بروز مسائلی نظير عدم وجود نسخه بهنگام شده در cache ممانعت بعمل می آيد .
در زمان تست برنامه بهتر است كه caching غير فعال گردد . در زمان استفاده از روش ها و تكنيك های اشكال زدائی نظير متغيرهای watch و يا ايجاد نقاط breakpoint ممكن است با مشكلاتی مواجه شويم . در چنين مواردی در صورتی كه يك نسخه cache شده از صفحه در دسترس باشد ، كد مرتبط با آن در زمان اشكال زدائی اجراء نخواهد شد .
Caching سمت سرويس گيرنده
برای cache يك صفحه در سمت سرويس گيرنده از خصلت Location در دايركتيو OutputCache استفاده می گردد . مقدار پيش فرض اين خصلت server است و می تواند مقادير ديگر نظير Client ، None و Any را به آن نسبت داد .
<%@ OutputCache Duration="20" VaryByParam="None" Location="Client" %> |
استفاده از caching سمت سرويس گيرنده بمراتب كمتر از caching سمت سرويس دهنده است چراكه صفحه همچنان برای هر كاربر خاص مجددا" ايجاد خواهد شد . در روش فوق ، شاهد كاهش مدت زمان اجراء كد و يا دستيابی به بانك اطلاعاتی در جهت بهبود كارآئی برنامه نخواهيم بود . از روش caching سمت سرويس گيرنده در موارد خاصی نظير زمانی كه صفحه cache شده حاوی داده سفارشی و مختص به يك كاربر است ، استفاده می گردد .
در صورتی كه هر كاربر در يك session مجزاء فعاليت می نمايد ، صفحه يك مرتبه ايجاد و تمامی سرويس گيرندگان از آن استفاده خواهند كرد . در چنين وضعيتی ممكن است عملكرد يك صفحه با مشكل مواجه گردد ( نظير نمايش يك پيام خوش آمدگوئی به كاربر و بر اساس نام آن ) . در مقابل ، می توان از fragment caching برای caching بخش هائی خاص از صفحه و يا caching سمت سرويس گيرنده به منظور ذخيره نسخه مختص يك كاربر بر روی كامپيوتر هر يك از سرويس گيرندگان استفاده نمود.
Caching و Query string
در مواردی كه اطلاعات به صورت پويا توليد می گردد وضعيت caching و يا استراتژی ايجاد و بكارگيری مجدد آن تا اندازه ای متفاوت خواهد بود . به عنوان نمونه ، در صورتی كه در صفحه ای از session كاربر جاری استفاده می شود تا بر اساس آن رابط كاربر سازماندهی گردد ، caching تمام صفحه مناسب نخواهد بود چراكه يك صفحه مشابه نمی تواند برای ساير كاربران مفيد و قابل استفاده مجدد باشد . يك نمونه ديگر ، صفحه ای است كه اطلاعات دريافتی خود را از يك صفحه ديگر و از طريق query string دريافت می نمايد . در چنين مواردی صفحه به صورت پويا ايجاد و برای caching آن می بايست از راهكارهائی ديگر استفاده گردد.
در مثال اشاره شده در بخش چهارم به خصلت VaryByParam دايركتيو OutputCache ، مقدار None نسبت داده شده بود . بدين ترتيب به ASP. NET اعلام شده است كه صرفا" يك نسخه از صفحه را cache نمايد تا بتوان از آن در تمامی حالات استفاده مجدد نمود . در چنين مواردی اگر درخواست صفحه به همراه اضافه كردن آرگومان های query string به URL باشد ، صرفا" از همان يك نسخه cache شده بدون توجه به مقدار آرگومان های دريافتی استفاده می گردد ( تا زمانی كه تاريخ مصرف نسخه cache شده به اتمام نرسيده باشد ) . شما می توانيد اين موضوع را با اضافه كردن يك آرگومان query string بطور دستی در مرورگر انجام دهيد . مثلا" سعی كنيد صفحه را با افزودن a=b ? در انتهای URL اجراء نمائيد. مشاهده خواهيد كرد كه خروجی cache شده همچنان يكسان خواهد بود .
با توجه به نتايج فوق ممكن است اينگونه برداشت شود كه output caching برای صفحه ای كه از آرگومان های query string استفاده می نمايد ، مناسب نباشد . در اين رابطه ASP.NET يك راه حل ديگر را ارائه نموده است . در چنين مواردی می توان خصلت VaryByParam را "*" در نظر گرفت تا مشخص گردد كه صفحه از query string استفاده می نمايد و به ASP.NET اعلام گردد كه نسخه های cache مجزاء را برای مقادير مختلف آرگومان query string ذخيره نمايد .
<%@ OutputCache Duration="20" VaryByParam="*" %> |
بدين ترتيب زمانی كه صفحه به همراه اطلاعات query string درخواست شود ، در ابتدا ASP.NET مقدار query string را بررسی می نمايد . در صورتی كه رشته دريافتی با درخواست قبلی مطابقت نمايد و يك نسخه cache شده از صفحه موجود باشد ، از آن استفاده خواهد كرد . در غير اينصورت يك نسخه جديد از صفحه ايجاد و بطور جداگانه cache می گردد .
برای آشنائی بهتر با نحوه عملكرد فرآيند فوق ، فرض كنيد مجموعه ای از درخواست ها به ترتيب زير دريافت گردد:
• كاربری صفحه ای را بدون پارامتر query string درخواست و نسخه A صفحه را دريافت می نمايد .
• كاربری صفحه را با پارامتر ProductID=1 درخواست و نسخه B صفحه را دريافت می نمايد .
• كاربر ديگر صفحه را با پارامتر ProductID=2 درخواست و نسخه C صفحه را دريافت می نمايد .
• كاربر ديگر صفحه را با پارامتر ProductID=1 درخواست می نمايد . در صورتی كه تاريخ اعتبار نسخه B كه قبلا" cache شده است به اتمام نرسيده باشد ، اين نسخه برای وی ارسال می گردد.
• كاربر ديگر صفحه را بدون پارامتر درخواست می نمايد . در صورتی كه تاريخ اعتبار نسخه A كه قبلا" cache شده است به اتمام نرسيده باشد ، اين نسخه برای وی ارسال می گردد.
برای تست فوق و دريافت نتايج بهتر می توان مدت زمان اعتبار نسخه cache شده را زياد كرد .
در صورتی كه صفحه ای صرفا" در ارتباط با داده سمت سرويس دهنده ( نظير داده موجود در يك بانك اطلاعاتی ) و يا داده موجود در query string باشد ، بدون نگرانی می توان از روش output caching استفاده كرد .
در صورتی كه خروجی صفحه وابسته به اطلاعات خاص و مرتبط با كاربر نظير داده session و يا كوكی باشد ، از روش output caching نمی توان استفاده نمود چراكه مكانيزمی وجود ندارد كه بر اساس آن بتوان تفاوت caching را بر اساس session و يا كوكی تشخيص داد. output caching همچنين با صفحات پويائی كه محتويات خود را در پاسخ به رويدادهای مرتبط با كنترل ها تغيير می دهند كار نمی كند . در چنين مواردی ، می توان از fragment caching برای caching يك بخش خاص از صفحه و يا از data caching برای caching اطلاعات خاص استفاده كرد.
caching با پارامترهائی خاص
<%@ OutputCache Duration="20" VaryByParam="ProductID" %> |
در چنين مواردی ، ASP.NET مقدار query string را بررسی و به دنبال پارامتر ProductID می گردد . درخواست هائی با پارامترهای مختلف ProductID بطور جداگانه cache و از ساير پارامترها صرفنظر خواهد شد .
در صورت لزوم می توان چندين پارامتر را كه توسط semicolon از يكديگر جدا شده اند به خصلت VaryByParam نسبت داد . كد زير نحوه انجام اين كار را نشان می دهد
در چنين مواردی ، ASP.NET نسخه هائی جداگانه از صفحه را با توجه به مقادير متفاوت ارائه شده توسط ProductID و CurrencyType در cache نگهداری خواهد كرد .
<%@ OutputCache Duration="20" VaryByParam="ProductID;CurrencyType" %> |
مثال : Caching چندين نسخه جداگانه از يك صفحه
در اين مثال از دو صفحه برای نشان دادن نحوه caching چندين نسخه جداگانه از يك صفحه وب استفاده شده است .
صفحه QueryStringSender.aspx |
<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %> |
يك event handler ( با نام AnyButton_Click ) پس از كليك بر روی هر يك از سه دكمه موجود در صفحه فعال می گردد . در روتين فوق پس از تشخيص اين كه بر روی كدام دكمه ( cmd2 ، cmd1 و cmd3 ) كليك شده است ، مقدار آن استخراج و به پارامتر Version نسبت داده می شود و در نهايت كاربر به صفحه QueryStringRecipient.aspx هدايت می گردد .
صفحه مقصد ( QueryStringRecipient.aspx ) يك پيام را متناسب با مقدار پارامتر Version در خروجی نمايش می دهد . در صفحه فوق مقدار خصلت VaryByParam دايركتيو OutputCache معادل Version در نظر گرفته شده است.
(صفحه فوق به دنبال يك پارامتر query string با نام Version جهت ايجاد نسخه های جداگانه cache می گردد ) .
<%@ OutputCache Duration="20" VaryByParam="Version" %> |
در صفحه QueryStringRecipient.aspx با توجه به مقدار پارامتر Version ، تاريخ و زمان جاری بر اساس يك فرمت خاص در خروجی نمايش و يك نسخه از آن نيز cache می گردد .
صفحه QueryStringRecipient.aspx |
<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %> |
بدين ترتيب سه خروجی جداگانه Html ايجاد و با توجه به مدت زمان مشخص شده توسط خصلت Duration دايركتيو OutputCache جهت استفاده آتی cache می گردند .
Custom Caching Control
كد نوشته شده در هر يك از رويه های فوق مناسب بودن اطلاعات را بررسی و يك رشته را برمی گرداند . در ادامه ، ASP.NET از رشته فوق برای پياده سازی caching استفاده می نمايد. در صورتی كه كد مورد نظر رشته مشابهی را برای درخواست های مختلف توليد نمايد ، ASP.NET از نسخه cache شده صفحه استفاده خواهد كرد و در صورتی كه كد فوق يك مقدار جديد را توليد نمايد ، ASP.NET يك نسخه جديد cache را ايجاد و آن را بطور جداگانه ذخيره می نمايد .
به عنوان نمونه فرض كنيد قصد داريم نسخه های مختلفی از يك صفحه را بر اساس نوع مرورگر cache نمائيم . بدين منظور در ابتدا از دايركتيو OutputCache در ابتدای صفحاتی كه قصد caching آنها را داريم استفاده كرده و در ادامه از خصلت VaryByCustom برای مشخص كردن يك نام كه نوع caching سفارشی را مشخص می نمايد ، استفاده می نمائيم .
با توجه به اين كه قصد داريم صفحات بر اساس مرورگر كاربران cache نمائيم ، در نمونه كد زير از نام Browser استفاده شده است .
<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="Browser" %> |
در ادامه نياز داريم رويه ای را كه رشته سفارشی caching را توليد می نمايد ، ايجاد نمائيم . رويه فوق می بايست در فايل پيكربندی global.asax و يا فايل code-behind مربوطه باشد .
كد زير نحوه انجام اين كار را نشان می دهد .
رويه ای برای ايجاد سفارشی چندين نسخه cache از يك صفحه
رويه ای برای ايجاد سفارشی چندين نسخه cacheاز يك صفحه |
Function GetVaryByCustomString(ByVal context As HttpContext, ByVal arg As String) As String |
تابع GetVaryByCustomString يك رشته با مقدار VaryByCustom را از طريق پارامتر arg دريافت می نمايد . بدين ترتيب می توان برنامه ای را پياده سازی نمود كه چندين نوع از caching سفارشی را صرفا" در يك تابع مشابه پياده سازی نمايد . هر نوع از يك نام VaryByCustom مختلف استفاده می نمايد ( نظير Browser ، BrowserVersion و يا DayOfWeek ) . تابع فوق مقدار VaryByCustom را از طريق آرگومان arg مشاهده و رشته caching مناسب را برمی گرداند . در صورتی كه رشته های caching برای درخواست های مختلف مطابقت نمايد ، ASP.NET از نسخه cache شده صفحه استفاده می نمايد. در غير اينصورت ASP.NET برای هر رشته caching يك نسخه جداگانه را ايجاد ، ذخيره و cache می نمايد .
دايركتيو OutputCache دارای يك خصلت سوم است كه از آن برای تعريف caching استفاده می گردد . خصلت فوق كه VaryByHeader نام دارد ، به شما اجازه می دهد كه نسخه هائی جداگانه از يك صفحه را بر اساس مقدار دريافتی يك HTTP header ذخيره نمائيد . در اين رابطه می توان صرفا" يك header و يا مجموعه ای header كه توسط semicolon از يكديگر جدا شده اند را مشخص نمود . سايت های چند زبانی می توانند از روش فوق برای caching چندين نسخه از يك صفحه بر اساس زبان مرورگر سرويس گيرنده استفاده نمايند .
كد زير نحوه استفاده از خصلت VaryByHeader را نشان می دهد .
<%@ OutputCache Duration="20" VaryByParam="None" VaryByHeader="Accept-Language" %> |
Fragment Caching
برای پياده سازی fragment Caching می بايست برای بخشی از صفحه كه قصد caching آن را داريم يك كنترل كاربر را ايجاد و دايركتيو OutputCache را به آن اضافه كرد . بدين ترتيب علی رغم اين كه صفحه cache نخواهد شد ولی كنترل كاربر cache می گردد .
fragment Caching از لحاظ مفهومی مشابه caching يك صفحه است و صرفا" دارای يك تفاوت اساسی است . در صورتی كه صفحه يك نسخه cache شده از يك كنترل كاربر را بازيابی نمايد ، نمی تواند با آن و از طريق كد ارتباط برقرار نمايد . به عنوان نمونه در صورتی كه كنترل كاربر خصلت هائی خاص را ارائه می نمايد ، صفحه وب مورد نظر نمی تواند به اين خصلت ها دستيابی و آنها را تغيير دهد . توجه داشته باشيد ، زمانی كه از يك نسخه cache شده كنترل كاربر استفاده می گردد ، يك بلاك از تگ های Html درون صفحه قرار خواهند گرفت و در عمل شی كنترل كاربر در دسترس نخواهد بود .
Cache Profiles
در ASP.NET 2.0 با معرفی يك راهكار جديد اين امكان در اختيار پياده كنندگان گذاشته شده است تا بتوانند از تنظيمات caching مشابه برای گروهی از صفحات استفاده نمايند . به ويژگی فوق cache profile می گويند و به كمك آن می توان تنظيمات caching را در يك فايل web.config تعريف نمود . بدين ترتيب ، اعمال تغييرات صرفا" از طريق يك نقطه فراهم می گردد .
برای تعريف يك Cache Profile ، از تگ <add> در بخش <outputCacheProfiles> فايل web.config استفاده می گردد . به cache profile ايجاد شده يك نام و مدت زمان مناسب نسبت داده می شود . كد زير نحوه انجام اين كار را نشان می دهد .
تعريف يك cache profileدر فايل web.config |
<configuration> |
در ادامه می توان از پروفايل فوق به كمك خصلت CacheProfile در يك صفحه استفاده نمود .
<%@ OutputCache CacheProfile="ProductItemCacheProfile" VaryByParam="None" %> |
در صورتی كه بخواهيم ساير جزئيات caching نظير VaryByParam را نيز مشخص نمائيم می توان آن را به عنوان يك خصلت در دايركتيو OutputCache و يا تگ <add> در پروفايل مشخص نمود .
Output Caching در يك سرويس وب
<WebMethod(CacheDuration:=30)> _ |
در اين بخش به بررسی data caching خواهيم پرداخت .
caching داده
cache يك خصلت از كلاس صفحه است و نمونه ای از كلاس System.Web.Caching.Cache را بر می گرداند . عملكرد شی فوق شباهت زيادی با شی Application دارد ( نظير دستيابی به آن در تمامی صفحات توسط سرويس گيرندگان مختلف ) . علی رغم وجود شباهت های زياد ، دو شی Application و Cache دارای تفاوت هائی اساسی با يكديگر می باشند :
• شی Cache از نوع thread-safe است . اين بدان معنی است كه پياده كنندگان لازم نيست با صراحت عمليات lock و unlock شی cache را قبل از اضافه كردن و يا حذف يك آيتم از cache انجام دهند . به عنوان نمونه ، در صورت ايجاد يك شی سفارشی ممكن است در يك لحظه بيش از يك سرويس گيرنده قصد استفاده از آن را داشته باشند . در چنين مواردی اين احتمال وجود خواهد داشت كه شرايط استفاده از داده غيرمعتبر برای هر يك از سرويس گيرندگان فراهم گردد . برای غلبه بر محدوديت فوق می توان از روش های مختلفی استفاده نمود . ايجاد يك نسخه ديگر از شی به منظور استفاده از آن در يك صفحه ، يكی از ساده ترين راهكارهای موجود در اين زمينه است .
• آيتم های موجود در شی Cache بطور اتوماتيك از آن حذف می گردند . ASP.NET يك آيتم را پس از اتمام مدت زمان اعتبار آن ، در صورت تغيير يكی از اشياء و يا فايل های وابسته و يا كمبود حافظه سرويس دهنده از cache خارج می نمايد . اين بدان معنی است كه پياده كنندگان می توانند با خيالی آسوده از cache استفاده نمايند بدون اين كه نگران از دست دادن منبع ارزشمند حافظه باشند چراكه ASP.NET در صورت نياز آيتم ها را از حافظه خارج خواهد كرد . با توجه به اين كه همواره اين احتمال وجود دارد كه آيتم های ذخيره شده از cache خارج شده باشند می بايست همواره قبل از دستيابی ، موجود بودن آنها در cache بررسی گردد .
• آيتم های موجود در cache از وابستگی ها ( dependencies ) حمايت می نمايند . پياده كنندگان می توانند يك شی cache شده را به يك فايل ، يك جدول بانك اطلاعاتی و يا يك منبع ديگر مرتبط نمايند . در صورت بروز تغييرات در منبع وابسته ، شی cache شده بطور اتوماتيك غيرمعتبر می گردد و در نهايت از حافظه حذف می شود .
اضافه كردن آيتم به cache
Cache("KeyName") = objectToCache |
يكی ديگر از روش های درج داده درون شی cache ، استفاده از متد Insert است . متد فوق دارای چهار نسخه خاص است . در جدول زير ، گرامر يكی از نسخه های فوق كه جزئيات بيش تری از كار را با بكارگيری پنچ پارامتر مشخص می نمايد، نشان داده شده است .
Cache.Insert(key, item, dependencies, absoluteExpiration, slidingExpiration) |
در جدول زير عملكرد هر يك از پارامترهای متد Insert توضيح داده شده است .
پارامتر | عملكرد |
Key | نام در نظر گرفته شده برای آيتم Cacheشده را مشخص می نمايد. بدين ترتيب ، امكان دستيابی به آيتم Cacheشده بر اساس نام فراهم گردد. |
Item | شی واقعی كه قصد cachingآن را داريم ، مشخص می نمايد . |
dependencies | يك شی CacheDependencyكه به شما اجازه می دهد يك وابستگی برای آيتم مورد نظر در cacheرا ايجاد نمائيد . |
absoluteExpiration | يك شی DataTimeكه زمان و تاريخ خارج كردن آيتم cacheشده از cacheرا مشخص می نمايد . |
slidingExpiration | يك شی TimeSpanكه مدت زمان انتظار بين درخواست های متوالی در صورت عدم استفاده از داده cacheشده جهت خروج از cacheرا مشخص می نمايد . |
جدول 1 : پارامترهای متد Insert
معمولا" از تمامی پارامترهای فوق در يك زمان استفاده نمی گردد . به عنوان مثال ، Cache dependencies يك ابزار خاص است كه به كمك آن می توان وابستگی يك آيتم cache شده به ساير منابع تاثيرگذار را مشخص نمود .
در صورتی كه قصد استفاده از يك absolute expiration را داشته باشيم ، می بايست مقدار پارامتر slidingExpiration معادل TimeSpan.Zero در نظر گرفته شود.
Cache.Insert("MyItem", obj, Nothing,DateTime.Now.AddMinutes(60), TimeSpan.Zero) |
در صورتی كه مطمئن باشيم اطلاعات موجود در يك آيتم cache شده در يك بازه زمانی خاص معتبر باقی می ماند ( نظير يك گزارش هواشناسی ) ، استفاده از absolute expiration توصيه می گردد . در صورتی كه داده ذخيره شده در cache همواره معتبر باشد ( نظير كاتولوگ يك محصول ) ، استفاده از Sliding expiration توصيه می گردد . به عنوان يك سياست مطلوب در خصوص بكارگيری Sliding expiration ، می توان مقدار پارامتر absoluteExpiration را به DateTime.Max نسبت داد .
Cache.Insert("MyItem", obj, Nothing,DateTime.MaxValue, TimeSpan.FromMinutes(10)) |
يك مثال كاربردی
ذخيره و بازيابی داده در شی cache |
<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %> |
در اين بخش برای آشنائی با نحوه عملكرد شی cache به بررسی يك نمونه مثال كاربردی پرداختيم كه در آن داده مورد نظر برای مدت زمان خاصی در cache مستقر می گرديد . در ادامه و به منظور پاسخ به درخواست سرويس گيرندگان از داده ذخيره شده در cache مشروط به عدم اتمام تاريخ اعتبار آن استفاده می گرديد . در صورت اتمام تاريخ مصرف نسخه cache شده ، داده جديد توليد و مجددا" در cache قرار می گرفت . در اين مثال صرفا" يك داده ساده در cache قرار می گرفت .
شايد برای شما اين سوال مطرح شده باشد كه آيا می توان اطلاعات پيچيده تری نظير داده بازيابی شده از يك بانك اطلاعاتی را نيز بدين شكل در cache قرار داد تا بتوان از آن برای پاسخ به ساير سرويس گيرندگان استفاده نمود ؟ آيا می توان يك سيستم فيلترينگ را بر اساس داده های cache شده پياده سازی نمود بگونه ای كه متناسب با خواسته كاربر بخشی از داده cache شده در اختيار وی قرار داده شود ؟ اجازه دهيد با بررسی يك مثال كاربردی به سوالات فوق پاسخ دهيم .
مثال : ايجاد caching با قابليت مشاهده چندين view از داده
در اين مثال اطلاعات مورد نظر از يك بانك اطلاعاتی ( به عنوان نمونه Northwind ) بازيابی و پس از ذخيره در يك DataSet در يك Gridview نمايش داده می شود . DataSet در cache ذخيره می گردد تا در آينده و قبل از اتمام تاريخ اعتبار آن بتوان از تمام و يا بخشی از اطلاعات آن متناسب با خواسته كاربر استفاده نمود .
خروجی صفحه وب بر اساس خواسته كاربر و به صورت پويا ايجاد می گردد . در واقع ، كاربر است كه مشخص می كند در خروجی قصد مشاهده چه نوع اطلاعاتی را دارد . خروجی برنامه فوق در چندين ستون مختلف می تواند نمايش داده شود . كاربر با انتخاب يك و يا چندين ستون نظر خود را خصوص نحوه نمايش خروجی مشخص می نمايد .
توضيحات برنامه :
ايجاد DataSetبه كمك يك تابع اختصاصی |
Function RetrieveData() As DataSet |
• در اولين مرتبه ای كه صفحه load می گردد ، ليستی از ستون ها توسط يك كنترل CheckBoxList با نام chckColumns در خروجی و به منظور دريافت نقطه نظرات كاربر نمايش داده می شود . بدين منظور از كد زير در روتين page_load استفاده شده است .
نمايش ليستی از ستون ها توسط يك كنترل CheckBoxList |
chkColumns.DataSource = ds.Tables(0).Columns |
• Dataset به مدت دو دقيقه كه توسط پارامتر sliding expiration مشخص شده است در cache قرار می گيرد . ذخيره Dataset در Cache در زمان ايجاد DataSet و از طريق روتين GetDataSet و به كمك متد Insert شی cache انجام می شود .
ذخيره DataSetدر cacheبه مدت 2 دقيقه |
Cache.Insert("DataSet", ds, Nothing, DateTime.MaxValue,TimeSpan.FromMinutes(2)) |
• پس از كليك بر روی دكمه " فيلتر و نمايش اطلاعات " ، در ابتدا سعی می گردد كه DataSet از طريق cache بازيابی گردد ( استفاده از روتين GetDataSet ) . در صورتی كه صفحه نتواند DataSet را از cache بازيابی نمايد ، تابع RetrieveData فراخوانده می شود تا پس از توليد DataSet در ادامه بتوان آن را به cache اضافه نمود .
برای آگاهی كاربران منبع ارائه اطلاعات نيز در خروجی نمايش داده می شود ( ايجاد و ذخيره اطلاعات در cache و يا بازيابی اطلاعات از cache ) .
بازيابی DataSetاز cacheو يا ايجاد و ذخيره مجدد DataSetدر cache |
Function GetDataSet() As DataSet |
• برای ارائه يك grid قابل پيكربندی ، كد موجود در روتين cmdApply_Click در DataTable حركت و تمامی ستون هائی را كه كاربر جهت عدم نمايش در خروجی فيلتر نموده است ، از grid حذف می نمايد ( قبل از حذف ستون هائی از DataSet يك نسخه ثانويه از آن ايجاد می گردد ) .
در اين رابطه شايد بتوان از گزينه های متعدد ديگری استفاده نمود ولی استراتژی بكار گرفته شده در مثال فوق بيانگر يك حقيقت مهم در خصوص caching است . زمانی كه يك آيتم بازيابی می گردد در واقع يك مرجع به شی cache شده بازيابی شده است و اگر شی تغيير يابد ، در حقيقت آيتم cache شده تغيير يافته است .
فيلترينگ داده بر اساس خواسته كاربر جهت نمايش در Gridview |
Sub cmdApply_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdApply.Click |
كد مثال فوق بطور كامل در جدول زير نشان داده شده است .
ذخيره داده بازيابی شده از بانك اطلاعاتی در cache |
<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %> |
كنترل های ObjectDataSource ، SqlDataSource و XmlDataSource بطور ذاتی از امكانات caching حمايت می نمايند . استفاده از caching به همراه كنترل های فوق اكيدا" توصيه می گردد چراكه برخلاف كد سفارشی نوشته شده توسط پياده كنندگان به منظور دستيابی داده ، كنترل های منبع داده همواره در هر postback يك query را بر روی منبع داده اجراء می نمايند .
كنترل های فوق ، همچنين برای هر كنترل نسبت دهی يك query در سطح منبع داده را اجراء می نمايند . به عنوان نمونه اگر در يك صفحه از سه كنترل نسبت دهی داده در ارتباط با يك منبع داده يكسان استفاده شده باشد ، سه query مجزاء بر روی بانك اطلاعاتی و قبل از تفسير و ارسال صفحه برای سرويس گيرنده ، اجراء خواهد شد . بديهی است حتی با استفاده از امكانات اندك caching به همراه كنترل های منبع داده ، شاهد بهبود چشمگير كارآئی و كاهش load عملياتی در سمت سرويس دهنده خواهيم بود .
با اين كه تعداد زيادی از كنترل های منبع داده از caching حمايت می نمايند ، ولی ويژگی فوق به عنوان يك ضرورت در بكارگيری كنترل های منبع داده مطرح نمی گردد و می توان از كنترل های منبع داده ئی كه از پتانسيل caching حمايت نمی نمايند نيز استفاده كرد .
برای حمايت از caching كنترل های ObjectDataSource ، SqlDataSource و XmlDataSource از خصلت های مشابهی استفاده می نمايند . در جدول 1 ، خصلت های فوق نشان داده شده اند .
خصلت | عملكرد |
EnableCaching | با نسبت دهی مقدار Trueبه خصلت فوق ، پتانسيل cachingفعال می گردد . مقدار پيش فرض خصلت فوق Falseدر نظر گرفته می شود . |
CacheExpirationPolicy | سياست و يا استراتژی زمان اتمام تاريخ اعتبار cacheرا مشخص می نمايد . بر اين اساس می توان مقدار خصلت فوق را ثابت و يا متغير ( مدت زمان بين دو درخواست متوالی ) در نظر گرفت . |
CacheDuration | مدت زمان cachingآيتم مورد نظر در cacheرا بر حسب ثانيه مشخص می نمايد . |
| امكان ايجاد يك وابستگی بين يك آيتم cacheشده با آيتم ديگر در data cache ( با استفاده از CacheKeyDependency) و يا يك جدول بانك اطلاعاتی(با استفاده از SqlCacheDependency) را فراهم می نمايد . |