یک پست خیلی خوب برای بررسی الگوهای طراحی سیستمهای مقیاسپذیر (scalable system design pattern) جدیداً خوندم که خیلی از سؤالاتم رو در مورد طراحی این سیستمها جواب داد. اما اونطور که خود نویسنده تو اول مقاله گفته، یه مقاله چند سال قبل اون نوشته و به طراحی سیستمهای توسعهپذیر اشارهکرده و گفته که اول بهتره اون رو بخونین. من هم اول مقاله قدیمی رو براتون خلاصش رو مینویسم و بعدش هم مقاله جدید رو باید بررسی کنیم. البته مقاله جدیده خیلی خلاصه نوشتهشده و باید خیلی گسترش پیدا بکنه.
مفاهیم اصلی
"توسعهپذیری" به معنای "قدرت پردازشی خالص" نیست
توسعهپذیری بهمنظور کاهش اثرات جانبی به وجود آمده به خاطر افزایش در کارایی، هزینه، نگهداری و خیلی جنبههای دیگر است.
برای مثال، اجرای یک قسمت از برنامه در یک باکس جداگانه، سرعت اجرای بیشتری درزمانی خواهد داشت که بار نیز کم باشد. اما این طراحی قابلیت توسعه ندارد، به دلیل اینکه اگر بار سیستم بیشتر از محدوده خاصی افزایش پیدا کند، کارایی سیستم بهصورت شدیدی افت خواهد کرد.
درک کامل از بارکاری و شرایط محیطی که سیستم برای آن طراحی میشود
شناخت جنبههای توسعه سیستم، مانند: تعداد کاربران، میزان تراکنشها، میزان دادهها.
نحوه اندازهگیری و هدف نهایی کارایی، مانند: میزان زمان پاسخ و همچنین میزان گذردهی سیستم
شناخت اینکه چه کسی مشتری نهایی شما خواهد بود.
ترافیکی که از سیستم شما خارج خواهد شد را رتبهبندی و اولویتبندی کنید، با استفاده از این روش میدانید که کدام ترافیک را در صورت افزایش بسیار زیاد بار قربانی کنید.
توسعه عرضی بهجای توسعه طولی
بهتر است بهجای سرمایهگذاری و قوییتر کردن یک سیستم، از تعداد بیشتری سیستم سختافزاری معمولی استفاده کنید،
کد خود را بهصورت ساده و ماژولار نگهدارید
قابلیت اینکه شما قسمتی از کد خود را بدون نگرانی از تغییر در کارایی در قسمتهای دیگر تغییر دهید، شمارا قادر میسازد تا بهصورت مؤثر نسبت به بهینهسازی قسمتهای مختلف سیستم خود آزمایشها متفاوتی انجام دهید.
هیچوقت برای منظور خاصی ماژولار بودن کد خود را به خطر نیاندازید.
هیچگاه نقطه bottleneck سرعت سیستم خود را حدس نزنید، آن را با آزمایش پیدا کنید
نقاط bottleneck نقاطی از سیستم هستند که کد آنها سرعت کمی دارد و به تعداد زیاد هم اجرا میشود. هیچگاه کدی که سرعت کمی دارد، اما بهندرت اجرا میشود را بهینه نکنید.
یک واحد برای اندازهگیری و تهیه آمار کارایی برای سیستم خود تهیه کنید و از روی آن برای بهینهسازی کد اقدام کنید.
نقشهای برای توسعه داشته باشید
آمار استفاده از سیستم خود را همیشه داشته باشید و نرخ پیشرفت را سعی کنید حدس برنید.
روشهای اصلی
راهاندازی server farm (سرعت دستیابی بلادرنگ)
اگر تعداد زیادی از درخواستهای مستقل (بهصورت همزمان) برای سیستم خوددارید، از مجموعه سرورهایی که در مکان فیزیکی نزدیک به یکدیگر قرار دارند استفاده کنید. این سرورها معمولاً بهصورت مشابه پیکربندی میشوند و در مقابل آنها یک توزیعکننده بار قرار دارد.
خود کاربردی که در حال اجرا بر روی چند سیستم است، باید بهصورت stateless باشد تا بتواند بهصورت کامل به سرورهای دیگر در هرلحظه منتقل شود.
تمامی درخواستهای ورودی به سیستم از طریق توزیعکننده بار بهتمامی سیستمهای دیگر منتقل میشود و به این صورت بار در بین سیستمها بهصورت اشتراکی پخش میشود.
توزیع بار بهصورت عرضی صورت میگیرد و بنابراین در صورت افزایش بار، تنها نیاز به افزودن تعداد سیستم خواهد بود.
این استراتژی درصورتیکه از پردازش ابری استفاده کنیم بسیار مؤثرتر خواهد بود و میتوان با افزایش تعداد ماشینهای مجازی کارایی سیستم را افزایش داد.
قسمتبندی دادهها
دادههای خود را بین چندین پایگاه داده پخشکنید و بنابراین هزینه دستیابی به دادهها بین چندین سرور پخش خواهد شد.
اصالتاً داده یک عنصر دارای وضعیت است. بنابراین پخش دادهها بین چندین سرور باید به صورتی باشد که وضعیت دادههای نگهداری شده در آن سرور در نظر گرفته شود.
در بهکارگیری یک مکانیسم توزیع داده، باید نحوه دسترسی به دادهها در نظر گرفته شود. دادههایی که باید بهصورت همزمان دسترسی شوند، بهتر است در یک سرور قرار گیرند. یک روش پیچیدهتر اما مؤثرتر، انتقال دادهها به سرورهای متفاوت بر اساس مدل دسترسی است.
استفاده از مدل پردازشی همزمان دستهای map/reduce
یک الگوریتم باید توانایی موازیسازی را داشته باشد. یعنی اینکه، یک مرحله اجرایی، از مراحل دیگر اجرا بهصورت کامل مستقل باشد.
روش map/reduce که از طرف شرکت گوگل ارائهشده است، یک روش بسیار خوب برای انجام پردازش موازی است. فریم وورک متنباز Hadoop برای java میتوان بهعنوان یک راه حل نیز استفاده شود.
استفاده از شبکه تحویل محتوا CDN (حافظه میانی ایستا)
استفاده از این فنّاوری برای محتوای ایستا بسیار متداول است. ایده اصلی قرار دادن چندین کپی از یک داده ایستا در نقاط جغرافیایی مختلف است.
درخواستهای کاربران به نزدیکترین نقطه که داری داده درخواستی باشد انتقال پیدا میکند.
استفاده از cache engine (محتوای پویا)
این فنّاوری یک توازن بین زمان و فضای ذخیرهسازی است. برخی از اجراها ممکن است نیازمند مجموعه یکسان از ورودیها باشد. که این ورودی چندین بار به سیستم داده شود. بنابراین بهجای انجام پردازش بهصورت کامل برای هر بار ورود این دادهها، بهتر است نتایج پردازش قبلی را در خاطر نگهداریم و از آن استفاده کنیم.
این ویژگی معمولاً با استفاده از lookup cache پیادهسازی میشود.
اکثراً از memcached و EHCached برای این منظور استفاده میشود.
استفاده از resource pool
ایجاد نشست برای پایگاه داده و TCP عملکرد پرهزینهای است، پس بهتر است از هر یک چندین بار استفاده شود.
محاسبه نتایج بهصورت تقریبی
بهجای محاسبه نتایج دقیق برای یک درخواست، در صورت امکان یک نتیجه تقریبی را با سرعت بالاتر ارائه دهید.
در جهان حقیقی، میزانی از عدم دقت قابلپذیرش است.
فیلتر کردن در منبع
سعی کنید بیشتر پردازش را در محلی که داده تولید و ارسال میشود انجام دهید، با استفاده از این روش، میتوان تا حدی داده انتقالی را کاهش داد.
پردازش ناهمگام (asynchronous)
شما درخواست انجام پردازشی را ارسال میکنید، اما نتایج این پردازش تا چند مرحله بعد موردنیاز است و میتوانید تا آن زمان بدون نیاز به این نتایج کار خود را ادامه دهید. بنابراین نیاز به منتظر ماندن تا آماده شدن نتایج نیست.
از جنبه دیگر، یک نخ پردازشی که منتظر منبع خاصی است، تا زمان حیات خود، تمامی منابع موردنیاز خود را از سیستم نگه میدارد.برای سیستمهای با تراکنش بالا، این تعداد نخ پردازشی منتظر میتواند بسیار زیاد باشد. درنتیجه کارایی سیستم میتواند بسیار کاهش پیدا کند.
فراخوانی سرویس در این مثال، بهتر است که از طریق پردازشهای غیر همگام انجام شود. این نوع پردازش معمولاً در دو مرحله انجام میشود: callback و polling