کاهش پینگ سرور مجازی؛ از اندازه‌گیری درست تا کاری که واقعاً جواب می‌دهد

کاهش پینگ سرور مجازی؛ از اندازه‌گیری درست تا کاری که واقعاً جواب می‌دهد

ساعت دو بامداد است، کاربر پیام داده «سایت کند شده»، و شما یک ping می‌گیرید و عدد ۱۲۰ میلی‌ثانیه می‌بینید. حالا چه؟ بیشتر کسانی که دنبال کاهش پینگ سرور مجازی می‌گردند دقیقاً همین‌جا اشتباه می‌کنند: یک عدد می‌بینند و شروع می‌کنند به عوض کردن چیزهایی که به آن عدد ربطی ندارند.

قبل از هر تنظیمی باید بدانید کدام عدد را دارید اندازه می‌گیرید. سه تأخیر کاملاً جدا وجود دارد و راه‌حل هرکدام به دیگری ربطی ندارد.

سه تأخیری که مدام با هم قاطی می‌شوند

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

  1. تأخیر شبکه (network latency): زمان رفت‌وبرگشت بسته بین کاربر و سرور. همان چیزی که ping نشان می‌دهد. واحدش RTT است.
  2. زمان پاسخ برنامه (application response time): از لحظه‌ای که سرور درخواست را گرفت تا وقتی اولین بایت پاسخ را فرستاد. این عدد کوئری دیتابیس، رندر PHP و منطق برنامه را دربر می‌گیرد و هیچ ربطی به فاصله جغرافیایی ندارد.
  3. زمان رندر مرورگر: بعد از رسیدن پاسخ، مرورگر باید JS را اجرا و صفحه را بکشد. این تماماً روی دستگاه خود کاربر می‌گذرد و سرور شما در آن نقشی ندارد.

اگر پینگ شبکه ۳۰ms است ولی صفحه ۴ ثانیه دیر می‌آید، تغییر لوکیشن سرور هیچ کمکی نمی‌کند. مشکل در برنامه یا مرورگر است. برعکسش هم درست است. پس اول تفکیک کنید.

درست اندازه بگیرید: سه دستور قابل کپی

۱) پینگ خام شبکه

ping -c 20 example.com

خروجی این شکلی تمام می‌شود:

rtt min/avg/max/mdev = 28.1/31.4/44.9/3.2 ms

به دو عدد نگاه کنید. avg سطح پایه تأخیر شبکه شماست. mdev نوسان (jitter) است؛ اگر این بزرگ باشد، مسیر ناپایدار است و برای بازی یا تماس صوتی از خود عددِ میانگین مهم‌تر است. اگر ping اصلاً جواب نداد، شاید ICMP روی مسیر بسته است؛ این به معنی قطعی نیست و باید با mtr یا curl بررسی کنید.

۲) کجای مسیر خراب است

mtr -rwz -c 100 example.com

mtr ترکیب ping و traceroute است و برای هر هاپ درصد از دست رفتن بسته (Loss%) و تأخیر را نشان می‌دهد. قاعده خواندنش: اگر Loss فقط روی یک هاپِ میانی بالا رفت ولی هاپ آخر سالم است، آن روتر صرفاً به ICMP جواب نمی‌دهد و مشکل واقعی نیست. اما اگر Loss از یک هاپ به بعد تا انتها بالا ماند، آن نقطه گلوگاه واقعی است. پرش ناگهانی تأخیر بین دو هاپ یعنی همان‌جا فاصله جغرافیایی یا ازدحام اضافه شده.

۳) شبکه یا برنامه؟

این مهم‌ترین دستور مقاله است. curl زمان را تکه‌تکه می‌کند:

curl -o /dev/null -s -w "dns: %{time_namelookup}s\nconnect: %{time_connect}s\ntls: %{time_appconnect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" https://example.com

خروجی نمونه:

dns: 0.012s
connect: 0.034s
tls: 0.071s
ttfb: 0.230s
total: 0.245s

حالا تفریق کنید و تشخیص بدهید:

  1. connect منهای dns ≈ یک RTT شبکه (دست‌دادن TCP). اینجا حدود ۲۲ms. این همان پینگ است.
  2. ttfb منهای tls = زمان پردازش برنامه روی سرور. اینجا ۰٫۲۳ منهای ۰٫۰۷ ≈ ۱۶۰ms. اگر این عدد بزرگ باشد، مقصر کد و دیتابیس است و شبکه بی‌گناه.
  3. اگر total منهای ttfb بزرگ بود، مشکل به پهنای باند یا حجم پاسخ برمی‌گردد و ربطی به تأخیر ندارد.

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

چه چیزی دست شماست: فاصله را کم کنید

تأخیر شبکه یک کف فیزیکی دارد که هیچ تنظیمی از آن پایین‌تر نمی‌رود. نور در فیبر با حدود ۲۰۰٬۰۰۰ کیلومتر بر ثانیه حرکت می‌کند، یعنی نزدیک دوسوم سرعت نور در خلأ. قاعده سرانگشتی این است: تقریباً ۱ms رفت‌وبرگشت به ازای هر ۱۰۰ کیلومتر فیبر (m2optics).

یعنی اگر کاربرانتان در تهران‌اند و سرور در اروپا حدود ۴٬۵۰۰ کیلومتر دورتر است، کف فیزیکی پینگ حدود ۴۵ms است و در عمل به‌خاطر مسیریابی همیشه بیشتر می‌شود. این عدد را با هیچ کرنل‌تیونینگی نمی‌توانید بشکنید؛ فقط با نزدیک‌تر کردن سرور.

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

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

رفت‌وبرگشت‌ها را کم کنید (نه فقط فاصله را)

هر اتصال تازه HTTPS پیش از فرستادن اولین بایت، چند رفت‌وبرگشت خرج می‌کند. دست‌دادن TCP یکی است و دست‌دادن TLS 1.3 یکی دیگر، و TLS 1.2 به‌جای یکی، دو تا می‌خواهد. روی کاربری با RTT صد میلی‌ثانیه یعنی حدود ۲۰۰ میلی‌ثانیه با TLS 1.3 و حدود ۳۰۰ میلی‌ثانیه با TLS 1.2، پیش از آنکه سرور اصلاً شروع به پاسخ کند (Core Web Vitals). راه نجات این است که همان اتصال را دوباره استفاده کنید به‌جای باز و بسته کردنش برای هر درخواست. این همان keep-alive است (Imperva).

دو جا باید keep-alive روشن باشد. اول بین کاربر و nginx:

server {
keepalive_timeout 65;
ssl_protocols TLSv1.2 TLSv1.3;
}

روشن بودن TLS 1.3 یک رفت‌وبرگشت کامل را از هر اتصال تازه حذف می‌کند. بررسی‌اش ساده است:

curl -sI --tlsv1.3 https://example.com -o /dev/null -w "%{http_version} %{ssl_verify_result}\n"

یک قدم جلوتر هم وجود دارد. در HTTP/3 که روی QUIC کار می‌کند، دست‌دادن انتقال و دست‌دادن رمزنگاری در هم ادغام می‌شوند و همان کار با یک رفت‌وبرگشت انجام می‌شود. اگر nginx شما نسخه‌ای است که HTTP/3 دارد، برای کاربر دور همین یک قدم به‌اندازه‌ی کل زحمت keep-alive اثر می‌گذارد.

نکته‌ای که اغلب فراموش می‌شود: بین nginx و بک‌اند خودتان هم اتصال باید بازاستفاده شود، وگرنه هر درخواست یک TCP تازه به اپلیکیشن می‌زند:

upstream app {
server 127.0.0.1:3000;
keepalive 32;
}
server {
location / {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}

آن دو خط آخر حیاتی‌اند. بدون proxy_http_version 1.1 و خالی کردن هدر Connection، nginx با هر درخواست اتصال بالادست را می‌بندد و بلوک keepalive عملاً بی‌اثر می‌شود. این خطایی است که در خیلی از کانفیگ‌های کپی‌شده هست.

کش و CDN برای فایل‌های ثابت

عکس، CSS، JS و فونت شما با هر بازدید تغییر نمی‌کنند. اگر اینها را هر بار از سرور اصلی بگیرید، هم سرور را درگیر می‌کنید و هم کاربر باید کل فاصله را طی کند. دو کار جدا لازم است.

اول، به مرورگر بگویید نگه‌شان دارد:

location ~* \.(css|js|woff2|png|jpg|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}

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

چه چیزی دست شما نیست

یک بخش از پینگ کاملاً بیرون از کنترل شماست: مسیری که اپراتور کاربر برای رسیدن به سرور انتخاب می‌کند. گاهی ترافیک داخل ایران از مسیری دورتر رد می‌شود، یا اپراتور کاربر پیرینگ بدی دارد. در mtr این را می‌بینید: پرش تأخیر روی هاپی که نه مال شبکه شماست نه دیتاسنتر.

اینجا کِی دست بکشید؟ اگر کف فیزیکی مسیر را حساب کردید، لوکیشن را نزدیک کردید، keep-alive و کش را بستید، و curl هنوز نشان می‌دهد که تأخیر در بخش شبکهٔ خارج از دیتاسنتر شماست، دیگر کاری از دست شما برنمی‌آید. آن ازدحام یا مسیریابی وظیفه اپراتور است. ادامه دادنِ تیونینگ از این نقطه فقط وقت تلف‌کردن است. بهترین اهرمی که باقی می‌ماند باز هم انتخاب لوکیشنی است که مسیر کوتاه‌تر و پایدارتری به کاربرانتان دارد.

جدول تصمیم: کدام عدد، کدام ابزار، کدام راه‌حل

نشانهبا چه چیزی می‌سنجیدراه‌حلی که جواب می‌دهد
پینگ پایه بالا برای همه کاربران یک منطقهping avg و کف فیزیکی فاصلهلوکیشن نزدیک‌تر به کاربر
پینگ خوب ولی صفحه دیر می‌آیدttfb منهای tls در curlبهینه‌سازی کوئری و کد، نه شبکه
اولین بازدید کند، بازدیدهای بعدی سریعمقایسه اتصال تازه و اتصال دومkeep-alive و TLS 1.3
فایل‌های ثابت کند بارگذاری می‌شوندزمان دانلود asset در DevToolsکش مرورگر و CDN
نوسان زیاد، قطع‌ووصلmtr Loss% و mdevمعمولاً مسیر اپراتور؛ خارج از کنترل شما

کدام لوکیشن و پلن را بردارید

قاعده ساده است: لوکیشن را جای کاربرانتان بگذارید، نه جای خودتان. اگر اکثریت کاربرانتان داخل ایران‌اند و curl ثابت کرده گلوگاه شبکه است، سرور مجازی ایران (تهران) یا شیراز کوتاه‌ترین مسیر را می‌دهد. اگر مخاطبتان اروپایی است، لوکیشن انگلستان، هلند یا سوئد را انتخاب کنید. و برای فایل‌های ثابت، بدون توجه به لوکیشن سرور اصلی، CDN آبریشم بار را از دوش سرور برمی‌دارد و asset را نزدیک کاربر نگه می‌دارد. اول با curl بسنجید، بعد لوکیشن را عوض کنید؛ نه برعکس.

منابع

  1. Understanding Network Latency: A Guide for Beginners (Globalping) (unknown)
  2. Calculating Optical Fiber Latency (M2 Optics) (unknown)
  3. Measure HTTP Connection times (TTFB) with curl (makandra) (unknown)
  4. What is HTTP Keep-Alive (Imperva) (unknown)
  5. Optimize the Connection Duration (TCP + TLS) sub-part of TTFB (unknown)

پرسش‌های پرتکرار

چرا پینگ سرورم پایین است ولی سایت کند است؟

چون پینگ فقط تأخیر شبکه را می‌سنجد، نه زمان پردازش برنامه. با دستور curl و تفریق ttfb از tls می‌توانید زمان واقعی پردازش سرور را جدا کنید. اگر آن عدد بزرگ بود، مشکل در کد و دیتابیس است و تغییر لوکیشن هیچ کمکی نمی‌کند.

کف فیزیکی پینگ چقدر است و آیا می‌شود از آن پایین‌تر رفت؟

نور در فیبر حدود ۲۰۰٬۰۰۰ کیلومتر بر ثانیه است، یعنی تقریباً ۱ میلی‌ثانیه رفت‌وبرگشت به ازای هر ۱۰۰ کیلومتر. از این کف نمی‌توان پایین‌تر رفت؛ تنها راه کم‌کردنش نزدیک‌کردن سرور به کاربر است.

keep-alive واقعاً چقدر فرق ایجاد می‌کند؟

هر اتصال تازه HTTPS یک تا دو رفت‌وبرگشت خرج دست‌دادن TCP و TLS می‌کند. روی کاربری با RTT صد میلی‌ثانیه این یعنی ۱۰۰ تا ۲۰۰ میلی‌ثانیه اضافه در هر اتصال جدید. keep-alive و TLS 1.3 این هزینه را برای درخواست‌های بعدی تقریباً صفر می‌کنند.

آیا CDN پینگ سرور من را کم می‌کند؟

فقط برای فایل‌های ثابت مثل عکس، CSS و JS. CDN نسخه کش‌شده را نزدیک کاربر نگه می‌دارد، اما پاسخ‌های داینامیک همچنان از سرور اصلی می‌آیند و تأخیرشان تغییر نمی‌کند. CDN مکمل لوکیشن درست است، نه جایگزین آن.

کی باید از تلاش برای کم‌کردن پینگ دست بکشم؟

وقتی لوکیشن را نزدیک کردید، keep-alive و کش را بستید، و mtr نشان می‌دهد تأخیر روی مسیر اپراتور و خارج از دیتاسنتر شماست. آن بخش وظیفه اپراتور کاربر است و ادامه تیونینگ از این نقطه فایده‌ای ندارد.

سفارش سرور مجازی بازگشت به وبلاگ →