سجاد غفاریان
سجاد غفاریان
خواندن ۹ دقیقه·۱ ماه پیش

اصول طراحی نرم‌افزارها و سیستم‌های مقیاس‌پذیر - بخش سوم

در ادامه‌ی بحث‌های قبلی که درباره Minimize Coordination (به حداقل رساندن هماهنگی بین کامپوننت‌ها) و Design to Scale Out (طراحی برای مقیاس‌پذیری افقی) صحبت کردیم، در این قسمت سوم، می‌خواهیم دو مفهوم کلیدی دیگه رو بررسی کنیم که نقش بسیار مهمی در طراحی سیستم‌های بزرگ و مقیاس‌پذیر دارن: Partition Around Limits و Design for Operations.

لینک بخش اول - اصول طراحی نرم‌افزارها و سیستم‌های مقیاس‌پذیر
لینک بخش دوم - اصول طراحی نرم‌افزارها و سیستم‌های مقیاس‌پذیر

چرا این مفاهیم مهم هستند؟

وقتی یک سیستم بزرگ و پیچیده رو طراحی می‌کنی، همیشه محدودیت‌هایی مثل ظرفیت پایگاه داده‌ها، توان شبکه، یا منابع محاسباتی سر راهت قرار می‌گیرن. این محدودیت‌ها می‌تونن مانعی جدی برای عملکرد و مقیاس‌پذیری سیستم باشن. اینجاست که اصل Partition Around Limits (پارتیشن‌بندی براساس محدودیت‌ها) وارد عمل میشه. این اصل بهت کمک می‌کنه داده‌ها و منابع سیستم رو به بخش‌های کوچکتر و مستقل تقسیم کنی تا بار بین اون‌ها توزیع بشه و از محدودیت‌ها عبور کنی.

در کنار اون، Design for Operations (طراحی برای عملیات) یکی دیگه از اصول مهم در طراحی سیستم‌های پیچیده است. این اصل به این نکته اشاره داره که سیستم‌ها باید از همون ابتدا طوری طراحی بشن که برای مدیریت و عملیات‌های نگهداری روزانه آماده باشن. به عبارت دیگه، داشتن یک سیستم پایدار فقط به معماری و کد خوب محدود نمیشه؛ بلکه باید ابزارها و فرآیندهایی برای تیم‌های عملیات فراهم بشه تا بتونن به‌راحتی سیستم رو مانیتور کنن، از مشکلات جلوگیری کنن و به سرعت در صورت بروز خطا واکنش نشون بدن.

در این مقاله، به بررسی این دو مفهوم خواهیم پرداخت و توضیح می‌دهیم چطور با پارتیشن‌بندی هوشمندانه و طراحی برای عملیات، می‌تونی سیستمی بسازی که نه تنها مقیاس‌پذیر باشه، بلکه مدیریت و نگهداریش هم ساده و کارآمد باشه.


پارتیشن‌بندی برای مدیریت محدودیت‌ها (Partition Around Limits)

یکی از مهم‌ترین چالش‌هایی که در سیستم‌های بزرگ و در حال رشد با آن مواجه می‌شوی، برخورد با محدودیت‌های مقیاس‌پذیری است. هر سرویس ابری، از جمله سرویس‌های ابری معروف مثل Azure، AWS ویا Google Cloud محدودیت‌هایی در زمینه مقیاس‌دهی داره؛ از جمله تعداد هسته‌های پردازشی، حجم پایگاه داده، میزان ورودی/خروجی داده‌ها (I/O)، و ظرفیت شبکه. به همین دلیل، وقتی سیستم به اندازه کافی بزرگ میشه، احتمالاً با یکی از این محدودیت‌ها برخورد خواهی کرد.

پارتیشن‌بندی (Partitioning) یک راه‌حل کارآمد برای عبور از این محدودیت‌هاست. با تقسیم‌بندی داده‌ها، منابع، یا اجزای سیستم به بخش‌های مستقل، می‌تونی بار رو بین اون‌ها توزیع کنی و از بروز گلوگاه‌ها جلوگیری کنی. پارتیشن‌بندی بهت این امکان رو میده که به جای اینکه یک منبع خاص رو بیش از حد تحت فشار بذاری، از چندین منبع کوچک‌تر به صورت همزمان استفاده کنی و از ظرفیت حداکثری اون‌ها بهره‌مند بشی.

روش‌های مختلف پارتیشن‌بندی

پارتیشن‌بندی می‌تونه در بخش‌های مختلف سیستم اعمال بشه، از جمله پایگاه‌های داده، صف‌ها، سرویس‌های وب، یا حتی زیرساخت‌های پردازشی. هر کدوم از این بخش‌ها ممکنه با محدودیت‌های خاص خودشون مواجه بشن و نیاز به تقسیم‌بندی داشته باشن.

پارتیشن‌بندی پایگاه داده

پایگاه داده‌ها یکی از رایج‌ترین بخش‌هایی هست که با محدودیت‌های مختلفی مثل حجم داده، تعداد درخواست‌های همزمان، یا سرعت I/O مواجه میشن. پارتیشن‌بندی پایگاه داده می‌تونه به سه شکل انجام بشه:

  • پارتیشن‌بندی افقی (Sharding): در این روش، داده‌ها براساس یک معیار خاص (مثل نام مشتری یا شماره سفارش) به چندین پارتیشن مستقل تقسیم میشن. هر پارتیشن شامل یک زیرمجموعه از داده‌های کل سیستمه و همه پارتیشن‌ها از یک طرح داده مشابه استفاده می‌کنن.
  • پارتیشن‌بندی عمودی: در این روش، هر پارتیشن شامل یک زیرمجموعه از فیلدهای داده‌های سیستم است. به عنوان مثال، می‌تونی فیلدهای پراستفاده رو در یک پارتیشن و فیلدهای کمتر استفاده شده رو در پارتیشن دیگری ذخیره کنی.
  • پارتیشن‌بندی عملکردی: در این روش، داده‌ها براساس کارکرد و زمینه استفاده‌شون تقسیم میشن. برای مثال، داده‌های مربوط به فاکتورها در یک پارتیشن و داده‌های موجودی محصولات در پارتیشن دیگه ذخیره میشه.

پارتیشن‌بندی صف‌ها و پیام‌ها

برای سرویس‌های پیام‌محور یا صف‌ها، محدودیت‌هایی مثل تعداد اتصالات همزمان یا حجم پیام‌ها می‌تونن ایجاد مشکل کنن. با پارتیشن‌بندی صف‌ها یا پیام‌ها، می‌تونی درخواست‌ها رو به چندین صف مجزا تقسیم کنی و تعداد پیام‌ها رو بین این صف‌ها به شکل مساوی توزیع کنی.

پارتیشن‌بندی سرویس‌های پردازشی

برای سرویس‌های پردازشی که ممکنه با محدودیت‌هایی مثل تعداد هسته‌های پردازشی یا ظرفیت شبکه مواجه بشن، می‌تونی پارتیشن‌بندی رو در سطح سرویس‌ها یا ماشین‌های مجازی انجام بدی. به این صورت که چندین سرویس یا ماشین مجازی با منابع جداگانه به کار گرفته بشن و بار پردازشی بین اون‌ها توزیع بشه.

نکات کلیدی در پارتیشن‌بندی

  • انتخاب کلید پارتیشن‌بندی مناسب: مهم‌ترین نکته در پارتیشن‌بندی اینه که کلید پارتیشن‌بندی رو طوری انتخاب کنی که باعث توزیع یکنواخت بار بین پارتیشن‌ها بشه. برای مثال، اگه پارتیشن‌بندی رو براساس اولین حرف نام مشتری انجام بدی، ممکنه برخی حروف بیشتر از بقیه تکرار بشن و یک پارتیشن خیلی شلوغ‌تر از بقیه بشه. در عوض، از کلیدهایی مثل شناسه‌های تصادفی یا هش شده استفاده کن که توزیع بار رو بهتر مدیریت کنن.
  • پارتیشن‌بندی بر اساس محدودیت‌های مختلف: پارتیشن‌بندی فقط برای پایگاه‌های داده کاربرد نداره، باید به محدودیت‌های دیگه مثل شبکه، پردازشگرها، و ذخیره‌سازی هم توجه کنی و در صورت نیاز، پارتیشن‌بندی رو در سطوح مختلف سیستم پیاده‌سازی کنی. مثلاً اگه یک سرور یا VM داره به محدودیت‌های CPU می‌رسه، می‌تونی بار پردازشی رو بین چندین VM یا سرویس تقسیم کنی.
  • پرهیز از نقاط بحرانی (Hotspots): یکی از چالش‌های رایج در پارتیشن‌بندی، بروز نقاط بحرانی یا Hotspotهاست. این اتفاق زمانی رخ میده که یک پارتیشن بیشتر از بقیه پارتیشن‌ها درخواست دریافت می‌کنه و در نتیجه، دچار گلوگاه میشه. برای جلوگیری از این مشکل، کلید پارتیشن‌بندی رو طوری انتخاب کن که بار به شکل مساوی بین پارتیشن‌ها تقسیم بشه.
  • پارتیشن‌بندی در سطوح مختلف: پارتیشن‌بندی می‌تونه در سطوح مختلفی از سیستم انجام بشه، از پایگاه‌های داده گرفته تا ماشین‌های مجازی، حساب‌های اشتراکی و حتی سطوح زیرساختی بالاتر. در برنامه‌های بزرگ، ممکنه نیاز باشه پارتیشن‌بندی رو حتی در سطح اشتراک‌ها (Subscriptions) یا گروه‌های منابع (Resource Groups) هم انجام بدی تا محدودیت‌های مربوط به این سطوح هم مدیریت بشن.

پارتیشن‌بندی یک ابزار قدرتمند برای مدیریت محدودیت‌های مختلف سیستم است. با تقسیم‌بندی هوشمندانه منابع، می‌تونی از بروز گلوگاه‌ها جلوگیری کنی و عملکرد سیستم رو به شکل قابل توجهی بهبود بدی. به کمک پارتیشن‌بندی، می‌تونی سیستم رو مقیاس‌پذیرتر، پایدارتر و انعطاف‌پذیرتر کنی تا در برابر چالش‌های مربوط به محدودیت‌های مقیاس‌پذیری مقاوم باشه.


طراحی برای عملیات (Design for Operations)

یکی از جنبه‌های حیاتی در طراحی اپلیکیشن‌های ابری موفق اینه که سیستم رو طوری بسازی که تیم عملیات بتونه به راحتی اون رو مدیریت کنه و ابزارهای لازم برای نظارت، نگهداری و واکنش سریع به مشکلات رو در اختیار داشته باشه. در دنیای ابری، نقش تیم عملیات به شکلی اساسی تغییر کرده. اون‌ها دیگه مسئولیت مدیریت مستقیم سخت‌افزار یا زیرساخت‌های میزبانی رو ندارن، اما همچنان نقش کلیدی در اجرای موفق اپلیکیشن‌ها ایفا می‌کنن.

وظایف تیم عملیات شامل موارد زیر میشه:

  • استقرار (Deployment): راه‌اندازی و به‌روز‌رسانی اپلیکیشن‌ها.
  • نظارت (Monitoring): پیگیری سلامت و عملکرد سیستم.
  • اقدام در برابر مشکلات (Incident Response): واکنش سریع به مشکلات و خطاها.
  • امنیت و بررسی‌های امنیتی (Security Auditing): بررسی امنیت و انطباق با استانداردهای امنیتی.
  • پایش و تحلیل ریشه‌ای مشکلات (Root Cause Analysis): پیدا کردن دلایل اصلی مشکلات.

اهمیت ثبت وقایع و ردیابی (Logging & Tracing)

یکی از مهم‌ترین ابزارهایی که تیم عملیات برای مدیریت سیستم‌های ابری نیاز داره، ثبت وقایع (Logging) و ردیابی (Tracing) است. در واقع، این دو مورد به عنوان مهم‌ترین منابع برای درک وضعیت سیستم و پیگیری مشکلات به شمار میان. در محیط‌های ابری، به دلیل پیچیدگی و مقیاس بالای سیستم‌ها، بدون داشتن لاگ‌ها و ردگیری‌ها، شناسایی مشکلات و نقاط ضعف به شدت دشوار میشه.

ثبت وقایع (Logging)

لاگ‌ها شامل رویدادهایی مثل تغییرات وضعیت اپلیکیشن، خطاها و استثناها هستن. این لاگ‌ها به تیم عملیات کمک می‌کنن که در زمان‌های بحرانی، اطلاعات دقیقی درباره اتفاقاتی که افتاده به دست بیارن.

ردیابی (Tracing)

ردیابی مسیر یک درخواست رو در سیستم دنبال می‌کنه و می‌تونه گلوگاه‌ها و مشکلات عملکردی رو شناسایی کنه. در اپلیکیشن‌های ابری که شامل سرویس‌های متعددی هستن، ردیابی به تیم عملیات کمک می‌کنه که بفهمن کدوم سرویس یا کدوم مرحله در پردازش یک درخواست باعث بروز مشکل شده.

توصیه‌ها برای طراحی عملیاتی

همه چیز رو قابل مشاهده کن

مشاهده‌پذیری (Observability) یکی از اصول کلیدی در عملیات موفقه. بعد از استقرار سیستم، لاگ‌ها و ردگیری‌ها اصلی‌ترین ابزاری هستن که به تیم عملیات دیدگاهی از داخل سیستم میدن. بنابراین، باید مطمئن بشی که همه بخش‌های سیستم به شکل مناسبی لاگ‌ها و اطلاعات مرتبط رو تولید و ارائه می‌کنن. اگر لاگ‌ها و ردیابی‌ها در محیط تولید فعال نباشن، در لحظاتی که بیشتر از همیشه به اطلاعات نیاز داری، اون‌ها رو از دست می‌دی.

ابزارهای نظارت (Monitoring) رو به‌درستی پیاده‌سازی کن

نظارت (Monitoring) باید دیدی از سلامت و عملکرد سیستم در زمان‌های واقعی (Real-Time) فراهم کنه. نظارت باید شامل اطلاعاتی مثل میزان دسترس‌پذیری، عملکرد و سلامت کلی سیستم باشه. این اطلاعات به تیم عملیات اجازه میده که در صورت مشاهده مشکلات، قبل از اینکه به بحران تبدیل بشن، اقدام کنن. نظارت باید در بالاترین سطح ممکن از زمان واقعی باشه تا تیم بتونه به سرعت به مشکلات واکنش نشون بده و حتی از وقوع اون‌ها جلوگیری کنه.

برای توضیحات بیشتر درمورد Prometheus و Application Performance Monitoring مطالعه داشته باشید.

ابزارهای تحلیل علت اصلی مشکلات (Root Cause Analysis) رو فراهم کن

وقتی مشکلی رخ میده، تحلیل علت اصلی (Root Cause Analysis) به تیم کمک می‌کنه که دلیل بروز مشکل رو پیدا کنه. بنابراین، سیستم باید طوری طراحی بشه که امکان ردیابی دقیق و ارائه اطلاعات لازم برای تشخیص مشکل رو فراهم کنه. استفاده از Distributed Tracing که از شناسه‌های همبسته (Correlation ID) استفاده می‌کنه، در اینجا اهمیت زیادی داره. شناسه‌های همبسته کمک می‌کنن که مسیر یک درخواست از بین سرویس‌های مختلف به شکل دقیق دنبال بشه و علت اصلی خطاها مشخص بشه.

برای توضیحات بیشتر درمورد Jaeger مطالعه داشته باشید.

استانداردسازی لاگ‌ها و معیارها (Metrics)

یکی از مشکلات رایج در سیستم‌های بزرگ اینه که هر سرویس لاگ‌ها و معیارهای خودش رو با قالب و استانداردی متفاوت تولید می‌کنه. این کار باعث میشه جمع‌آوری و تحلیل اطلاعات سخت بشه. برای حل این مشکل، از استانداردسازی استفاده کن. همه سرویس‌ها باید از یک طرح مشترک برای ثبت لاگ‌ها استفاده کنن که شامل اطلاعات مهم مثل شناسه‌های همبسته، نام رویداد، آدرس IP فرستنده و غیره باشه.

برای توضیحات بیشتر درمورد Open Telemetry مطالعه داشته باشید.

اتوماتیک سازی وظایف (Automation)

اتوماسیون وظایف عملیاتی مثل استقرار (Deployment)، نظارت (Monitoring) و پیاده‌سازی (Provisioning) باعث میشه این فرآیندها تکرارپذیر و کمتر وابسته به خطاهای انسانی باشن. وظایف دستی معمولاً احتمال بروز خطا دارن، اما وقتی این فرآیندها رو اتومات کنی، دقت و سرعت کارها به شکل چشمگیری افزایش پیدا می‌کنه.

برای توضیحات بیشتر درمورد Ansible مطالعه داشته باشید.

استفاده از تنظیمات به‌عنوان کد (Configuration as Code)

تنظیمات به‌عنوان کد (Configuration as Code) یکی از اصول مهم در مدیریت عملیات مدرن است. فایل‌های پیکربندی باید به شکلی مدیریت بشن که تغییرات اون‌ها قابل ردیابی و نسخه‌بندی باشن. با استفاده از سیستم‌های کنترل نسخه (Version Control)، می‌تونی تغییرات تنظیمات رو دنبال کنی و در صورت بروز مشکل، به راحتی به نسخه قبلی برگردی.

برای توضیحات بیشتر درمورد GitOps مطالعه داشته باشید.


طراحی برای عملیات به این معنیه که از همون ابتدای طراحی، سیستم رو طوری بسازی که تیم عملیات به راحتی بتونه عملکرد، سلامت و امنیت سیستم رو مدیریت کنه. با پیاده‌سازی ابزارهای مشاهده‌پذیری مثل لاگ‌ها و ردیابی، استانداردسازی داده‌های عملیاتی، و اتوماسیون فرآیندهای کلیدی، می‌تونی سیستمی بسازی که نه تنها مقیاس‌پذیر باشه، بلکه به راحتی مدیریت و نگهداری بشه.


پایان

امیدوارم که واستون مفید بوده باشه!

منابع:

https://learn.microsoft.com/en-us/azure/architecture/guide/design-principles/partition
https://learn.microsoft.com/en-us/azure/architecture/guide/design-principles/design-for-operations
طراحی نرم افزارسیستم دیزایننرم افزارمهندسی نرم افزاردواپس
SRE at Asa Co. / Agah Group
شاید از این پست‌ها خوشتان بیاید