معماری وب: آشنایی با مفاهیم پایه

معماری مدرن برنامه‌های تحت وب در یک نگاه
معماری مدرن برنامه‌های تحت وب در یک نگاه

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

۱. سامانه نام دامنه (DNS)

سامانه نام دامنه (Domain Name System) یا مخفف رایج‌تر آن DNS یک فناوری پایه و حیاتی برای وجود شبکه­‌ی جهانی اینترنت است. در سطوح اولیه، DNS یک کلید/مقدار (مثلاً google.com) را به یک IP (مثلاً: 85.129.83.120) ربط می­‌دهد که باعث می­شود کامپیوتر شما یک درخواست به سرور مناسب بفرستد. اگر این سیستم را به برقراری تماس تلفنی تشبیه کنیم، فرآیند کار DNS مانند تبدیل «با علی تماس بگیر» به این است که: «با شماره‌­ی 22112233 تماس بگیر». همانطور که در گذشته برای پیدا کردن شماره تلفن علی باید در دفترچه تلفن دنبال آن می­‌گشتید، امروزه نیز برای پیدا کردن IP یک دامنه به DNS نیاز دارید. می­توان گفت DNS دفترچه تلفن اینترنت است.

جزئیات بسیار زیادی هستند که می­توان به آن­ها پرداخت، اما برای مراحل ابتدایی تا همینجا کافی است.

۲. متوازن­‌کننده بار (Load Balancer)

قبل از پرداختن به جزئیات توازن بار، باید راجع به مقیاس‌دهی افقی و عمودی اپلیکیشن توضیح بدهیم. به طور ساده، تغییر مقیاس افقی یعنی افزایش «تعداد» منابع مثلاً از طریق افزایش تعداد کامپیوترها؛ در حالی که تغییر مقیاس عمودی یعنی افزایش «قدرت» منابعی که در اختیار داریم مثلاً با ارتقای CPU یا RAM کامپیوتر.

در توسعه­‌ی وب، شما تقریباً همیشه باید به صورت افقی مقیاس کنید، دلیل آن هم این است که هر چیزی خراب می­شود! سرورها ناخواسته به مشکل می­‌خورند، شبکه‌­ها تحلیل می­روند، حتی گاهی یک مرکز داده (Data Center) به طور کلی آفلاین می­‌شود. داشتن چند سرور باعث می­‌شود بتوانید از قطعی­‌ها فرار کنید و برنامه­‌ی شما همچنان کار کند. در واقع برنامه­‌ی شما "مقاوم به مشکل" (Fault Tolerant) می­‌شود. مزیت دوم تغییر مقیاس افقی این است که اجزای مختلف Back-end برنامه ­ی شما (مانند سرور شبکه، دیتابیس و...) اگر روی سرورهای جدا قرار داشته باشند، کمترین وابستگی را به هم خواهند داشت. مورد آخر هم این که در نهایت برای مقیاس عمودی محدودیت وجود دارد و به جایی می­رسید که دیگر نمی­توانید مقیاس عمودی بیشتری انجام دهید. هیچ کامپیوتری آنقدر قوی نیست که بتواند از عهده­‌ی تمام محاسبات مورد نیاز شما بر بیاید!

خب، برگردیم به متوازن کننده­ های بار، همان چاشنی جادویی که مقیاس افقی را امکان­‌پذیر می‌کند! کار آن­ها این است که درخواست را به یکی از چندین سرور اپلیکیشن که معمولاً دقیقاً شبیه هم (یا Mirror Image هم هستند) بفرستند و پاسخ آن را به کاربر (Client) برگردانند. همه­‌ی این سرورها درخواست را مشابه یکدیگر مدیریت می­‌کنند، پس مسئله صرفا توزیع درخواست­‌ها است به طوری که هیچ کدام از سرورها بار اضافی نگیرند.

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

۳. سرور برنامه­‌های مبتنی بر وب (Web Application Servers)

در بیان کلی، سرورهای برنامه­‌های مبتنی بر وب را می‌توان به سادگی معرفی کرد. آن­ها منطق مورد نیاز برای مدیریت کردن درخواست­‌های کاربر را اجرا می­‌کنند و پاسخ را در قالب HTML به مرورگر کاربر می­‌فرستند. سرورها برای کار خود، با زیرساخت­‌های بک‌اند مختلف مثل دیتابیس­‌ها، لایه­‌های Cache، صف­‌های انجام کار (Job Queues) و... در ارتباط هستند. همان طور که بالاتر گفته شد، به صورت معمول حداقل دو سرور وجود دارد (و خیلی مواقع بیشتر) که به یک متوازن­‌کننده بار متصل شده‌­اند تا درخواست کاربر بتواند پردازش شود.

برای پیاده‌­سازی سرورهای برنامه، به یک زبان برنامه‌نویسی (مثلاً Node.js ،Ruby ،PHP، جاوا، اسکالا، سی‌شارپ و...) و در کنار آن یک فریم‌ورک Web MVC برای آن زبان (Express برای Node.js، لاراول برای پی‌اچ‌پی، Play برای Scala و...) نیاز است. البته جزئیات این موارد فراتر از موضوع این مقاله است.

۴. سرورهای دیتابیس

امروزه هر برنامه­‌ی شبکه از یک یا تعدادی بیشتر دیتابیس برای ذخیره‌­سازی اطلاعات استفاده می­‌کند. دیتابیس به شما امکان تعریف داده­‌ساختارهای خود، اضافه­ کردن داده­‌ی جدید، پیدا کردن داده، به‌­روز کردن یا پاک کردن داده، و خیلی کارهای دیگر را می­‌دهد. سرورهای برنامه­‌های تحت وب معمولاً مستقیم به یک دیتابیس متصل می‌شوند، علاوه بر این هر سرویس Back-end ممکن است دیتابیس خاص خود را داشته باشد که از بقیه­‌ی برنامه جدا است.

درست است که از پرداختن به خیلی از جزئیات پرهیز می‌­کنیم اما دانستن جزئیات دو مورد بهتر از ندانستن آن‌هاست: SQL و NoSQL.

زبان SQL (که مخفف Structured Query Language یا به عبارتی زبان ساختارمند پرسش‌ها) است در دهه ۷۰ میلادی ایجاد شد. هدف از ساخت این زبان، ایجاد راهکاری ساده برای کوئری زدن بر روی مجموعه داده‌های رابطه‌ای (Relational Data Sets) بود. دیتابیس‌­های SQL داده‌­ها را در جدول­‌هایی نگه می­دارند که به وسیله‌­ی IDهای مشترک با یکدیگر مرتبط هستند. بگذارید مثال ساده‌­ای در مورد ذخیره‌­ی اطلاعات آدرس کاربران بزنیم:

می‌توانیم داده‌ها را در دو جدول ذخیره کنیم: یکی جدول users و دیگری جدول user_addresses. هر دو این جدول‌ها یک ستون id دارند که به ترتیب، شناسه‌ی کاربرها و شناسه‌ی آدرس‌ها را با یک عدد یکتا مشخص می‌کند. در جدول user_addresses یک ستون به نام user_id نیز قرار دارد که یک کلید خارجی (Foreign Key) محسوب می‌شود و این دو جدول را به یکدیگر متصل می‌کند. با user_id می‌توانیم بفهمیم آدرسی که ذخیره شده است برای کدام کاربر است. تصویر زیر یک طرح ساده از این مثال است:

اگر با SQL آشنایی ندارید، بهتر است کمی در مورد آن مطالعه کنید؛ زیرا در بخش‌های زیادی از توسعه­‌ی وب به کار می‌رود و آشنایی با مبانی آن بسیار کاربردی است.

در طرف مقابل NoSQL، که به معنای غیر SQL (یا Non-SQL) است، مجموعه‌­ای جدیدتر از فناوری­‌های دیتابیس است. هدف ایجاد NoSQL مدیریت حجم عظیم داده­‌هایی است که برخی برنامه‌های تحت وب در مقیاس بزرگ تولید می­‌کنند. بیشتر انواع SQL معمولاً به خوبی نمی­‌توانند به صورت افقی مقیاس کنند و تنها توانایی مقیاس شدن عمودی (آن هم به شکل محدود) را دارند. اگر در مورد NoSQL به کسب اطلاعات تکمیلی نیاز دارید، می‌توانید نگاهی به منابع زیر بیندازید:

در نظر داشته باشید که به طور کلی دنیای وب، حتی برای دیتابیس­‌های NoSQL، از SQL استفاده می­‌کند. پس حتماً باید SQL یاد بگیرید و هیچ راه فراری از آن ندارید.

۵. سرویس­‌های Caching

یک سرویس Caching، پایگاه داده ساده­‌ای به صورت کلید/مقدار (یا به عبارتی Key/Value) در اختیار ما می‌گذارد که امکان ذخیره و پیدا کردن اطلاعات را تقریباً با O(1) فراهم می­کند. برنامه­‌ها از سرویس‌­های Caching استفاده می­کنند تا نتایج محاسبات پرخرج و پرزحمت را نگه دارند و به این ترتیب دفعه‌­ی بعد نیازی نباشد که دوباره این محاسبات از اول انجام شوند و صرفا نتایج از Cache بازیابی می‌­شوند. یک برنامه می‌تواند نتایج یک کوئری دیتابیس، نتایج ارتباط با سرویس­‌های خارجی، HTML یک URL خاص و خیلی چیزهای دیگر از این دست را Cache کند. مثال­‌هایی از دنیای واقعی ببینید:

  • گوگل نتایج جست­جوهای پرطرفدار مثل “آب” یا “سریال جدید” را Cache می‌کند تا هر دفعه نیازی به محاسبه کردن آن‌ها نباشد.
  • فیس­بوک خیلی از چیزهایی که بعد از ورود می­‌بینید، مثلاً داده‌های پست‌ها، فهرست دوستان و... را Cache می­کند. درباره سیستم Caching فیس‌بوک در این مطلب می‌توانید بیشتر بخوانید.

فراگیرترین فناوری‌های کاربردی برای Caching عبارتند از Redis و Memcached.

۶. صف کار (Job Queue & Servers)

بیشتر برنامه‌­های تحت وب نیاز دارند که یک سری کار را به صورت ناهمگام (Asynchronously) در پشت پرده انجام دهند که بعضاً ربط مستقیمی هم به درخواست کاربر ندارند. مثلاً گوگل باید کل اینترنت را Crawl کند (خزش در صفحات وب) و نتایج را نمایه کند تا بتواند پاسخ جست­جوها را بدهد. گوگل این کارها را صرفاً زمان جست­جوی کاربر انجام نمی‌دهد، بلکه به صورت ناهمگامی شبکه را Crawl می­کند و نمایه‌­های جست­جو را به طور مداوم به روز می­‌کند. یا مثال روزمره دیگری که همگی که با آن سروکار داشته‌ایم، زمانی است که کاربر در سایت عضو می‌شود و قرار است برای او ایمیل تایید عضویت ارسال شود. پیامی مبنی بر ارسال ایمیل سریعاً به کاربر نمایش داده می‌شود اما در واقع ایمیل هنوز ارسال نشده و به صورت ناهمگام و کمی بعدتر ارسال می‌شود.

ساختارهای زیادی برای کار کردن به صورت ناهمگام وجود دارد، فراگیرترین آن چیزی است که آن را ساختار «صف کار» می­نامیم. دو جزء اینجا ایفای نقش می­‌کنند: یک صف «کار» که باید اجرا شود و یک یا چند سرور کار (معمولا به آن­ها "کارگر" می­گویند) که باید کارهای صف را انجام دهند.

صف­‌های کار لیستی از کارها که باید به صورت ناهمگام انجام شوند نگه می­دارند. ساده ­ترین نوع آن‌­ها صف‌های «خروج به ترتیب ورود» (یا FIFO) هستند که اولین درخواستی که وارد صف می‌شود، قبل از سایر درخواست‌ها پردازش می‌شود. هرچند FIFO در بسیاری از مواقع هم جوابگو نیست و بیشتر برنامه­‌ها در نهایت به صف­‌هایی نیاز پیدا می­کنند که اولویت‌بندی بهتری از اهمیت کارها در آن‌ها صورت می‌گیرد. هروقت یک کار باید انجام شود، چه طبق یک برنامه‌­ی منظم و چه طبق عملیات­‌های کاربر، برنامه این کار را به صف اضافه می‌کند.

سرورهای کار، کارها را پردازش می­کنند. آن­ها هر از گاهی به صف کار سر می‌زنند (Polling) تا ببیند آیا کاری برای انجام دادن هست یا نه و اگر بود، آن کار را از صف خارج، و اجرا می‌­کنند. زبان­‌ها و فریم­‌ورک­‌های این سرورها نیز همانند سرورهای شبکه بسیار گسترده می­‌باشند و برای این مقاله از ورود دقیق‌تر به آن‌ها خودداری مي‌کنیم.

۷. سرویس جست­جوی تمام متن

اکثر برنامه­‌های تحت وب، نوعی از جست­جو را درون خود دارند؛ به این صورت که کاربر یک متن ورودی می­‌دهد (Query) و برنامه مرتبط‌ترین نتایج را برمی­‌گرداند. فناوری پشت این عملیات، «جست­جوی تمام متن» (یا Full-text Search) نام دارد که از یک ایندکس معکوس (Inverted Index) استفاده می­کند تا به سرعت پست‌هایی را پیدا کند که کلیدواژه‌­های موجود در Query را دارا هستند.

نمونه­‌ای از تبدیل سه سند به ایندکس معکوس. دقت کنید که کلمه­‌های عمومی و رایج مثل “in”، “the” و “with” در ایندکس معکوس آورده نشده­‌اند.
نمونه­‌ای از تبدیل سه سند به ایندکس معکوس. دقت کنید که کلمه­‌های عمومی و رایج مثل “in”، “the” و “with” در ایندکس معکوس آورده نشده­‌اند.


با اینکه امکان انجام جست­جوی تمام متن به طور مستقیم در یک سری دیتابیس­‌ها (مثلاً MySQL) وجود دارد اما راه‌­اندازی یک «سرویس جست­جوی» جداگانه که ایندکس معکوس بسازد و رابط Query داشته باشد هم بسیار معمول است. برای این منظور امروزه Elasticsearch پرطرفدارترین پلتفرم جست­جوی تمام متن را ارائه می‌کند؛ البته موارد دیگری مثل Sphinx و Apache Solr نیز وجود دارند

۸. سرویس‌­ها (Services)

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

۹. داده (Data)

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

۱. برنامه، داده‌هایی که معمولاً درباره­‌ی رفتار کاربران است را به محیطی برای پردازش داده‌ها ارسال می‌کند. AWS Kinesis و Kafka دو فناوری رایج این کار هستند.

۲. هم داده‌­ی خام و هم داده‌­ی نهایی تغییریافته در سرویس ذخیره‌­ی ابری ذخیره می­شوند. AWS Kinesis محیطی به نام Firehose دارد که امکان ذخیره‌­ی داده‌­ی خام در سرویس ابری خودش (S3) را بسیار ساده کرده است.

۳. معمولا داده‌­ی تغییریافته برای آنالیز به یک انبار داده (Data Warehouse) بارگذاری می­‌شود. [در خارج از ایران] بسیاری از استارتاپ‌ها برای این منظور از AWS Redshift استفاده می­‌کنند، هرچند شرکت­‌های بزرگتر معمولاً از Oracle یا انبارداده‌های انحصاری دیگر استفاده می­‌کنند. اگر داده‌­ها به اندازه­‌ی کافی بزرگ باشند، باید از فناوری­های ویژه داده‌های بزرگ مانند هدوپ (Hadoop) و NoSQL استفاده کرد.

۱۰. ذخیره ابری (Cloud Storage)

ذخیره­ ی ابری راهی ساده و مقیاس‌پذیر برای ذخیره داده، دسترسی به آن و به اشتراک گذاشتن داده‌ها در اینترنت است. شما می­‌توانید هر چیزی که روی فایل‌سیستم محلی ذخیره می­‌کنید را در آن ذخیره کنید، و مزیت آن این است که با استفاده از یک RESTful API می­شود تحت HTTP به آن دسترسی داشت. سرویس S3 آمازون امروزه با اختلاف محبوب­‌ترین سرویس ذخیره‌­ی ابری جهان است.

۱۱. شبکه توزیع محتوا (CDN)

دسترسی به اطلاعات زمانی که CDN وجود دارد و زمانی که بدون CDN می‌خواهیم به آن‌ها دسترسی داشته باشیم.
دسترسی به اطلاعات زمانی که CDN وجود دارد و زمانی که بدون CDN می‌خواهیم به آن‌ها دسترسی داشته باشیم.

شبکه توزیع محتوا (Content Delivery Network) یا مخفف آن CDN راهی در اختیار ما می­گذارد تا دارایی‌هایی مثل HTML ایستا، CSS، جاوا اسکریپت و عکس‌­ها را سریع‌تر در وب به کاربران ارائه دهیم، بسیار سریعتر از زمانی که آن‌ها را از یک سرور تک‌مبدا ارائه می‌دهیم. روش کار CDN به این صورت است که محتوا را بین تعداد زیادی سرور حاشیه­‌ای در سرتاسر جهان پخش می­کند تا کاربر آن محتوا را به جای دریافت از سرور مبدا اصلی، از سرورهای حاشیه­‌ای دریافت کند. برای مثال در شکل زیر، کاربری در اسپانیا یک صفحه را از سایتی درخواست کرده که سرورهای مبدا آن در نیویورک هستند؛ اما دارایی‌های ایستا می­‌توانند از یک سرور CDN حاشیه‌­ای در انگلیس دریافت شوند تا فاصله‌­ی طولانی بین اسپانیا و نیویورک طی نشود.


برخی مطلب‌های قبلی کوئرامگ برای توسعه‌دهندگان وب:


ترجمه و تلخیص از:

"Web Architecture 101", by Jonathan Fulton at Storyblocks

کوئرامگ مجله‌ای تخصصی برای توسعه‌دهندگان است که هر هفته با مطلب‌هایی در زمینه تکنولوژی، رشد فردی و آینده برنامه‌نویسی به‌روزرسانی می‌شود. برای اطلاع از آخرین مطلب‌های ما، می‌توانید توئیتر یا کانال تلگرام کوئرا را دنبال کنید.