محسن میرزانیا
محسن میرزانیا
خواندن ۸ دقیقه·۵ سال پیش

برنامه‌های "cloud-native" - قسمت دوم Sessions

در قسمت اول در مورد scalability صحبت کردیم. برای دسترسی به آن می‌توانید به لینک زیر مراجعه کنید:

https://virgool.io/@mo.mirzania/cloud-native-d0bupicynnnb

در این قسمت به مبحث نشست‌ها (sessions) و نودهای بدون حالت (stateless) خواهیم پرداخت.

الگوی scale کردن نودهای محاسباتی (Compute nodes)

نکته‌ی کلیدی در استفاده‌ی بهینه از منابع، نودهای محاسباتیِ stateless و autonomous هستند. استفاده از نود stateless لزوما به معنی برنامه‌ی stateless نیست. state برنامه را می‌توان خارج از نودها، در یک حافظه‌ی کش یا یک سرویس ذخیره‌سازی نگهداری کرد. در لایه‌ی وب، این امر معمولا توسط کوکی‌ها مدیریت می‌شود.

مفهوم “Horizontal Scaling Compute Pattern” شامل چالش‌های زیر می‌شود:

  • قابلیت scale شدن نودهای محاسباتی به صورت مقرون به صرفه
  • نیازمندی‌های برنامه، ممکن است از ظرفیت بزرگترین نود موجود بیشتر باشد.
  • نیازمندی‌های برنامه،‌ به صورت دوره‌ای (مثلا ساعت مشخصی در طی روز، یا روزهای مشخصی در طی هفته) تغییر پیدا می‌کند، یا ممکن است تغییرات به صورت پیش‌بینی نشده‌ای رخ دهند.
  • نودهای محاسباتی برنامه نیازمند حداقل downtime هستند، حتا هنگامی که در سطح سخت‌افزار failure رخ دهد.

این الگو معمولا در ارتباط با الگوی “Node Termination Pattern”، و “Auto-Scaling Pattern” استفاده می‌شود.

هنگامی که یک برنامه‌ی “cloud-native” آماده‌ی scale شدن به صورت افقی با اضافه یا کم کردن نودها باشد، این عمل را می‌توان توسط رابط کاربری مدیریت محیط ابری، یک ابزار scaling، یا مستقیما توسط سرویس مدیریتی پلتفورم ابری انجام داد (رابط کاربری یا ابزار scaling در نهایت از سرویس مدیریت ابر استفاده خواهند کرد). این سرویس مدیریتی نیازمند این است که یک پیکربندی خاص (مثلا image ماشین مجازی) و تعداد مطلوب نودها مشخص شود. اگر تعداد نودهای حال حاضر کمتر از میزان تعداد مطلوب باشد، نودهایی اضافه خواهند شد، و اگر این تعداد بیشتر باشند، تعدادی از این منابع آزاد خواهند شد.

فرآیند اضافه یا کم شدن نودها در محیط ابری آسان است،‌اما نکته‌ی مهم مدیریت session کاربران و کارامدی عملیات است.

ویژگی برگشت‌پذیری در ابر

به صورت سنتی، scalability همیشه در مورد اضافه کردن ظرفیت بوده است. برای مثال، اگر نرم‌افزار شما در اکثر اوقات هفته به ظرفیت خیلی کمی نیاز داشته باشد، اما روزهای جمعه به ۲۰ برابر این ظرفیت نیاز داشته باشد، معمولا کسی به فکر استفاده‌ی بهینه از این ظرفیت اضافی (که شش روز در هفته در دسترس است) نخواهد افتاد. اما با استفاده از برنامه‌های “cloud-native” استفاده از ظرفیت اضافه بسیار آسان‌تر و کم‌ خطرتر خواهد بود. ظرفیت اضافه به ابر پس داده خواهد شد، و هزینه‌ی منابع اضافی قطع می‌شود.

قابلیت کشسانی یا elasticity در ابر به همین مفهوم اشاره دارد.

مدیریت Session State

یک وب اپلیکیشن معمولا به ۳ لایه تقسیم می‌شود: لایه‌ی وب، لایه‌ی سرویس و لایه‌ی دیتا. هر کدام از این لایه‌ها می‌تواند شامل یک یا چند نود باشد. لایه‌ی وب، وب‌سرورها را اجرا می‌کند که برای کاربران قابل دسترسی است، و محتوایی که در مرورگرها نمایش داده می‌شود را ارائه می‌کند. اکنون تصور کنید که ما بیش از یک نود در لایه‌ی وب داشته باشیم، و یک کاربر با استفاده از مرورگرش به اپلیکیشن ما مراجعه کند. در این حالت کدام یک از نودها باید پاسخ کاربر را بدهد؟ بنابراین باید روشی وجود داشته باشد که مشخص کند کاربر به سمت کدام نود هدایت شود. این تصمیم‌گیری معمولا توسط یک توزیع‌کننده‌ی بار یا “Load balancer” (یا به صورت مختصر lb) اتفاق می‌افتد. در اولین درخواست و session جدید یک کاربر، معمولا lb درخواست کاربر را با استفاده از الگوریتم “Round Robin” یا “rr” برای یک نود ارسال می‌کند، تا بار به صورت متعادل بین سرورها توزیع شود. اما درخواست‌های بعدی کاربر در همان “session” را چگونه باید مدیریت کرد؟ این امر به این بستگی دارد که ما چگونه session state را مدیریت می‌کنیم، که در ادامه به آن خواهیم پرداخت.

وب سرویس‌ها (یا همان سرویس‌ها) با استفاده از یک پروتکل استاندارد شبکه مانند HTTP استفاده می‌کنند. دو سبک متداول در سرویس‌ها SOAP و REST است. در محیط‌های ابری استفاده از REST محبوب‌تر است.

لایه‌ی سرویس در اپلیکیشن لایه‌ای است که اصطلاحا “business login” را پیاده‌سازی می‌کند. همان لایه‌ای که تصمیم می‌گیرد داده‌ها چگونه ایجاد شوند، ذخیره شوند یا تغییر کنند. این لایه برای لایه‌ی وب قابل دسترس است، اما کاربران نمی‌توانند به صورت مستقیم به آن دسترسی پیدا کنند. نکته‌ی مهم این است که نودهای این لایه “stateless” هستند.

لایه‌ی دیتا، اطلاعات را به یک یا چند شکل، به صورت همیشگی ذخیره می‌کند. شکل‌های مختلف ذخیره‌سازی می‌تواند استفاده از پایگاه‌داده‌های رابطه‌ای، پایگاه‌داده‌های NoSQL، یا ذخیره‌سازی به صورت فایل باشد. بعضی وقت‌ها به مرورگرها اجازه‌ی دسترسی read-only به بعضی از انواع این اطلاعات، برای مثال فایل‌ها داده می‌شود. اما این دسترسی معمولا شامل پایگاه‌داده نمی‌شود.

لایه‌ی وب و Sticky sessionها

بعضی از اپلیکیشن‌ها از “sticky sessions” استفاده می‌کنند، یعنی هر کاربر تنها باید از همان وب‌سروری که بار اول به سمت آن هدایت شده استفاده کند. هنگامی که انتساب یک کاربر به یک وب‌سرور رخ داد، تمام درخواست‌های یک کاربر توسط یک سرور پاسخ داده خواهد شد. از این امر باید در دو جا پشتیبانی شود: lb یک کاربر را تنها به همان وب‌سرور هدایت کند، و نودهای وب‌سرور session state کاربر بین درخواست‌ها را ذخیره کنند.

مزیت استفاده از “sticky sessions” سادگی و راحتی استفاده از آن است. زیرا برنامه‌نویسی آن آسان‌ است و به راحتی می‌توان session کاربران را در حافظه ذخیره کرد. اما نکته‌ی مهم این است که هنگامی که session state یک کاربر در یک نود مشخص ذخیره شود، آن نود دیگر stateless نیست، بلکه stateful است.

چالش‌های استفاده از نودهای stateful

نگهداری session state کاربران در نودهای stateful، چالش‌هایی در رابطه با تجربه‌ی کاربری به وجود می‌آورد. اولین مشکل در اینجاست که اگر نودی که session state کاربر را ذخیره می‌کند به هر دلیلی از مدار خارج شود، session کاربر نیز از بین خواهد رفت. این امر ممکن است کاربر را مجبور کند که دوباره لاگین کند، یا مثلا محتوای سبد خریدش حدف شود. به عبارت دیگر نود stateful تبدیل به “single point of failure” می‌شود.

مشکل دوم این است که اطلاعات sessionها ممکن است به طور غیر یکنواخت بین نودها پخش شود. برای مثال فرض کنید که لایه‌ی وب از دو نود تشکیل شده است که هر کدام ۱۰۰۰ session فعال را کنترل می‌کنند، و شما برای افزایش ظرفیت در زمانی که می‌دانید ممکن است ترافیک سایت بالا رود یک نود سوم اضافه می‌کنید. در این حالت lb باز هم به صورت یکنواخت sessionهای جدید را بین نودها پخش می‌کنند. یعنی این اطلاعات را ندارد که ابتدا ۱۰۰۰ session اول را برای نود سوم ارسال کند، و بعد بین هر سه نود. این اتفاق هم ممکن است به پر شدن ظرفیت نود اول و دوم و متاثر شدن تجربه‌ی کاربری شود.

نگهداری از session state بدون استفاده از نودهای stateful

راهکار “cloud-native” نگهداری از session state بدون نودهای stateful است. برای داشتن نودهای stateless تنها باید به جای اینکه session state کاربران به صورت محلی در خود نودها ذخیره شود، از یک فضای ذخیره‌سازی خارجی استفاده شود.

اپلیکیشن‌هایی که مقدار session state آن‌ها خیلی کوچک باشد، می‌توانند تمام آن را در کوکی‌ها ذخیره کنند. این امر موجب می‌شود که نیازی به ذخیره‌ی محلی session state وجود نداشته باشد.

اما اگر یک کوکی نتواند تمام اطلاعات session state را ذخیره کند، همچنان می‌توان از کوکی استفاده کرد، با این تفاوت که به جای اینکه تمام اطلاعات session state داخل کوکی ذخیره شود، کوکی تنها از یک Session ID نگهداری خواهد کرد، که به session state سمت سرور متناظر می‌شود. این روش به نودهای وب اجازه می‌دهد که autonomous باقی بمانند و چالش‌های نودهای stateful را نداشته باشند. اما برخی از مسئولیت‌های scalability اکنون به عهده‌ی یک مکانیزم ذخیره‌سازی خواهد افتاد. برای مثال می‌توان از یک سرویس کش توزیع‌شده برای برون‌سپاری نگهداری از session state استفاده کرد. مثلا ElastiCache در AWS چنین سرویسی را ارائه می‌دهد.

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