آپاستریم (Upstream) مجموعهای از یک یا چند سرور است که لبههای CDN برای دریافت محتوا به آن متصل میشوند. زمانی که محتوای موردنظر در کش لبه موجود نباشد، لبه درخواست را به آپاستریم ارسال میکند و پاسخ دریافتشده را به کاربر تحویل میدهد.
بنابراین، آپاستریم بخشی از مسیر دریافت محتواست و مشخص میکند لبه برای دریافت یک محتوا باید به چه سرورهایی متصل شود.
ساختار آپاستریم
هر آپاستریم میتواند یک یا چند سرور داشته باشد. وقتی یک درخواست به آپاستریم میرسد، یکی از سرورهای آن برای دریافت درخواست انتخاب میشود.
میتوانیم این مسیر را به شکل زیر در نظر بگیریم:
flowchart LR client(["کاربر"]) edge(["لبه CDN"]) rule(["قانون مسیر"]) upstream(["آپاستریم"]) server(["سرور"]) client --> edge --> rule --> upstream --> server
قانون مسیر مشخص میکند درخواست به کدام آپاستریم ارسال شود. سپس آپاستریم مشخص میکند درخواست به کدام سرور خود ارسال شود.
این تفکیک باعث میشود انتخاب آپاستریم را از انتخاب سرور داخل آن مستقل کنیم. برای مثال، میتوانیم چند سرور را در یک آپاستریم قرار دهیم و بدون تغییر قانون مسیر، نحوه توزیع درخواستها بین این سرورها را تغییر دهیم.
چند سرور در یک آپاستریم
داشتن چند سرور در یک آپاستریم دو کاربرد اصلی دارد:
- توزیع بار: درخواستها را بین چند سرور تقسیم میکنیم تا بار روی یک سرور متمرکز نشود.
- افزایش دسترسپذیری: در صورت اختلال یک سرور، میتوانیم درخواستهای جدید را به سرورهای سالم ارسال کنیم.
برای توزیع بار، آپاستریم میتواند از الگوریتمهای مختلفی استفاده کند. در حالت Weighted Round Robin، سهم هر سرور بر اساس وزن آن تعیین میشود. بنابراین، سروری با وزن بیشتر درخواستهای بیشتری دریافت میکند.
در Consistent Hashing، انتخاب سرور بر اساس یک کلید انجام میشود. این کلید میتواند مثلا IP کاربر یا مقادیر تعدادی از Headerهای درخواست باشد. این روش زمانی کاربرد دارد که بخواهیم درخواستهایی با یک کلید مشخص، تا حد امکان به یک سرور یکسان ارسال شوند.
جزییات الگوریتمها و تنظیمات آنها در مرجع آپاستریم آمده است.
سرورهای Active و Passive
سرورهای یک آپاستریم میتوانند در دو نقش Active و Passive قرار بگیرند.
سرورهای Active در توزیع عادی درخواستها شرکت میکنند. در حالت عادی، درخواستها میان این سرورها توزیع میشوند.
سرورهای Passive برای شرایط Failover نگه داشته میشوند و در توزیع عادی درخواستها شرکت نمیکنند. زمانی که سرورهای Active در دسترس نباشند، سرورهای Passive میتوانند وارد چرخه دریافت درخواست شوند.
بنابراین، Passive را نباید صرفا یک سرور با وزن کمتر در نظر بگیریم؛ این سرورها بخشی از مکانیزم Failover هستند.
برای جزییات راهاندازی این الگو، فعالسازی Failover با سرور Passive را مطالعه میکنیم.
سلامتسنجی سرورها
اگر یک آپاستریم چند سرور داشته باشد، باید بتوانیم تشخیص دهیم کدام سرورها در هر لحظه آماده دریافت درخواست هستند.
Health Check برای همین منظور استفاده میشود. CDN بهصورت دورهای وضعیت سرورها را بررسی میکند و سرورهایی را که شرایط سلامت را ندارند، از توزیع درخواستهای جدید خارج میکند.
این موضوع باعث میشود خرابی یک سرور لزوما به قطع دریافت محتوا منجر نشود؛ درخواستهای جدید میتوانند به سرورهای سالم ارسال شوند.
اما سلامت اتصال شبکه با سلامت برنامه یکسان نیست. برای مثال، ممکن است یک سرور اتصال TCP را بپذیرد، اما برنامه روی آن نتواند درخواستهای HTTP را بهدرستی پردازش کند.
بنابراین، نوع Health Check باید متناسب با چیزی باشد که میخواهیم سلامت آن را بررسی کنیم.
مهلت زمانی Health Check فقط مربوط به پروب سلامتسنجی است و با مهلت انتظار برای پاسخ درخواستهای عادی متفاوت است. جزییات Timeoutها در مرجع آپاستریم آمده است.
پروتکل ارتباط با آپاستریم
پروتکل ارتباط کاربر با لبه مستقل از پروتکل ارتباط لبه با آپاستریم است.
برای مثال، ممکن است کاربر با HTTPS به CDN متصل شود، اما لبه برای دریافت محتوا از آپاستریم از HTTP استفاده کند. در صورت استفاده از HTTPS برای ارتباط با آپاستریم، ارتباط بین لبه و آپاستریم نیز با TLS برقرار میشود.
بنابراین، این دو ارتباط را جداگانه در نظر میگیریم:
flowchart LR client(["کاربر"]) edge(["لبه CDN"]) origin(["آپاستریم"]) client -->|"HTTPS"| edge edge -->|"HTTP یا HTTPS"| origin
پروتکل HTTPS
با انتخاب
HTTPS، ارتباط لبه CDN با سرور آپاستریم روی TLS برقرار میشود. CDN ستون گواهی سرور آپاستریم را Verify نمیکند و گواهیهای Self-signed نیز پذیرفته میشوند.
مرز TLS سمت کاربر با TLS تا مبدا در گواهی TLS چیست؟ آمده است.
نقش Host در ارتباط با آپاستریم
وقتی لبه یک درخواست را به آپاستریم ارسال میکند، مقدار Header به نام Host مشخص میکند درخواست برای کدام سایت ارسال شده است.
این موضوع زمانی اهمیت بیشتری پیدا میکند که یک سرور چند وبسایت را بهصورت Virtual Hosting میزبانی کند. در این حالت ممکن است چند سایت روی یک IP قرار داشته باشند و سرور بر اساس مقدار Host تشخیص دهد کدام سایت باید درخواست را پردازش کند.
برای مثال:
flowchart TB edge(["لبه CDN"]) subgraph origin ["IP: 192.0.2.10"] siteA(["example.com"]) siteB(["api.example.com"]) siteC(["another-site.com"]) end edge -->|"Host: example.com"| siteA
بنابراین، اتصال لبه به IP سرور بهتنهایی برای تعیین سایت مقصد کافی نیست؛ مقدار Host نیز میتواند در انتخاب سایت توسط سرور نقش داشته باشد.
در آپاستریم میتوانیم نحوه تعیین Host ارسالی را متناسب با معماری سرویس خود تنظیم کنیم. جزییات حالتهای مختلف در مرجع آپاستریم آمده است.
قانون مسیر و قانون آپاستریم
بعد از ایجاد یک آپاستریم، باید مشخص کنیم چه درخواستهایی به آن ارسال شوند.
دو مکانیزم اصلی برای این کار وجود دارد:
قانون مسیر برای تصمیمگیری بر اساس مسیر درخواست استفاده میشود. برای مثال:
flowchart LR staticPath(["/static/*"]) apiPath(["/api/*"]) defaultPath(["/*"]) staticUp(["Static Upstream"]) apiUp(["API Upstream"]) defaultUp(["Default Upstream"]) staticPath --> staticUp apiPath --> apiUp defaultPath --> defaultUp
در مقابل، قانون آپاستریم میتواند برای یک مسیر یکسان، بر اساس ویژگیهای درخواست آپاستریم متفاوتی را انتخاب کند؛ برای مثال بر اساس موقعیت جغرافیایی یا IP کاربر.
پس میتوانیم جریان تصمیمگیری را اینگونه تصور کنیم:
flowchart TB req(["درخواست"]) loc(["قانون مسیر"]) up(["آپاستریم"]) srv(["سرور"]) req --> loc loc -->|"انتخاب آپاستریم"| up up -->|"انتخاب سرور"| srv
این تفکیک باعث میشود دو مساله متفاوت را از هم جدا کنیم:
- کدام آپاستریم باید درخواست را دریافت کند؟
- کدام سرور داخل آپاستریم باید درخواست را پردازش کند؟
اگر تصمیمگیری بر اساس مسیر URL باشد، قانون مسیر ابزار اصلی ماست. اگر چند درخواست با مسیر یکسان باید بر اساس ویژگیهایی مانند موقعیت کاربر به آپاستریمهای متفاوت ارسال شوند، قانون آپاستریم کاربرد دارد.
آپاستریم و دسترسپذیری
ترکیب چند سرور، Health Check و Failover میتواند باعث شود خرابی یک سرور بهتنهایی باعث از دست رفتن مسیر دریافت محتوا نشود.
برای مثال، فرض کنیم یک آپاستریم سه سرور Active دارد:
flowchart LR edge(["لبه CDN"]) up(["آپاستریم"]) s1(["Server 1"]) s2(["Server 2"]) s3(["Server 3"]) edge --> up up --> s1 up --> s2 up --> s3
اگر Health Check نشان دهد Server 2 سالم نیست، این سرور از توزیع درخواستهای جدید خارج میشود:
flowchart LR edge(["لبه CDN"]) up(["آپاستریم"]) s1(["Server 1 سالم"]) s2(["Server 2 ناسالم"]) s3(["Server 3 سالم"]) edge --> up up --> s1 up -.-> s2 up --> s3
در نتیجه، تا زمانی که سرورهای سالم دیگری وجود داشته باشند، درخواستهای جدید میتوانند بدون تغییر در قانون مسیر به آنها ارسال شوند.
اگر سرورهای Active کافی نباشند، سرورهای Passive میتوانند برای Failover وارد مدار شوند.
آپاستریم و موقعیت جغرافیایی
موقعیت سرورهای یک آپاستریم میتواند روی مسیر شبکه و زمان دریافت محتوا از آپاستریم اثر بگذارد.
برای مثال، اگر یک سرویس سرورهایی در چند موقعیت جغرافیایی داشته باشد، میتوانیم با استفاده از قوانین مسیریابی، درخواستها را بر اساس ویژگیهایی مانند موقعیت کاربر به آپاستریمهای متفاوت هدایت کنیم.
این موضوع با کش CDN متفاوت است. حتی اگر محتوا در لبه کش نشده باشد، میتوانیم بر اساس قوانین مسیریابی تعیین کنیم لبه برای دریافت آن محتوا به کدام آپاستریم متصل شود.
انتخاب آپاستریم با مسیر شبکه تا همان آپاستریم یکی نیست. مسیریابی هوشمند مبدا را عوض نمیکند؛ در اختلال شبکه یا برای خزنده، مسیر لبه تا همان مبدا را عوض میکند.
