بلاگ/راه‌اندازی HAProxy برای Load Balancer بین چند سرور مجازی و اختصاصی
به‌روز شده

راه‌اندازی HAProxy برای Load Balancer بین چند سرور مجازی و اختصاصی

1405/06/040 بازدید
راه‌اندازی HAProxy برای Load Balancer بین چند سرور مجازی و اختصاصی

راه‌اندازی HAProxy برای Load Balancer بین چند سرور مجازی و اختصاصی

وقتی یک وب‌سایت فقط روی یک سرور اجرا می‌شود، تمام درخواست‌ها، پردازش‌ها و وابستگی‌های سرویس به همان ماشین متکی هستند. افزایش ترافیک می‌تواند منابع آن را پر کند و خرابی سرور نیز کل سرویس را از دسترس خارج می‌کند. یکی از راه‌های کاهش این وابستگی، اجرای برنامه روی چند سرور و قرار دادن یک Load Balancer در جلوی آن‌هاست؛ همین الگو در مقیاس بزرگ‌تر، مثلاً برای Load Balancer در کلاستر Kubernetes، هم کاربرد دارد. HAProxy یک پراکسی معکوس و توزیع‌کننده بار متن‌باز است که می‌تواند درخواست‌های TCP و HTTP را میان چند سرور مجازی یا اختصاصی تقسیم کند. این نرم‌افزار علاوه بر توزیع ترافیک، وضعیت سرورهای پشت صحنه را بررسی می‌کند و سرورهای معیوب را موقتاً از چرخه خارج می‌کند. در این آموزش، راه‌اندازی HAProxy برای Load Balancer را با یک سناریوی عملی بررسی می‌کنیم: یک سرور HAProxy در ورودی و سه وب‌سرور Nginx در لایه Backend. نمای کلی معماری HAProxy و سه وب‌سرور

معماری نمونه و پیش‌نیازها

فرض می‌کنیم چهار سرور با سیستم‌عامل Ubuntu 24.04 یا 22.04 در اختیار داریم: - سرور Load Balancer با IP عمومی 203.0.113.10 - وب‌سرور اول با IP خصوصی 10.10.0.11 - وب‌سرور دوم با IP خصوصی 10.10.0.12 - وب‌سرور سوم با IP خصوصی 10.10.0.13 آدرس‌های بالا نمونه هستند و باید آن‌ها را با IP واقعی سرورها جایگزین کنید. بهتر است ارتباط HAProxy با Backendها از طریق شبکه خصوصی انجام شود. به این ترتیب، ترافیک داخلی از اینترنت عمومی عبور نمی‌کند و لازم نیست پورت وب‌سرورها برای همه IPها باز باشد. برای اجرای این سناریو به دسترسی sudo، ارتباط شبکه میان سرورها و پورت‌های باز موردنیاز احتیاج دارید. روی سرور HAProxy معمولاً پورت‌های 80 و 443 از اینترنت پذیرفته می‌شوند. روی Backendها نیز پورت سرویس، در این مثال 80، فقط باید از IP سرور HAProxy قابل دسترسی باشد؛ برای اعمال این محدودیت می‌توان از فایروال UFW روی هر Backend استفاده کرد. یک Load Balancer به‌تنهایی نقطه خرابی ورودی را حذف نمی‌کند. اگر دسترس‌پذیری در سطح ورودی حیاتی است، باید در مرحله بعد دو نمونه HAProxy همراه با یک IP مجازی یا سرویس Failover راه‌اندازی کنید. این مقاله روی توزیع بار میان Backendها تمرکز دارد.

آماده‌سازی وب‌سرورهای Nginx

ابتدا روی هر سه سرور Backend، Nginx را نصب کنید:

sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx

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

echo '<h1>Backend 1</h1>' | sudo tee /var/www/html/index.html

روی سرور دوم:

echo '<h1>Backend 2</h1>' | sudo tee /var/www/html/index.html

و روی سرور سوم:

echo '<h1>Backend 3</h1>' | sudo tee /var/www/html/index.html

سپس از سرور Load Balancer بررسی کنید که هر سه مقصد قابل دسترسی باشند:

curl http://10.10.0.11
curl http://10.10.0.12
curl http://10.10.0.13

اگر یکی از درخواست‌ها پاسخ نمی‌دهد، پیش از نصب HAProxy مسیر شبکه، فایروال سیستم‌عامل، Security Group و وضعیت Nginx را بررسی کنید. HAProxy نمی‌تواند مشکل ارتباط پایه میان سرورها را برطرف کند.

نصب HAProxy روی سرور Load Balancer

روی سرور ورودی، بسته HAProxy را از مخزن سیستم‌عامل نصب کنید:

sudo apt update
sudo apt install -y haproxy

نسخه نصب‌شده را ببینید:

haproxy -v

سرویس را نیز برای اجرا پس از راه‌اندازی مجدد سیستم فعال کنید:

sudo systemctl enable haproxy

فایل اصلی پیکربندی در اوبونتو و دبیان معمولاً در مسیر زیر قرار دارد:

/etc/haproxy/haproxy.cfg

پیش از تغییر فایل، یک نسخه پشتیبان بسازید:

sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.backup

ساخت پیکربندی اولیه HAProxy

پیکربندی HAProxy معمولاً از چهار بخش تشکیل می‌شود: global برای تنظیمات سطح پردازش، defaults برای مقادیر پیش‌فرض، frontend برای ورودی درخواست‌ها و backend برای تعریف سرورهای مقصد. فایل /etc/haproxy/haproxy.cfg را با ویرایشگر دلخواه باز کنید و نمونه زیر را متناسب با شبکه خود قرار دهید:

global
    log /dev/log local0
    log /dev/log local1 notice
    user haproxy
    group haproxy
    daemon
    maxconn 4096
defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5s
    timeout client 30s
    timeout server 30s
frontend http_front
    bind *:80
    default_backend web_servers
backend web_servers
    balance roundrobin
    option httpchk GET /
    http-check expect status 200
    server web1 10.10.0.11:80 check
    server web2 10.10.0.12:80 check
    server web3 10.10.0.13:80 check

در بخش frontend، دستور bind *:80 باعث می‌شود HAProxy روی پورت ۸۰ تمام رابط‌های شبکه گوش دهد. default_backend نیز درخواست‌ها را به مجموعه web_servers می‌فرستد. در بخش Backend، الگوریتم roundrobin درخواست‌ها را به‌ترتیب میان سرورها پخش می‌کند. گزینه check در انتهای هر خط، بررسی سلامت آن سرور را فعال می‌کند. دستورهای option httpchk و http-check expect مشخص می‌کنند که HAProxy مسیر / را درخواست کند و کد وضعیت 200 را پاسخ سالم بداند.

بررسی پیکربندی پیش از اجرا

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

sudo haproxy -c -f /etc/haproxy/haproxy.cfg

اگر پیام معتبر بودن پیکربندی نمایش داده شد، سرویس را راه‌اندازی مجدد کنید:

sudo systemctl restart haproxy
sudo systemctl status haproxy

برای تغییرات بعدی می‌توانید پس از اعتبارسنجی از Reload استفاده کنید تا اتصال‌های موجود با اختلال کمتری روبه‌رو شوند:

sudo systemctl reload haproxy

انتخاب الگوریتم مناسب توزیع بار

HAProxy چند الگوریتم برای انتخاب Backend دارد. انتخاب درست به نوع برنامه، طول اتصال‌ها و تفاوت ظرفیت سرورها بستگی دارد.

الگوریتمرفتارکاربرد مناسب
roundrobinدرخواست‌ها را به‌ترتیب پخش می‌کندوب‌سرورهای هم‌ظرفیت و درخواست‌های مشابه
leastconnسروری را انتخاب می‌کند که اتصال فعال کمتری دارداتصال‌های طولانی یا زمان پردازش نامتوازن
sourceمقصد را بر اساس IP مبدأ انتخاب می‌کندحفظ نسبی وابستگی کاربر به یک Backend
randomمقصد را با انتخاب تصادفی کنترل‌شده تعیین می‌کندکلاسترهای بزرگ و بار عمومی

اگر یک سرور اختصاصی قوی در کنار دو VPS کوچک دارید، تقسیم برابر ترافیک منطقی نیست. برای تعیین سهم هر سرور می‌توان از weight استفاده کرد:

backend web_servers
    balance roundrobin
    server dedicated1 10.10.0.11:80 check weight 4
    server vps1       10.10.0.12:80 check weight 2
    server vps2       10.10.0.13:80 check weight 2

در این نمونه، سرور اختصاصی تقریباً دو برابر هر VPS سهم می‌گیرد. وزن مناسب را باید با توجه به CPU، حافظه، توان شبکه و نتایج آزمون بار تعیین کنید؛ تعداد هسته به‌تنهایی معیار کافی نیست.

تنظیم Health Check دقیق‌تر

بررسی صفحه اصلی همیشه روش خوبی برای سنجش سلامت برنامه نیست. ممکن است Nginx پاسخ 200 بدهد، اما برنامه به دیتابیس دسترسی نداشته باشد. بهتر است برنامه یک مسیر سبک مانند /health داشته باشد که وابستگی‌های ضروری را بررسی کند. پیکربندی Backend در این حالت می‌تواند چنین باشد:

backend web_servers
    balance leastconn
    option httpchk GET /health
    http-check expect status 200
    default-server inter 3s fall 3 rise 2
    server web1 10.10.0.11:80 check
    server web2 10.10.0.12:80 check
    server web3 10.10.0.13:80 check

پارامتر inter 3s فاصله بررسی‌ها را سه ثانیه تعیین می‌کند. fall 3 یعنی پس از سه بررسی ناموفق، سرور Down شناخته شود. rise 2 نیز بازگشت سرور را به دو بررسی موفق متوالی وابسته می‌کند. این آستانه‌ها از خارج و وارد شدن مکرر یک Backend ناپایدار جلوگیری می‌کنند. مسیر Health Check نباید عملیات سنگین اجرا کند. همچنین بهتر است فقط وابستگی‌هایی را بررسی کند که نبود آن‌ها واقعاً مانع پاسخ‌گویی برنامه می‌شود. وابسته کردن این مسیر به یک سرویس جانبی غیرضروری ممکن است تمام Backendها را هم‌زمان ناسالم نشان دهد.

عبور دادن اطلاعات واقعی کاربر

چون اتصال HTTP ابتدا به HAProxy می‌رسد، وب‌سرور ممکن است IP پراکسی را به‌جای IP کاربر ثبت کند. با افزودن option forwardfor، HAProxy آدرس کاربر را در هدر X-Forwarded-For قرار می‌دهد:

backend web_servers
    balance roundrobin
    option forwardfor
    option httpchk GET /health
    server web1 10.10.0.11:80 check
    server web2 10.10.0.12:80 check
    server web3 10.10.0.13:80 check

برای تشخیص پروتکل اصلی نیز می‌توانید در Frontend هدر زیر را تنظیم کنید:

frontend http_front
    bind *:80
    http-request set-header X-Forwarded-Proto http
    default_backend web_servers

در محیط HTTPS مقدار این هدر باید متناسب با محل پایان TLS تنظیم شود. برنامه یا Nginx نیز باید فقط هدرهای پراکسی‌های مورد اعتماد را بپذیرد؛ اعتماد عمومی به X-Forwarded-For امکان جعل IP را ایجاد می‌کند. فهرست کامل‌تری از این نکات در ترفندهای امنیتی Nginx آمده است.

فعال‌سازی صفحه آمار

HAProxy یک صفحه داخلی برای مشاهده وضعیت Backendها، تعداد اتصال‌ها و نتیجه Health Check دارد. آن را روی یک پورت جداگانه فعال کنید:

listen stats
    bind 127.0.0.1:8404
    mode http
    stats enable
    stats uri /stats
    stats refresh 10s

اتصال به 127.0.0.1 باعث می‌شود صفحه مستقیماً از اینترنت قابل دسترسی نباشد. برای مشاهده آن می‌توانید تونل SSH بسازید:

ssh -L 8404:127.0.0.1:8404 user@203.0.113.10

سپس در مرورگر آدرس http://127.0.0.1:8404/stats را باز کنید. اگر لازم است این صفحه از شبکه مدیریتی دیده شود، دسترسی را با فایروال، احراز هویت و محدودیت IP کنترل کنید.

آزمایش توزیع بار و خرابی Backend

پس از اجرای سرویس، چند درخواست متوالی به IP عمومی Load Balancer بفرستید:

for i in $(seq 1 9); do
  curl -s http://203.0.113.10
done

با الگوریتم roundrobin باید پاسخ Backendهای مختلف را ببینید. سپس Nginx را موقتاً روی یکی از Backendها متوقف کنید:

sudo systemctl stop nginx

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

sudo systemctl start nginx

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

نکات مهم برای محیط عملیاتی

Timeoutها را متناسب با برنامه تنظیم کنید. مقدار بسیار کم ممکن است درخواست‌های معتبر را قطع کند و مقدار بسیار زیاد، اتصال‌های معیوب را مدت بیشتری نگه دارد. برای WebSocket، دانلود فایل‌های بزرگ یا APIهای پردازش‌محور باید زمان‌های client و server جداگانه بررسی شوند. اگر برنامه Session را در حافظه محلی هر Backend نگه می‌دارد، جابه‌جایی کاربر میان سرورها مشکل ایجاد می‌کند. راه پایدارتر، انتقال Session به یک مخزن مشترک مانند Redis است. قابلیت Sticky Session در HAProxy نیز وجود دارد، اما وابستگی به یک Backend را بیشتر می‌کند و باید آگاهانه انتخاب شود. TLS را می‌توان روی HAProxy خاتمه داد و ترافیک را داخل شبکه خصوصی به‌صورت HTTP فرستاد. در شبکه‌های نامطمئن یا محیط‌هایی با الزام امنیتی، ارتباط HAProxy تا Backend نیز باید رمزنگاری شود. تمدید خودکار گواهی، محدود کردن نسخه‌های TLS و نگهداری امن کلید خصوصی بخشی از آماده‌سازی HTTPS هستند. لاگ‌های HAProxy را به سامانه مانیتورینگ بفرستید و شاخص‌هایی مانند نرخ خطای 5xx، زمان پاسخ، تعداد اتصال‌های فعال و تعداد Backendهای سالم را زیر نظر بگیرید. صرف روشن بودن سرویس به معنای عملکرد درست آن نیست؛ ابزارها و راهکارهای مانیتورینگ لینوکس نقطه شروع خوبی برای این کار هستند.

انتخاب زیرساخت برای HAProxy و Backendها

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

جمع‌بندی

راه‌اندازی HAProxy برای Load Balancer با تعریف یک Frontend، یک Backend و فعال کردن Health Check شروع می‌شود. در نمونه این مقاله، درخواست‌های ورودی میان سه وب‌سرور Nginx توزیع شدند و Backend معیوب به‌صورت خودکار از چرخه کنار رفت. برای استفاده عملی، الگوریتم توزیع بار و وزن سرورها را بر اساس ظرفیت واقعی انتخاب کنید، مسیر Health Check اختصاصی بسازید، دسترسی شبکه Backendها را محدود نگه دارید و رفتار سیستم را با لاگ و متریک بررسی کنید. اگر قطع شدن سرور HAProxy نیز قابل قبول نیست، دو Load Balancer و سازوکار Failover مرحله بعدی معماری خواهند بود.