- برنامههای وب نیازی به نصب بر روی تک تک کلاینتها و همچنین به روز رسانی مداوم کلاینتها را ندارند. به این صورت مدیریت چند صد کاربر در یک سازمان سادهتر از قبل خواهد بود. دیگر نگران این نخواهید بود که آیا فلان کاربر آخرین به روز رسانیها را نصب کرده (دریافت کرده) یا خیر.
- امکان دسترسی از راه دور، برای مثال از طریق اینترنت یا VPN یا RRAS و خطوط دایال آپ (برای مثال دسترسی سادهتر دفاتر مختلف یک سازمان به اطلاعات یکدیگر یا امکان داشتن کارکنانی که از راه دور برای شما کار میکنند).
- امکان ذخیره سازی دادهها در سازمانی دیگر (هاست کردن این برنامهها در محیطهای ابری(!) (cloud computing) هزینههای تهیه و نگهداری سخت افزارهای یک سازمان را نیز کاهش میدهند).
- کاهش هزینههای سازمان با توجه به اینکه اگر از سرورهای قدرتمندی استفاده شود؛ از یک برنامهی وب چندین هزار یا چند میلیون کاربر میتوانند استفاده کنند بدون اینکه نگران تامین هزینه مجوز استفاده از برنامهی تهیه شده به ازای هر کاربر باشید.
- امکان دسترسی به برنامهی وب تهیه شده در انواع و اقسام سیستم عاملهایی که تنها مجهز به یک مرورگر وب هستند (نتیجه نهایی قابل استفاده مستقل از سکو است). برای مثال این روزها به کمک Adobe AIR ، Silverlight و یا کتابخانههای اسکریپتی مانند jQuery و ASP.Net Ajax، بسیاری از تواناییهای نمایشی برنامههای دسکتاپ را در وب نیز میتوان شاهد بود با این خصوصیت که نتیجهی نهایی مستقل از سکو است.
- در این حالت کلاینتها نیازی به داشتن سخت افزارهای قوی ندارند (که در کاهش هزینههای یک سازمان مؤثر است). همچنین این برنامهها مشکلات ناسازگاری با سخت افزارها و نگارشهای مختلف سیستم عاملها را نیز ندارند. بنابراین یک سازمان میتواند بودجهی خود را صرف تهیهی سرورهای بهتری کند.
- کلاینتها با توجه به محدود بودن دسترسیهای امنیتی اعمالی توسط مرورگرها، امنیت بیشتری خواهند داشت. به همین ترتیب کاربران برای استفاده از این برنامهها نیز نیازی به دسترسی بالا در یک سازمان برای اجرای مرورگر خود نخواهند داشت (کمتر جملهی "من دسترسی ادمین میخواهم" را خواهید شنید).
- امکان مونیتور کردن سادهتر فعالیت کاربران در برنامه.
- در صورت محافظت از سرور، کدهای شما از خطر دزدیده شدن مصون(تر) هستند.
- مدیریت سادهتر و مجتمع اطلاعات تولیدی با توجه به اینکه همه چیز باید بر روی سرور ذخیره شود. به این صورت مدیریت نقل مکان کاربران از یک کامپیوتر به کامپیوتری دیگر نیز سادهتر می شود؛ زیرا چیزی را قرار نیست جابجا کنند (نه اطلاعات و نه برنامه را). اگر یکی از کامپیوترهای کلاینتها قابل استفاده نباشد، به سادگی میتواند از کامپیوتری دیگر در شبکه استفاده کند، بدون اینکه معطل تیم فنی شود تا برنامهای را برای او نصب و راه اندازی کنند. به علاوه تهیه پشتیبان از اطلاعات سرورها نیز همیشه سادهتر است از تهیه پشتیبان از 100 ها کامپیوتر موجود در شبکه.
- اگر خروجی برنامهی وب شما تنها از صفحات وب و جاوا اسکریپت تشکیل شده باشد، امکان دسترسی آن در دستگاههای موبایل به سادگی میسر است.
آیا با وجود سیاماس فروشگاهی قدرتمندی مثل nopCommerce یا SmartStore آیا منطقی است که ما دوباره خودمان از صفر کد بزنیم؟
- woocommerce (فروشگاههای تا متوسط و عملیات تجاری سبک) - سفارشی سازی در حد وردپرس - راحته ولی رو اعصابه
- prestashop (فروشگاههای تا متوسط و عملیات تجاری متوسط) - سفارشی سازی متوسط - زیرساختهای خیلی پیشرفته درش وجود ندارد
- magento (فروشگاههای تا سایز بزرگ و عملیات تجاری بزرگ) - سفارشی سازی پیشرفته
- nopCommerce(فروشگاههای تا متوسط و عملیات تجاری متوسط) -سفارشی سازی متوسط
- VirtoCommerce(فروشگاههای تا سایز بزرگ و عملیات تجاری بزرگ) -سفارشی سازی پیشرفته، زمان بر است ولی برای کارهای بزرگ لازم است.
- با ASP.NET چند مورد توسعه داشتیم.
ویژگیهای یک مایکرو سرویس چیست؟
Componentization via Services
Technology Heterogeneity
یک سیستم را در نظر بگیرید که از همکاری چندین سرویس تشکیل شدهاست. ما میتوانیم تصمیم بگیریم که برای هر کدام از سرویسها از تکنولوژی متفاوتی استفاده کنیم. این امر به ما اجازه میدهد برای حل هر مشکل، از بهترین ابزار و تکنولوژی استفاده کنیم. این امر بر خلاف سیستمهایی که تنها باید از تکنولوژی بکار رفته در سیستم استفاده کنند، انعطاف پذیری سیستم را بسیار بالا میبرد.برای روشن شدن موضوع فرض کنید میخواهیم در بخشی از سیستم، performance را افزایش دهیم. برای این امر میتوانیم از هر تکنولوژی که به ما کمک میکند، استفاده کنیم. برای نمونه در یک سیستم شبکه اجتماعی، میتوانیم اطلاعات مربوط به کاربران و ارتباطات آنها را در یک دیتابیس مبتنی بر گراف و اطلاعات مربوط به پستها و نظرات کاربران را در یک دیتابیس سندگرا ذخیره کنیم. به این ترتیب مشاهده میکنیم که وابستهی به تکنولوژی خاصی نمیباشیم و میتوانیم بر اساس نیاز خود، از تکنولوژی مورد نظر بهره ببریم.
مایکرو سرویسها به ما این اجازه را میدهند تا در انتخاب تکنولوژیها نهایت دقت را انجام دهیم و متوجه شویم که تکنولوژیهای جدید چگونه میتوانند به ما کمک کنند.
یکی از بزرگترین موانع در استفاده و انتخاب یک تکنولوژی جدید، ایجاد وابستگی سیستم به آن میباشد. در یک سیستم یکپارچه چنانچه قصد تغییر زبان مورد استفاده یا دیتابیس یا فریمورک مورد استفاده را داشته باشیم، سیستم هزینهی سنگینی را متحمل میشود. در حالیکه در مایکرو سرویسها میتوانیم این تغییرات را با کمترین هزینه انجام دهیم. البته باید توجه داشت که استفاده از تکنولوژی جدید چالشها و سربارهای خودش را دارد و انتخاب یک تکنولوژی جدید نیازمند بررسی کارشناسانه و دقیق میباشد.
Resilience
چنانچه یکی ازسرویسها دچار اشکال شود و این مسئله بصورت زنجیروار برای تمام سرویسها رخ ندهد، با جدا شدن آن سرویس، درروند کار سیستم خللی بوجود نمیآید و سیستم بدون کمترین مشکلی به ادامه کار خود میپردازد. یعنی محدوده یک سرویس، دیوار حائلی میشود تا سایر بخشها تاثیر نپذیرند. در سیستمهای یکپارچه چنانچه یک سرویس دچار اشکال شود، سایر بخشهای سیستم نیز غیر قابل استفاده میشوند. البته میتوان با نصب نسخههای متفاوتی بر روی ماشینهای متفاوت (Scale out)، تاثیر اینگونه اختلالات را تا حدودی کاهش داد. اما بوسیله مایکرو سرویسها میتوانیم سیستمهایی را بسازیم که قادرند با خطاهای بوجود آمده در سرویسها بهدرستی رفتار کنند؛ تا خللی در کار سیستم ایجاد نشود.Scaling
Gilt یک خرده فروش آنلاین در صنعت مد میباشد که بخاطر مسائل Performance به معماری مایکروسرویسها روی آورد. آنها در سال 2007 با یک نرم افزار یکپارچه شروع به کار کردند. اما بعد از دوسال سیستم آنها قادر به مقابله با ترافیک سایت نبود. آنها با تقسیم بندی قسمتهای اصلی سیستم خود به مایکرو سرویسها، توانستند خیلی بهتر و موثرتر با ترافیک رسیده مقابله کنند و قابلیت دسترسی پذیری سیستم را افزایش دهند. در حال حاضر سیستم آنها از حدود 450 مایکرو سرویس تشکیل شده که هر کدام روی چندین ماشین مختلف در حال اجرا میباشند.
Ease of Deployment
Organizational Alignment
Composability
Optimizing for Replaceability
یکی از تجربیاتی که من در زمینه طراحی و پیاده سازی سیستمهای توزیع شده داشتهام «سیستم آمارنامه فرآوردههای دارویی کشور» است. هدف این سیستم، تامین کردن آماری از زنجیره تامین فرآوردههای دارویی کشور است و در آن همه چیز در قالب رخدادهایی که در این زنجیره اتفاق میافتند، بوجود میآید. یعنی ما باید تمام رخدادها را از لحظهای که یک تولید کننده یا وارد کننده، فرآورده را وارد این زنجیره میکند، تا لحظهای که فرآورده توسط داروخانه به مشتری تحویل داده میشود و از زنجیره خارج میشود، ثبت کنیم و در مرحله بعد گزارشات کاملی را از اطلاعات ثبت شده، در اختیار تمام تولید کنندگان، وارد کنندگان، توزیع کنندگان و شعب آنها، داروخانهها، یکسری از ارگانهای دولتی، دانشگاهها و عموم جامعه قرار بدهیم.
نمایی از زنجیره تامین فرآوردههای دارویی و نحوه فراخوانی سرویس آمارنامه
در این سیستم چالشهای بسیار مهمی وجود دارند که پس از بررسیهای انجام شده، برای هر یک راه حلی ارائه خواهد شد:
چالش اول: در دسترس بودن سیستم
در دسترس بودن این سرویس بسیار حیاتی است. یعنی با از دسترس خارج شدن این سرویس، قسمتی از دادههای اصلی خود را از دست میدهیم؛ که باعث میشود آمار ارائه شده درست نباشد.
ارائه راه حل:
بدلیل اینکه احتمال از دسترس خارج شدن یک سرور همیشه وجود دارد، این چالش به تنهایی میتواند دلیل محکمی برای پیاده سازی سیستم بصورت توزیع شده باشد. برای حل این مشکل میتوانیم از روش Active/Standby استفاده کنیم. به این صورت که چند کپی از سرویس روی چند سرور داشته باشیم که هر لحظه یکی از این سرورها فعال باشد. با از دسترس خارج شدن سرور Active، یکی از سرورهای Standby فعال شود و درخواستهای جدید برای این سرور ارسال شوند.
این روش تنها قابلیت در دسترس بودن سیستم را افزایش میدهد و هیچ تاثیری روی کارآیی سیستم ندارد.
برای رفع مشکل فوق، از روش Replicate روی یک یا چند Cluster استفاده میکنیم. یعنی چند کپی از سرویس، روی چند سرور داشته باشیم؛ به این صورت که همه آنها فعال باشند. درخواستها با الگوریتمی که انتخاب میکنیم، از طریق Load Balancer بین این Nodeها پخش میشوند. با این روش، هم کارآیی سیستم بالا میرود و هم همیشه Nodeهایی وجود دارند که جای Nodeهای از دسترس خارج شده را بگیرند.
این روش کارآیی سیستم را افزایش چشمگیری میدهد. اما بدلیل اینکه یک Load Balancer داریم، در صورتیکه به هر دلیلی Load balancer از دسترس خارج شود، کل سیستم از دسترس خارج میشود.
برای رفع مشکل فوق بصورت ترکیبی، از هر دو روش در قسمتهای مختلف استفاده میکنیم که در این روش احتمال از دسترس خارج شدن سیستم به حداقل ممکن میرسد و کارآیی سیستم نیز به حداکثر ممکن میرسد.
(در هر صورت بهترین راه حل برای این چالش، استفاده از سیستمهای توزیع شده است.)
چالش دوم: تعداد کاربران و تعداد درخواست بسیار زیاد و همیشه رو به افزایشند
کاربران این سیستم شامل تمام داروخانههای کشور، تمام توزیع کنندگان و شعب آنها، تمام تولید کنندگان، تمام وارد کنندگان، دانشگاههای مرتبط، یکسری از ارگانهای دولتی و عموم جامعه هستند. یعنی سیستم شامل تعداد کاربران بسیار زیادی است که چیزی در حدود 15000 کاربر از این مجموعه وظیفه دارند بصورت فعال و متناوب با این سیستم کار کنند. کاربران این سیستم همیشه رو به افزایشند.
به نسبت تعدادکاربران و رو به افزایش بودن آنها، درخواست از این سیستم، هیچگاه قطع نمیشود و همیشه رو به افزایش است. با رخ دادن هر Event، یک درخواست برای سیستم ارسال میشود. بطور مثال تنها در آخرین مرحله به ازای هر رخداد داروخانه، درخواستی برای سیستم ارسال میشود (تنها یکی از رخدادهای داروخانه، رخداد فروش است که با ارائه هر نسخه توسط مشتری اتفاق میافتد). با توجه به اینکه در کشور چیزی در حدود 12000 داروخانه وجود دارند، سیستم باید توانایی پاسخ دادن به 12000 درخواست بصورت همزمان و متناوب، آن هم فقط برای رخداد فروش داروخانهها را داشته باشد.
ارائه راه حل:
بدلیل تعداد بسیار زیاد درخواستها و بالا رفتن این تعداد، بصورت لحظهای و حیاتی بودن دسترسی به این سیستم، سیستم باید قابلیت این را داشته باشد که بدون از دسترس خارج شدن، اولا درخواستهای جاری را پاسخ دهد، دوما همیشه آمادگی لازم را برای افزایش تعداد درخواستها، داشته باشد. یعنی به هیچ وجه Scale-up بهتنهایی پاسخگوی نیاز ما نیست و برای رفع این مشکل باید از Scale-out کمک بگیریم. یعنی با افزایش تعداد درخواستها، بدون از دسترس خارج شدن سیستم و با کمترین هزینه و پیچیدگی، Nodeهایی به سیستم اضافه کنیم که قسمتی از بار پردازشی در آنها انجام شود.
در این روش ما میتوانیم به راحتی و با کمترین هزینه، با افزایش تعداد درخواست، Nodeهایی را به Cluster اضافه کنیم تا بار پردازشی اضافی در آنها رفع شود. همچنین برای استفاده بهینه از منابع، با کاهش درخواست، Nodeهایی را از Cluster خارج کنیم. همچنین قابلیت در دسترس بودن این سیستم نیز در بالاترین سطح خود قرار دارد.
چالش سوم: حجم زیاد هر درخواست و زمان زیاد مورد نیاز برای پردازش آن
روال پاسخ دادن به هر درخواست، شامل دریافت درخواست، گرفتن Log از درخواست، اعمال دسترسیهای ارسال کننده درخواست، اعتبارسنجی درخواست، پردازش درخواست، ذخیره آن و پاسخ به کاربر است و بدلیل اینکه هر رخداد میتواند شامل اطلاعات بسیار زیادی باشد، انجام همه این اعمال، زمان زیادی را میطلبد. همچنین با توجه به تعداد کاربران، تعداد درخواست و حجم دادهای که باید ذخیره کنیم - در صورتی که هر درخواست نیز بخواهد در مدت زمان زیادی پردازش شود - سیستم با حجم بسیار زیادی از درخواست مواجه است که هر یک زمانی زیادی را نیز برای پردازش نیاز دارد.
ارائه راه حل:
در صورت ارائه راه حل نادرست برای حل این چالش، با توجه به تعداد درخواست و دادههایی که در سیستم ذخیره شدهاند، این چالش میتواند برای سیستم، مشکلات بسیار زیادی را ایجاد کند. به همین دلیل باید این پردازش بزرگ را به پردازشهای کوچکتری که قابلیت Concurrency را با کمترین میزان تاخیر دارند و هدف همه آنها پاسخ دادن به کاربر است، تبدیل کنیم.
با تقسیم بندی وظایف و قرار دادن هریک از این وظایف در سخت افزارهای متفاوت، سیستم این قابلیت را دارد که برای کاربر همیشه در دسترس باشد. در کمترین زمان بیشترین تعداد درخواست را بصورت همزمان و با کمترین تاخیر پردازش کند و با افزایش درخواستها، برای هر قسمت میتوانیم تعداد Node موجود در آن قسمت را افزایش دهیم.
چالش چهارم: حجم بسیار زیاد و رو به افزایش دادههای سیستم
دادههای این سیستم ذاتا همیشه و در هر شرایطی رو به افزایش هستند و هیچگاه جریان داده، در این سیستم قطع نمیشود. با توجه به تعداد کاربران، تعداد درخواست و نوع داده، ما با حجم دادهی بسیار زیادی روبرو هستیم که پایانی ندارند.
ارائه راه حل:
با توجه به حیاتی بودن دسترسی به سیستم و سایر چالشهایی که در قسمتهای قبلی ذکر شد، در صورتیکه حتی تمام قسمتهای قبل را بهدرستی طراحی و پیاده سازی کنیم، اگر برای این چالش راه حل درستی را ارائه ندهیم، تمامی راه حلهای قبلی که ارائه کردیم، بی فایده میباشند. چون با از دسترس خارج شدن Database، کل سیستم از دسترس خارج میشود.
برای رفع این مشکل واقعا نمیتوان از یک سخت افزار استفاده کرد؛ چون دقیقا شبیه به این است که تعداد خودروهای بسیار زیادی که از طریق یک بزرگراه چند بانده حرکت میکنند و جریان آنها هیچگاه قطع نمیشود، در انتهای مسیر وارد یک پارکینگ شوند. یعنی در انتها باید وارد یک پارکینگ شوند که در هر لحظه ممکن است ظرفیت آن پر شود. گذشته از این برای رفتن به این پارکینگ باید وارد یک صف شوند که زمان انتظار آنها را افزایش میدهد. یک سخت افزار همیشه قابلیت از دسترس خارج شدن را دارد. با جریان داده افزایشی، همیشه احتمال پر شدن حافظهاش وجود دارد. گذشته از همه اینها به احتمال زیاد قادر به پاسخ دادن به تعداد درخواستهای بسیار زیادی که هر لحظه ممکن است تعداد آنها بیشتر شود را نیز نداشته باشد.
نتیجه گیری این است که تقریبا تمام چالشهایی که برای سرویس وجود داشت، برای Database نیز وجود دارد. به همین دلیل باید Database نیز بصورت توزیع شده پیاده سازی شود:
این طراحی تقریبا تمامی قابلیتهای طراحی سرویسمان را دارد. یعنی با افزایش تعداد درخواست، یا کم شدن فضای ذخیره سازی در هر یک از Nodeها، ما این قابلیت را داریم که Nodeهایی را به آن اضافه کنیم. همچنین بدلیل اینکه دادههای ما در دو یا چند Node کپی شدهاند، با از دسترس خارج شدن هر Node همیشه Nodeهایی وجود دارند که جای Node معیوب را بگیرند؛ تا زمانیکه Node معیوب دوباره به سیستم بازگردد.
همانطور که دیدید، هر یک از چالشهای ذکر شده به تنهایی قابلیت این را دارند که سیستم خود را بهصورت توزیع شده پیاده سازی کنید. اما نکته بسیار مهمی که باید همیشه در نظر داشته باشید این است که تصمیمات شما همیشه باید با بررسیهای کامل از جنبههای مختلف گرفته شوند. در دنیای واقعی علاوه برفاکتورهایی که هر یک بصورت یک چالش در قسمت بالا ذکر شد، فاکتورهای دیگری نیز وجود دارند که میتوانند عاملی برای انتخاب، یا عدم انتخاب سیستمهای توزیع شده باشند. فاکتورهایی که در ادامه مطلب ذکر میشوند.
مهمترین فاکتورهای انتخاب سیستمهای توزیع شده:
1- هزینه: هزینه میتواند مهمترین فاکتور در انتخاب یک سیستم توزیع شده باشد. هیچ کسی نمیخواهد سیستمی را طراحی کند که هزینه طراحی، پیاده سازی و نگهداری آن بیشتر از سود حاصل از آن باشد. یا کمتر پیش میآید که گروهی تصمیم بگیرند که وقتی که یک نوع طراحی و پیاده سازی با هزینه کمتر جوابگوی نیازهای آنها است، از نوع طراحی و پیاده سازی استفاده کنند که هزینه بیشتری را برای آنها ایجاد میکند؛ حتی در صورتیکه طراحی دوم قابلیتهای بیشتری را نیز ایجاد کند.
2- در دسترس بودن سیستم: گاهی ممکن است یک لحظه از دسترس خارج شدن سیستم، عواقب جبران ناپذیری را برای کل سیستم بهوجود بیاورد. در این حالت بهترین انتخاب، سیستمهای توزیع شده است.
3- تعداد یا نوع کاربران سیستم: تعداد کاربرانی که همیشه رو به افزایشند، میتواند فاکتور بسیار مهمی در انتخاب یک سیستم توزیع شده باشد. اما مشکلی که وجود دارد این است که همیشه در ابتدای طراحی این تعداد مشخص نیست. گاهی نیاز است نوع طراحی خود را با توجه به نوع کاربران سیستم انتخاب کنید. بطور مثال سیستم شما نیازهای کاربران یک مکان یا سازمان خاص را رفع میکند، یا نیازهای یک جامعه را رفع میکند. در صورتیکه سیستم شما نیاز کاربران یک محیط بزرگ را رفع کند، همیشه باید منتظر بالا رفتن میزان کاربران سیستم نیز باشید.
4- تعداد درخواستهای از سیستم: تعداد درخواستها در اکثر موارد وابستگی بسیار زیادی به تعداد یا نوع کاربران دارد. پوشش دادن تعداد زیاد درخواست، بصورت متناوب و رو به افزایش میتواند فاکتور بسیار مهمی در انتخاب یک سیستم توزیع شده باشد.
5- نوع و حجم عملیاتی که انجام میدهیم: برخی عملیات ممکن است زمان بسیار زیادی برای اجرا نیاز داشته باشند که میتواند روی سیستم ما تاثیر بسیار زیادی بگذارند. برای افزایش کارآیی و پردازش تعداد بیشتر درخواستها، گاهی بهتر است یک عملیات را تبدیل به عملیاتی کوچکتر کرد و هرکدام از این عملیات کوچکتر را در یک سخت افزار جداگانه اجرا کرد.
6- نوع و حجم دادههایی که نیاز به ذخیره شدن دارند: نوع دادههایی که ذاتا همیشه رو به افزایشند میتواند فاکتور بسیار مهمی در انتخاب سیستمهای توزیع شده باشد. البته این مورد نیز همیشه از ابتدای طراحی مشخص نیست. نوع کاربران شما میتوانند کمک بسیار بزرگی در انتخاب این فاکتور داشته باشند.
7- کارآیی: با یک طراحی و تقسیم بندی درست در قسمتهای مختلف سیستم میتوان حجم و تعداد بسیار زیادی از پردازشها را بصورت همزمان اجرا کرد. البته کاملا بصورت انعطاف پذیر؛ به صورتیکه با بیشتر شدن تعداد و حجم پردازش، سیستم بدون از دسترس خارج شدن، قادر به پوشش دادن آنها باشد.
8- امنیت: پردازش شما میتواند تقسیم بندی شود. بصورتیکه هر قسمت در سرور جداگانهای که از قبل مشخص نیست، اجرا شود. سروری که حتی به اینترنت هم وصل نیست. با طراحی درست میتوان امنیت سیستم را بسیار افزایش داد.
9- موقعیت جغرافیایی کاربران: گاهی بدلیل تعداد زیاد کاربران نیاز است درخواستهای هر کاربر، در نزدیکترین سرور به او پردازش شود. این فاکتور در سیستمهای بسیار بزرگ دلیل بسیار مهمی در انتخاب سیستمهای توزیع شدهاست.
علاوه بر موارد فوق مواردی را مانند Internet of things یا همان IOT که پایه و اساس آن سیستمهای توزیع شدهاست، یا مواردی را مانند Machine learning که میتواند بصورت توزیع شده پیاده سازی شود، نیز در نظر بگیرید.
با در نظر گرفتن تمام موارد فوق و شرایط اختصاصی سیستمی که طراحی میکنید، سعی کنید بهترین انتخاب را انجام دهید.
- وقتی دیتایی داریم که به تکرار از آن در برنامه استفاده میکنیم.
- وقتی بعد از گرفتن دیتایی از دیتابیس، محاسباتی بر روی آن انجام میدهیم و پاسخ نهایی محاسبه را به کاربر نمایش میدهیم، میتوانیم یکبار پاسخ را کش کنیم تا از محاسبهی هر بارهی آن جلوگیری شود.
- سخت افزاری که برای کش استفاده میکنیم یعنی Ram، بسیار گرانتر از دیتابیس برای ما تمام میشود؛ چرا که محدود است.
- اگر همه دیتاهارا کش کنید، عمل سرچ میان آن زمان بیشتری خواهد برد.
این روش تا زمانیکه برنامهی ما برای اجرا شدن، تنها از یک سرور استفاده کند، بهترین انتخاب خواهد بود؛ چرا که به دلیل نزدیک بودن، سریعترین بازخورد را نیز به درخواستها ارائه میدهد.
اما شرایطی را فرض کنید که برنامه از چندین سرور برای اجرا شدن استفاده میکند و به طبع هر سرور درخواستهای خودش را داراست که ما باید برای هر یک بصورت جداگانهای یک کش In-Memory را در حافظه Ram هرکدام ایجاد کنیم.
فرض کنید دیتای ما 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 باشد. بخشی از دیتا در Server 1 کش میشود (1 , 3 , 5 , 9) و بخشی دیگر در Server 2 کش خواهد شد (2 , 4 , 6 ,7 , 8 , 10).
در اینجا مشکلات و ضعف هایی به وجود خواهد آمد :
- برای مثال اگر Server 1 به هر دلیلی از بین برود یا Down شود، اطلاعات کش درون آن نیز پاک خواهد شد و بعد از راه اندازی باید همه آن را دوباره از دیتابیس بخواند.
- هر کدام از سرورها کشهای جدایی دارند و باهم Sync نیستند و امکان وجود یک دادهی حیاتی در یکی و عدم وجود آن در دیگری، بالاست. فرض کنید برنامه برای هر درخواست، نیاز به اطلاعات دسترسی کاربری را دارد. دسترسیهای کاربر، در Server 1 کش شده، اما در Server 2 موجود نیست. در Server 2 به دلیل عدم وجود این کش، برنامه برای درخواستهای معمول خود و چک کردن دسترسی کاربر یا باید هربار به دیتابیس درخواستی را ارسال کند که این برخلاف خواسته ماست و یا باید دیتای مربوط به دسترسیهای کاربر را بعد از یکبار درخواست، از دیتابیس در خودش کش کند که اینهم دوباره کاری به حساب میاید و دوبار کش کردن یک دیتا، امر مطلوبی نخواهد بود.
روش هایی وجود دارد که بتوان از سیستم Local Caching در حالت چند سروری هم استفاده کرد و این مشکلات را از بین برد، اما روش استاندارد در حالت چند سروری، استفاده از Distributed Cacheها است.
روش دوم : Distributed Caching
در این روش برنامهی ما برای اجرا شدن از چندین سرور شبکه شده به هم، در حال استفاده هست و Cache برنامه، توسط سرورها به اشتراک گذاشته شده.
در این حالت سرورهای ما از یک کش عمومی استفاده میکنند که مزایای آن شامل :
■ درخواستها به چندین سرور مختلف از هم ارسال شده، اما دیتای کش بصورت منسجم در هریک وجود خواهد داشت.
■ با خراب شدن یا Down شدن یک سرور، کش موجود در سرورهای دیگر پاک نمیشود و کماکان قابل استفاده است.
■ به حافظه Ram یک سرور محدود نیست و مشکلات زیادی همچون کمبود سخت افزاری و محدودیتهای حافظهی Ram را تا حد معقولی کاهش میدهد.
طریقه استفاده از Cache در Asp.Net Core :
- بر خلاف ASP.NET web forms و ASP.NET MVC در نسخههای Core به بعد، Cache بصورت از پیش ثبت شده، وجود ندارد. کش در Asp.Net Core با فراخوانی سرویسهای مربوطهی آن قابل استفاده است و نیاز است قبل از استفاده، سرویس آن را در کلاس Startup برنامه فراخوانی کنید.
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddMemoryCache(); }
- اینترفیس IMemoryCache از سیستم تزریق وابستگیها در Core استفاده میکند و برای استفاده از اینترفیس آن، پس از اضافه کردن MemoryCache به Startup ، باید در کنترلر، عمل تزریق وابستگی (DI) را انجام دهید؛ سپس متدهای مورد نیاز برای کش، در دسترس خواهد بود.
public class HomeController : Controller { private readonly IMemoryCache _cache; public HomeController(IMemoryCache cache) { _cache = cache; } .... }
- برای ذخیرهی کش میتوانید از متد Set موجود در این اینترفیس استفاده کنید.
public IActionResult Set() { _cache.Set("CacheKey", data , TimeSpan.FromDays(1)); return View(); }
در پارامتر اول این متد (CacheKey)، یک کلید، برای اطلاعاتی که میخواهیم کش کنیم قرار میدهیم. دقت کنید که این کلید، شناسهی دیتای شماست و باید طوری آن را در نظر گرفت که با صدا زدن این کلید از سرویس کش، همان دیتای مورد نظر را برگشت دهد (هر Object دیتا، باید کلید Unique خود را داشته باشد).
در پارامتر دوم، دیتای مورد نظر را که میخواهیم کش کنیم، به متد میدهیم و در پارامتر سوم نیز زمان اعتبار و تاریخ انقضای دیتای کش شده را وارد میکنیم؛ به این معنا که دیتای کش شده، بعد از مدت زمان گفته شده، از حافظه کش(Ram) حذف شود و برای دسترسی دوباره و کش کردن دوباره اطلاعات، نیاز به خواندن مجدد از دیتابیس باشد.
- برای دسترسی به اطلاعات کش شده میتوانید از متد Get استفاده کنید.
public IActionResult Get() { string data = _cache.Get("CacheKey"); return View(data); }
تنها پارامتر ورودی این متد، کلید از قبل نسبت داده شده به اطلاعات کش هست که با استفاده از یکسان بودن کلید در ورودی این متد و کلید Set شده از قبل در حافظه Ram، دیتا مربوط به آن را برگشت میدهد.
- متد TryGetValue برای بررسی وجود یا عدم وجود یک کلید در حافظه کش هست و یک Boolean را خروجی میدهد.
public IActionResult Set() { DateTime data; // Look for cache key. if (!_cache.TryGetValue( "CacheKey" , out data)) { // Key not in cache, so get data. data= DateTime.Now; // Save data in cache and set the relative expiration time to one day _cache.Set( "CacheKey" , data, TimeSpan.FromDays(1)); } return View(data); }
این متد ابتدا بررسی میکند که کلیدی با نام "CacheKey" وجود دارد یا خیر؟ در صورت عدم وجود، آن را میسازد و دیتای مورد نظر را به آن نسبت میدهد.
- با استفاده از متد GetOrCreate میتوانید کار متدهای Get و Set را باهم انجام دهید و در یک متد، وجود یا عدم وجود کش را بررسی و در صورت وجود، مقداری را return و در صورت عدم وجود، ابتدا ایجاد کش و بعد return مقدار کش شده را انجام دهید.
public IActionResult GetOrCreate() { var data = _cache.GetOrCreate( "CacheKey" , entry => entry.SlidingExpiration = TimeSpan.FromSeconds(3); return View(data); }); return View(data); }
- برای مدیریت حافظهی Ram شما باید یک Expiration Time را برای کشهای خود مشخص کنید؛ تا هم حافظه Ram را حجیم نکنید و هم در هر بازهی زمانی، دیتای بروز را از دیتابیس بخوانید. برای این کار optionهای متفاوتی از جمله absolute expiration و sliding expiration وجود دارند.
در اینجا absolute expiration به این معنا است که یک زمان قطعی را برای منقضی شدن کشها مشخص میکند؛ به عبارتی میگوییم کش با کلید فلان، در تاریخ و ساعت فلان حذف شود. اما در sliding expiration یک بازه زمانی برای منقضی شدن کشها مشخص میکنیم؛ یعنی میگوییم بعد از گذشت فلان دقیقه از ایجاد کش، آن را حذف کن و اگر در طی این مدت مجددا خوانده شد، طول مدت زمان آن تمدید خواهد شد.
این تنظیمات را میتوانید در قالب یک option زمان Set کردن یک کش، به آن بدهید.
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions(); options.AbsoluteExpiration = DateTime.Now.AddMinutes(1); options.SlidingExpiration = TimeSpan.FromMinutes(1); _cache.Set("CacheKey", data, options );
در مثال بالا هردو option اضافه شده یک کار را انجام میدهند؛ با این تفاوت که absolute expiration تاریخ now را گرفته و یک دقیقه بعد را به آن اضافه کرده و تاریخ انقضای کش را با آن تاریخ set میکند. اما sliding expiration از حالا بمدت یک دقیقه اعتبار دارد.
- یکی از روشهای مدیریت حافظه Ram در کشها این است که برای حذف شدن کشها از حافظه، اولویت بندیهایی را تعریف کنید. اولویتها در چهار سطح قابل دسترسی است:
- NeverRemove = 3
- High = 2
- Normal = 1
- Low = 0
این اولویت بندیها زمانی کاربرد خواهند داشت که حافظه اختصاصی Ram، برای کشها پر شده باشد و در این حالت سیستم کشینگ بصورت خودمختار، کشهای با الویت پایین را از حافظه حذف میکند و کشهای با الویت بیشتر، در حافظه باقی میمانند. این با شماست که الویت را برای دیتاهای خود تعیین کنید؛ پس باید با دقت و فکر شده این کار را انجام دهید.
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions(); // Low / Normal / High / NeverRemove options.Priority = CacheItemPriority.High; cache.Set("CacheKey", data, options);
به این صورت میتوانید الویتهای متفاوت را در قالب option به کشهای خود اختصاص دهید.
در این مقاله سعی شد مفاهیم اولیه Cache، طوری گفته شود، تا برای افرادی که میخواهند به تازگی این سیستم را بیاموزند و در پروژههای خود استفاده کنند، کاربردی باشد و درک نسبی را نسبت به مزایا و محدودیتهای این سیستم بدست آورند.
در قسمت دوم همین مقاله بطور تخصصیتر به این مبحث میپردازیم و یک پکیج آماده را معرفی میکنیم که خیلی راحتتر و اصولیتر کش را برای ما پیاده سازی میکند.
مروری مختصر بر زبان DMX
برای بسیاری داده کاوی تنها مجموعه ای از تعدادی الگوریتم تعبیر میشود؛ به همان طریقی که در گذشته تصورشان از بانک اطلاعاتی تنها ساختاری سلسله مراتبی به منظور ذخیره دادهها بود. بدین ترتیب داده کاوی به ابزاری تبدیل شده که تنها در انحصار تعدادی متخصص (بویژه PhDهای علم آمار و یادگیری ماشین) قرار دارد که آشنائی با اصطلاحات یک زمینه خاص را دارند. هدف از ایجاد زبان DMX تعریف مفاهیمی استاندارد و گزارهایی متداول است که در دنیای داده کاوی استفاده میشود به شکلی که زبان SQL برای بانک اطلاعاتی این کار را انجام میدهد.
فرضیه اساسی در داده کاوی و همچنین یادگیری ماشین از این قرار است که تعدادی نمونه به الگوریتم نشان داده میشود و الگوریتم با استفاده از این نمونهها قادر است به استخراج الگوها بپردازد. بدین ترتیب به منظور بازبینی و همچنین استنتاج از اطلاعات درباره نمونههای جدید میتواند مورد استفاده قرار گیرد.
ذکر این نکته ضروری است که الگوهای استخراج شده میتوانند مفید، آموزنده و دقیق باشند. تصویر زیر به اختصار مراحل فرآیند داده کاوی را نمایان میسازد:
در گام نخست اقدام به تعریف مسئله و فرموله کردن آن میکنیم که اصطلاحاً Mining Model نامیده میشود. در واقع Mining Model توصیف کننده این است که داده نمونه به چه شکل به نظر میرسد و چگونه الگوریتم داده کاوی باید دادهها را تفسیر کند. در گام بعدی به فراهم کردن نمونههای داده برای الگوریتم میپردازیم، الگوریتم با بهره گیری از Mining Model به طریقی که یک لنز دادهها را مرتب میکند، به بررسی دادهها و استخراج الگوها میپردازد؛ این عملیات را اصطلاحاً Training Model مینامیم. هنگامی که این عملیات به پایان رسید، بسته به اینکه چگونه آنرا انجام داده اید، میتوانید به تحلیل الگوهایی که توسط الگوریتم از روی نمونه هایتان بدست آمده بپردازید. و در نهایت میتوانید اقدام به فراهم کردن دادههای جدید و فرموله کردن آنها، به همان طریقی که نمونهها آموزش دیده اند، به منظور انجام پیش بینی و استنتاج از اطلاعات با استفاده از الگوهای کشف شده توسط الگوریتم پرداخت.
زبان DMX وظیفه تبدیل دادههای موجودتان (سطرها و ستونهای Tables) به دادههای مورد نیاز الگوریتمهای داده کاوی (Cases و Attributes) را دارد. به منظور انجام این تبدیل به Mining Structure و Mining Model (که در قسمت اول به شرح آن پرداخته شد) نیاز است. بطور خلاصه Mining Structure صورت مسئله را توصیف میکند و Mining Model وظیفه تبدیل سطرهای داده ای به درون Caseها و انجام عملیات یادگیری ماشین با استفاده از الگوریتم داده کاوی مشخص شده را بر عهده دارد.
Syntax زبان DMX
مشابه زبان SQL دستورات زبان DMX نیز به محیطی جهت اجرا نیاز دارند که میتوان با استفاده از (SQL Server Management Studio (SSMS به اجرای دستورات DMX اقدام نمود. ایجاد ساختار کاوش (Mining Structure) و مدل کاوشی (Mining Model) مشابه دستورات ایجاد Table در زبان SQL میباشد. همانطور که اشاره شد، گام اول (از سه مرحله اصلی در داده کاوی) ایجاد یک مدل کاوش است؛ شامل تعیین تعداد ستونهای ورودی، ستونهای قابل پیش بینی و مشخص کردن نام الگوریتم مورد استفاده در مدل. گام دوم آموزش مدل که پردازش نیز نامیده میشود و گام سوم مرحله پیش بینی است که نیاز به یک مدل کاوش آموزش دیده و مجموعه اطلاعات جدید دارد. در طول پیش بینی، موتور داده کاوی قوانین (Rules) پیدا شده در مرحلهی آموزش (یادگیری) را با مجموعه اطلاعات جدید تطبیق داده و نتیجه پیش بینی را برای هر Case ورودی انجام میدهد. دو نوع پرس و جوی پیش بینی وجود دارد Batch و Singleton که به ترتیب چند Case ورودی دارد و خروجی در یک جدول ذخیره میشود و دیگری تنها یک Case ورودی دارد و خروجی در زمان اجرا ساخته میشود.
در زبان DMX دو روش برای ساخت مدلهای کاوش وجود دارد:
• ایجاد یک ساختار کاوش و مدل کاوش مربوط به هم و تحت یک نام، زمانی کاربرد دارد که یک ساختار کاوش فقط شامل یک مدل کاوش باشد.
• ایجاد یک ساختار کاوش و سپس اضافه نمودن یک مدل کاوش به ساختار تعریف شده، زمانی کاربرد دارد که یک ساختار کاوش شامل چندین مدل کاوشی باشد. دلایل مختلفی وجود دارد که ممکن است نیاز به این روش باشد، برای مثال ممکن است مدلهای متعددی را با استفاده از الگوریتمهای مختلف ساخت و سپس بررسی نمود که کدام مدل بهتر عمل خواهد کرد و یا مدلهای متعددی را با استفاده از یک الگوریتم ولی با مجموعه پارامترهای متفاوت برای هر مدل ساخت و سپس بهترین را انتخاب نمود.
عناصر سازندهی ساختار کاوش، ستونهای ساختار کاوشی هستند که داده هایی را که منبع اصلی داده فراهم میکند، توصیف میکند. این ستونها شامل اطلاعاتی از قبیل نوع داده (Data Type)، نوع محتوا (Content Type)، ماهیت داده و اینکه داده چگونه توزیع شده است میباشند. نوع محتوا پیوسته و یا گسسته بودن آن را مشخص میکند و بدین ترتیب به الگوریتم راه درست مدل کردن ستون را نشان میدهیم. کلمه کلیدی Discrete برای ماهیت گسسته داده و از کلمه Continuous برای ماهیت پیوسته داده استفاده میشود. مقادیر نوع داده و نوع محتوا به قرار زیر میباشند:
Data Type | کاربرد |
LONG | اعداد صحیح |
DOUBLE | اعداد اعشاری |
TEXT | دادههای رشته ای |
DATE | دادههای تاریخی |
BOOLEAN | دادههای منطقی (True و False) |
TABLE | برای تعریف Nested Case |
Content Type | کاربرد |
KEY | مشخص کننده کلید |
DISCRETE | دادههای گسسته |
CONTINUOUS | دادههای پیوسته |
DISCRETIZED | دادههای گسسته شده |
KEY TIME | کلید زمان، تنها در مدلهای Time Series استفاده میشود |
KEY SEQUENCE | کلید توالی، تنها در بخش Nested Table مدلهای Sequence Clustering استفاده میشود |
همچنین یک مدل کاوش استفاده و کاربرد هر ستون و الگوریتمی که برای ساخت مدل استفاده میشود را تعریف میکند، میتوانید با استفاده از کلمه کلیدی Predict و یا Predict_Only خاصیت پیش بینی را به ستونها اضافه نمود، برای نمونه به دستورات زیر توجه نمائید:
CREATE MINING STRUCTURE [New Mailing] ( CustomerKey LONG KEY, Gender TEXT DISCRETE, [Number Cars Owned] LONG DISCRETE, [Bike Buyer] LONG DISCRETE ) GO ALTER MINING STRUCTURE [New Mailing] ADD MINING MODEL [Naive Bayes] ( CustomerKey, Gender, [Number Cars Owned], [Bike Buyer] PREDICT ) USING Microsoft_Naive_Bayes
به منظور آموزش یک مدل کاوش از دستور Insert به شکل زیر استفاده میشود:
INSERT INTO <mining model name> [<mapped model columns>] <source data query>
در ادامه به شکل عملی میتوانید با طی مراحل و اجرای کوئریهای زیر به بررسی بیشتر موضوع بپردازید.
ابتدا به سرویس SSAS متصل شوید و اقدام به ایجاد یک Database با تنظیمات پیش فرض (مثلاً با نام DM-02) نمائید و در ادامه کوئری XMLA زیر را جهت ایجاد Data Source ای به بانک AdventureWorksDW2012 موجود روی دستگاه تان، اجرا نمائید.
<Create xmlns="http://schemas.microsoft.com/analysisservices/2003/engine"> <ParentObject> <DatabaseID>DM-02</DatabaseID> </ParentObject> <ObjectDefinition> <DataSource xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ddl2="http://schemas.microsoft.com/analysisservices/2003/engine/2" xmlns:ddl2_2="http://schemas.microsoft.com/analysisservices/2003/engine/2/2" xmlns:ddl100_100="http://schemas.microsoft.com/analysisservices/2008/engine/100/100" xmlns:ddl200="http://schemas.microsoft.com/analysisservices/2010/engine/200" xmlns:ddl200_200="http://schemas.microsoft.com/analysisservices/2010/engine/200/200" xmlns:ddl300="http://schemas.microsoft.com/analysisservices/2011/engine/300" xmlns:ddl300_300="http://schemas.microsoft.com/analysisservices/2011/engine/300/300" xmlns:ddl400="http://schemas.microsoft.com/analysisservices/2012/engine/400" xmlns:ddl400_400="http://schemas.microsoft.com/analysisservices/2012/engine/400/400" xsi:type="RelationalDataSource"> <ID>Adventure Works DW2012</ID> <Name>Adventure Works DW2012</Name> <ConnectionString>Provider=SQLNCLI11.1;Data Source=(local);Integrated Security=SSPI; Initial Catalog=AdventureWorksDW2012</ConnectionString> <ImpersonationInfo> <ImpersonationMode>ImpersonateCurrentUser</ImpersonationMode> </ImpersonationInfo> <Timeout>PT0S</Timeout> </DataSource> </ObjectDefinition> </Create>
/* Step 1 */ CREATE MINING MODEL [NBSample] ( CustomerKey LONG KEY, Gender TEXT DISCRETE, [Number Cars Owned] LONG DISCRETE, [Bike Buyer] LONG DISCRETE PREDICT ) USING Microsoft_Naive_Bayes Go /* Step 2 */ INSERT INTO NBSample (CustomerKey, Gender, [Number Cars Owned], [Bike Buyer]) OPENQUERY([Adventure Works DW2012],'Select CustomerKey, Gender, [NumberCarsOwned], [BikeBuyer] FROM [vTargetMail]') /* */ SELECT * FROM [NBSample].CONTENT /* */ SELECT * FROM [NBSample_Structure].CASES /* Step 3*/ SELECT FLATTENED MODEL_NAME, (SELECT ATTRIBUTE_NAME, ATTRIBUTE_VALUE, [SUPPORT], [PROBABILITY], VALUETYPE FROM NODE_DISTRIBUTION) AS t FROM [NBSample].CONTENT WHERE NODE_TYPE = 26
در این بخش ما 4 هدف اصلی را که باید در سیستمهای توزیع شده برآورده شوند، بر اساس ارزش آنها مورد بررسی قرار میدهیم. یک سیستم توزیع شده باید اولا منابع را به آسانی در دسترس کاربران قرار دهد. دوما شفاف باشد و تمام پیچیدگیهای یک سیستم توزیع شده را از دید کاربر، مخفی کند. سوما باز و قابل گسترش باشد؛ بصورتیکه به آسانی و با شفافیت کامل بتوانیم اجزای جدیدی را به آن اضافه کنیم. چهارما مقیاس پذیر باشد؛ بصورتیکه بدون اینکه مشکلی برای سیستم بوجود بیاید، بتوانیم منابع موجود سیستم را افزایش دهیم. در این بخش جزئیات هر یک از این اهداف را مورد بررسی قرار میدهیم.
اهداف سیستمهای توزیع شده
1- Connecting resources and users: مشخصترین و اصلیترین هدف سیستمهای توزیع شده، اتصال کاربران به منابع و اشتراک منابع بصورت کنترل شده با کارآیی بالا برای کاربران است. بهصورتیکه کاربران به آسانی به منابع دسترسی داشته باشند. منظور از منابع، هرچیزی در سیستمهای توزیع شده میتواند باشد. منابعی مانند دادهها، سختافزارها، فایلها، Componentها، زیرسیستمها و هر چیز دیگری که کاربران میتوانند بصورت مستقیم و غیر مستقیم به آنها دسترسی داشته باشند. یکی از مهمترین دلایل دسترسی به این هدف، مسائل اقتصادی است. بطور مثال ممکن است ما سیستم خودمان را طوری طراحی کنیم که پردازشهای بسیار مهم و پیچیده در تعدادی از سخت افزارهای بسیار پر هزینه انجام شوند. به این صورت ما این سخت افزارها را برای سایر قسمتهای سیستم، به اشتراک میگزاریم و از طریق دیگر قسمتهای سیستم، دسترسی آن را به کاربران میدهیم. در این حالت دیگر نیازی نیست هر قسمت جداگانه در سیستم، سخت افزاری بسیار قوی را برای خودش نیاز داشته باشد. یا زمانیکه ما یک زیرسیستم را یکبار پیاده سازی میکنیم و دسترسی آن را به سایر قسمتها میدهیم، سایر سیستمها، دیگر نیازی نیست آن زیرسیستم را برای خودشان پیاده سازی کنند و تنها از زیرسیستم موجود استفاده میکنند. دسترسی به این هدف باعث میشود تا کاربران به راحتی به تمام منابع موجود در سیستمهای توزیع شده دسترسی داشته باشند.
2- Distribution transparency: بدلیل پیچیدگیهای بسیار زیاد در سیستمهای توزیع شده، شفافیت، کمک بسیار بزرگی به سادگی نحوه تعامل کاربر با سیستمهای توزیع شده میکند. شفافیت در سیستمهای توزیع شده بدین معنا است که سیستم باید تمام پیچیدگیهای خود را از دید کاربر مخفی کند و پیاده سازی سیستم بصورت توزیع شده نباید هیچ پیچیدگی را در نحوه تعامل کاربر با سیستم بوجود بیاورد.
درواقع در سیستمهای توزیع شده، درخواست دریافت شده، در بین منابع سیستم توزیع میشود. تمام منابع با همکاری که با یکدیگر انجام میدهند، درخواست مورد نظر را پردازش کرده و پاسخ لازم را به کاربر ارائه میدهند. در این بین ممکن است منابع موجود در سیستم، رفتارهای متفاوتی را داشته باشند؛ مثلا هر زیرسیستم در سخت افزار و سیستم عامل جداگانهای اجرا شود که باعث میشود حتی نحوه دستیابی به فایلها یا دادههای هر زیرسیستم نیز با سایر زیرسیستمها متفاوت باشد. شفافیت در سیستمهای توزیع شده بدین معنا است که یک سیستم توزیع شده باید خود را بهصورت یک سیستم واحد که در یک سخت افزار ارائه میشود، ارائه دهد تا کاربران هیچ نگرانی در نحوه تعامل با سیستم نداشته باشند. شفافیت در سیستمهای توزیع شده جنبههای مختلفی دارد که در این قسمت آنها را بررسی میکنیم.
جنبههای مختلف شفافیت در سیستمهای توزیع شده
1- Access Transparency: شفافیت در دسترسی به منابع یا مخفی کردن پیچیدگیها و روشهای مختلف دسترسی به منابع. زیر سیستمهای متفاوت ممکن است در سیستم عاملهای متفاوتی نیز اجرا شوند و همانطور که میدانید هر سیستم عامل ممکن است نحوه دسترسی به منابعش با سایر سیستم عاملها متفاوت باشد. در اینجا ما باید زیر سیستمهای خود را طوری طراحی کنیم تا این تفاوتهای در نحوه دسترسی به منابع را از دید کاربر مخفی کنند و این حس را به کاربر بدهد که سیستم، یک روش واحدی را برای دسترسی به منابع دارد.
2- Location Transparency: شفافیت در مکان منابع و مخفی کردن اینکه منابع در سطح شبکه توزیع شدهاند. این جنبه بیان میکند که کاربران نمیتوانند بگویند که منابع بصورت فیزیکی در سخت افزارهای متفاوتی توزیع شدهاند.کاربران هیچ درکی از اینکه ممکن است منابع حتی بصورت جغرافیایی در مکانهای بسیار دوری از یکدیگر قرار گرفتهاند، ندارند.
3- Migration Transparency: مخفی کردن اینکه ممکن است مکان منابع تغییر یابند. در یک سیستم توزیع شده ممکن است به هر دلیلی، مکان منابع تغییر کند. بطور مثال ممکن است با افزایش دادهها نیاز به افزودن Node جدیدی به سیستم باشد تا قسمتی از دادههای سیستم از این پس از طریق این Node در دسترس باشند. این جابجایی منابع نباید هیچ تاثیری در نحوهی تعامل کاربر داشته باشد.
4- Relocation Transparency: مخفی کردن اینکه منابع ممکن است در زمان استفاده، تغییر مکان دهند. در این حالت دقیقا در زمانیکه شخص در حال استفاده از منابع است ممکن است منابع جابجا شوند که این جابجایی در زمان استفاده از منابع نباید هیچ تاثیری در نحوه تعامل کاربر با سیستم داشته باشد. بطور مثال زمانیکه دو کاربر از طریق تلفن همراه در حال ارسال اطلاعات برای یکدیگر هستند، جابجایی هر یک از این دو کاربر، نباید تاثیری در جریان ارتباطی آنها داشته باشد.
5- Replication Transparency: مخفی کردن اینکه منابع در چند جا کپی شدهاند. در یک سیستم توزیع شده برای بهبود کارآیی و دسترسی ممکن است منابع در چند جای مختلف کپی شوند و شفافیت در Replication میگوید ما باید این واقعیت را که ممکن است منابع ما در سخت افزارهای مختلفی کپی شده باشند، از دید کاربر مخفی کنیم.
6- Concurrency Transparency: مخفی کردن اینکه ممکن است منابع، بین چند کاربر مشترک باشند. بدلیل بالا بودن تعداد کاربران در سیستمهای توزیع شده، همزمانی در دسترسی به منابع مشترک، بسیار بیشتر اتفاق میافتد و این مهم است که هیچ یک از کاربران ندانند که کاربر دیگری بصورت همزمان در حال استفاده از آن داده است.
7- Failure Transparency: مخفی کردن خرابی و بازیابی منابع یک سیستم توزیع شده، از کاربر. در یک سیستم توزیع شده ممکن است منابع به هر دلیلی از دسترس خارج شوند. در این صورت نباید از دسترس خارج شدن منابع و بازیابی آنها هیچ تاثیری در جریان تعامل کاربر با سیستم داشته باشد.
البته این نکته را نیز بگویم اگرچه شفافیت یکی از اهداف بسیار مهم سیستمهای توزیع شدهاست و ما نیز باید سیستمی را طراحی کنیم که تا حد امکان به این هدف دست پیدا کند، اما بدلیل این که گاهی ممکن است شفافیت تاثیر مخربی بر روی کاربر داشته باشد، باید درجههایی را برای آن در نظر بگیریم. بطور مثال زمانیکه دو کاربر از طریق تلفن همراه خود با یکدیگر در ارتباطند، نیازی به مخفی کردن موقعیت مکانی آنها نیست. یا در سیستمهای موقعیت یاب، اصل بر این است که موقعیت منابع مختلف مشخص باشند. یا زمانیکه قرار است یک درخواست را برای یک چاپگر ارسال کنیم بهتر است درخواست ما به نزدیکترین چاپگر به ما ارسال شود تا اینکه به یک چاپگر در جایی دیگر ارسال شود. منظور از دستیابی به این هدف این است که پیچیدگی سیستمهای توزیع شده باید از دید کاربر مخفی بماند تا تاثیر مخربی بر روی کاربر نداشته باشد؛ در صورتیکه نیاز کاربر به عدم شفافیت برخی از قسمتهای سیستم باشد بهتر است درجههایی را برای سیستمهای توزیع شده در نظر بگیریم.
3- Openness: باز بودن یا قابل گسترش بودن سیستمهای توزیع شده یکی دیگر از اهداف بسیار مهم این سیستمها میباشد. به این صورت که یک سیستم در حال اجرا باید توانایی اضافه کردن منابع جدید را داشته باشد. بطور مثال با افزوده شدن نیازمندیهای جدید، نیاز میشود که یک زیر سیستم جدید یا Component جدید را پیاده سازی کنیم. قسمت جدید به راحتی و بدون تاثیر در جریان تعامل کاربر باید بتواند به سیستم اضافه شود. در اکثر موارد این هدف با استفاده از یکسری قراردادهای مشخص که تمامی زیر سیستمها آنها را میشناسند و رعایت میکنند، محقق میشود.
4- Scalability: مقیاس پذیری سیستمهای توزیع شده بدین معنی است که با رشد مواردی مانند تعداد پردازش و درخواست یا موقعیت جغرافیایی کاربران، سیستم قادر باشد بدون تاثیر بر جریان تعامل کاربر با سیستم، آنها را پوشش دهد. یعنی بطور مثال زمانیکه تعداد درخواستهای کاربران سیستم افزایش مییابد، با Replicate قسمتهای موجود سیستم در سخت افزارهای جدید میتوانیم بار پردازشی را بین تعداد بیشتری از Nodeها تقسیم کنیم. به این صورت سیستم میتواند بدون از دسترس خارج شدن، تعداد بیشتری از درخواستهای کاربران را پوشش دهد. یا زمانیکه قرار است موقعیتهای جدید جغرافیایی را سیستم پوشش دهد، با اضافه کردن منابع مورد نیاز، در آن موقعیت جغرافیایی، سیستم قادر است نیاز کاربران آن مکان جغرافیایی را برآورده کند.
تا به این قسمت از سری مقالات سیستمهای توزیع شده، هدف من این بوده که با چرایی وجود این نوع از سیستمها و نحوهی انتخاب آنها و اهداف سیستمهای توزیع شده آشنا شوید. در بخشهای بعد، روشهای مختلف طراحی و پیاده سازی سیستمهای توزیع شده را مورد بررسی قرار میدهیم و میبینیم که چه ابزارهایی برای پیاده سازی سیستمهای توزیع شده در NET. وجود دارند و با توجه به نوع کارآیی هر یک از این ابزارها، آنها را بصورت جداگانه مورد استفاده قرار میدهیم تا با مزایا و معایب هریک آشنا شویم. البته این را نیز ذکر کنم که با توجه به تعاریف سیستمهای توزیع شده، انواع مختلفی از سیستمهای توزیع شده وجود دارند که ما از قبل با برخی از آنها آشنا هستیم؛ معماریهایی مانند Client/Server یا N-Tier نمونههایی از سیستمهای توزیع شده هستند که در آنها وظایف، در سخت افزارهای متفاوتی تقسیم شده و ارتباط هر قسمت از طریق سرویسهایی که ما پیاده سازی میکنیم، صورت میپذیرد و به دلیل اینکه مطمئنا همه شما با نحوه طراحی و پیاده سازی آنها و نحوه ارتباط قسمتهای مختلف آنها آشنا هستید، در سری مقالات سیستمهای توزیع شده در NET.، دیگر نیازی به توضیحی در مورد آنها نمیباشد. هدف من از قسمتهای مرتبط با پیاده سازی سیستمهای توزیع شده، چگونگی تکامل معماریهایی مانند N-Tier بوسیله ابزارهایی است که با هدف دستیابی به خصوصیات و اهداف سیستمهای توزیع شده بوجود آمدهاند.
از SQL Server 2005 نوع دادهی varbinary(max) معرفی شد که برخی از چالشهای بهکاربری Image را کاست و دربارهی بسیاری از موارد مانند ذخیرهی عکس پرسنلی هنوز هم کاربرد دارد؛ ولی توجه داشته باشید که استفاده از این فیلد فقط برای فایلهای کمتر از 256 کیلوبایت سفارش شده است و برای بالاتر از آن، کارآیی کاهش فراوانی خواهد یافت.
در SQL Server 2008 نوع دادهی جدیدی به نام FileStream به وجود آمد به این شکل که یک FileGroup از نوع Data FileStream به پایگاهداده افزوده میشود و در واقع با یک پوشه در سیستم فایل در پیوند است. از این پس هنگام ساخت یک جدول به جای استفاده از نوع دادهی varbinary از نوع FileStream استفاده میکنیم با مد نظر داشتن این نکته که حتماً باید یک فیلد از نوع Uniqueidentifier هم در آن جدول تعریف شده باشد. شیوهی کار نیز به این صورت خواهد بود که خود رکورد در جدول ذخیره میشود و فقط محتوای فایل در آن مسیری از NTFS ذخیره میشود. برخلاف روش درج مسیر فایل در جدول که پس از حذف رکورد، فایل همچنان در سیستم فایل میماند؛ این بار با حذف رکورد فایل مربوطه نیز حذف خواهد شد. افزون بر این مدیریت پشتیبانی از فایلها نیز برعهدهی پایگاه دادهها خواهد بود. اندازهی فایلها در FileStream محدودیتهای پیشین را نخواهد داشت و شما به اندازهی حجم درایو هارددیسک میتوانید فایل در آن ذخیره کنید. نکتهی دیگر دربارهی فایلهای با حجم سنگین که میتوانید Stream مربوط به یک فایل را به صورت بخشبخش در سمت مشتری بارگذاری کنید و به او نشان دهید. در FileStream امنیت و تراکنش فایلها برعهدهی SQL Server است و از این دیدگاه بسیار سادهتر و کارآتر از FileSystem است. (برای آشنایی بیشتر با FileStream، این نوشتار از مهندس وحید نصیری را مطالعه کنید.)
گونهی FileTable از ویژگیهای نوین SQL Server 2012 است که تکمیلکنندهی FileStream است. FileTable آمیزشی از FileStream با hierarchyid و سیستم فایل ویندوز برای ارائهی تواناییهای نوین مدیریت BLOB در SQL Server است. FileTable همانگونه که از دو واژهی تشکیلدهندهاش پیداست؛ همزمان یک جدول و یک سیستم فایل معمولی است.
FileTable به هر روی یک جدول از پایگاهدادههای SQL Server است با یک تفاوت که ساختار آن از پیش تعریفشده است. ستونهای FileTable و نوع دادهی آن از پیش توسط SQL Server مشخص شده است. ستونهای تشکیلدهندهی FileTable دربرگیرندهی جدول زیر است:
هر ردیف از FileTable نمایندهی یک فایل یا پوشه در File System است. ستون path_locator که از نوع hierarchyid است نشاندهندهی مسیر یک فایل یا پوشه است. hierarchyid که از SQL Server 2008 معرفی شده است؛ بهترین نوع داده برای نگهداری ارتباط ساختار سلسلهمراتبی مانند چارت سازمانی، درخت تجهیزات یک کارخانه و یا در همین نمونه درخت فایلها و پوشهها است. پس میتوانیم از همهی امکانات hierarchyid در FileTable نیز برخوردار شویم. اینکه این فایل به ترتیب در چه پوشههایی قرار گرفته است یا اینکه این پوشه شامل چه فایلها یا پوشههایی خواهد بود. اینکه پوشههای همفرزند پوشهی جاری کدام است و یا یا توابع مربوط به جابهجایی فایلها و پوشهها.
دنباله دارد...
OpenCVSharp #4
فرض کنید قصد داریم یک چنین مثال زبان C را که در مورد کار با فیلترها در OpenCV است، به نمونهی دات نتی آن تبدیل کنیم:
#include <cv.h> #include <highgui.h> #include <stdio.h> int main (int argc, char **argv) { IplImage *src_img = 0, *dst_img; float data[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; CvMat kernel = cvMat (1, 21, CV_32F, data); if (argc >= 2) src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); if (src_img == 0) exit (-1); dst_img = cvCreateImage (cvGetSize (src_img), src_img->depth, src_img->nChannels); cvNormalize (&kernel, &kernel, 1.0, 0, CV_L1); cvFilter2D (src_img, dst_img, &kernel, cvPoint (0, 0)); cvNamedWindow ("Filter2D", CV_WINDOW_AUTOSIZE); cvShowImage ("Filter2D", dst_img); cvWaitKey (0); cvDestroyWindow ("Filter2D"); cvReleaseImage (&src_img); cvReleaseImage (&dst_img); return 0; }
using (var src = new IplImage(@"..\..\Images\Penguin.Png", LoadMode.AnyDepth | LoadMode.AnyColor)) using (var dst = new IplImage(src.Size, src.Depth, src.NChannels)) { float[] data = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var kernel = new CvMat(rows: 1, cols: 21, type: MatrixType.F32C1, elements: data); Cv.Normalize(src: kernel, dst: kernel, a: 1.0, b: 0, normType: NormType.L1); Cv.Filter2D(src, dst, kernel, anchor: new CvPoint(0, 0)); using (new CvWindow("src", image: src)) using (new CvWindow("dst", image: dst)) { Cv.WaitKey(0); } }
در قسمتهای قبلی در مورد بارگذاری تصاویر، تهیهی یک Clone از آن و همچنین ساخت یک پنجره به روشهای مختلف و رها سازی خودکار منابع مرتبط، بیشتر بحث شد. در اینجا تصویر اصلی با همان عمق و وضوح تغییر نیافتهی آن بارگذاری میشود.
کار cvMat، آغاز یک ماتریس OpenCV است. پارامترهای آن، تعداد ردیفها، ستونها، نوع دادهی المانها و دادههای مرتبط را مشخص میکنند.
در این مثال آرایهی data، یک فیلتر را تعریف میکند که در اینجا، حالت یک بردار را دارد تا یک ماتریس. برای تبدیل آن به ماتریس، از شیء CvMat استفاده خواهد شد که آنرا تبدیل به ماتریسی با یک ردیف و 21 ستون خواهد کرد.
در اینجا از نام کرنل استفاده شدهاست. کرنل در OpenCV به معنای ماتریسی از دادهها با یک نقطهی anchor (لنگر) است. این لنگر به صورت پیش فرض در میانهی ماتریس قرار دارد (نقطهی 1- , 1- ).
مرحلهی بعد، نرمال سازی این فیلتر است. تاثیر نرمال سازی اطلاعات را به این نحو میتوان نمایش داد:
double sum = 0; foreach (var item in data) { sum += Math.Abs(item); } Console.WriteLine(sum); // => .999999970197678
اگر مرحلهی نرمال سازی اطلاعات را حذف کنیم، تصویر نهایی حاصل، چنین شکلی را پیدا میکند:
زیرا عملیات تغییر اندازهی اطلاعات بردار صورت نگرفتهاست و دادههای آن مطلوب متد cvFilter2D نیست.
و مرحلهی آخر، اجرای این بردار نرمال شده خطی، بر روی تصویر اصلی به کمک متد cvFilter2D است. این متد، تصویر مبدا را پس از تبدیلات ماتریسی، به تصویر مقصد تبدیل میکند. فرمول ریاضی اعمال شدهی در اینجا برای محاسبهی نقاط تصویر خروجی به صورت زیر است:
فیلترهای توکار OpenCV
علاوه بر امکان طراحی فیلترهای سفارشی خطی مانند مثال فوق، کتابخانهی OpenCV دارای تعدادی فیلتر توکار نیز میباشد که نمونهای از آنرا در مثال ذیل میتوانید مشاهده کنید:
using (var src = new IplImage(@"..\..\Images\Car.jpg", LoadMode.AnyDepth | LoadMode.AnyColor)) { using (var dst = new IplImage(src.Size, src.Depth, src.NChannels)) { using (new CvWindow("src", image: src)) { Cv.Erode(src, dst); using (new CvWindow("Erode", image: dst)) { Cv.Dilate(src, dst); using (new CvWindow("Dilate", image: dst)) { Cv.Not(src, dst); using (new CvWindow("Invert", image: dst)) { Cv.WaitKey(0); } } } } } }
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید.