عنوان:

‫چالش‌های متداول توسعه‌دهندگان ASP.NET Core هنگام استفاده از Nginx - قسمت ششم - مباحث پیشرفته و بهینه‌سازی عملکرد


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۱۲ ۰۸:۱۰
آدرس: www.dntips.ir
تا اینجا شما با موفقیت یک برنامه ASP.NET Core را بر روی یک زیرساخت استاندارد، امن و پایدار در لینوکس مستقر کرده‌اید. برنامه شما کار می‌کند، امن است و به راحتی مدیریت می‌شود. اما همیشه جا برای بهتر شدن وجود دارد. در این قسمت پایانی، از وضعیت "کار می‌کند" فراتر رفته و به وضعیت "عالی کار می‌کند" می‌رسیم. ما یاد می‌گیریم چگونه قابلیت‌های مدرن مانند ارتباطات دوطرفه (Real-time) را فعال کنیم، سرعت بارگذاری سایت را به شکل چشمگیری افزایش دهیم و از سرور خود در برابر استفاده‌های مخرب محافظت کنیم.

بخش ۱: فعال‌سازی WebSockets برای SignalR
بسیاری از برنامه‌های مدرن به قابلیت‌های Real-time مانند چت، اعلان‌های زنده یا داشبوردهای پویا نیاز دارند. فریم‌ورک SignalR در ASP.NET Core این کار را با استفاده از تکنولوژی WebSockets انجام می‌دهد.
  • مشکل: برنامه SignalR من که در ویندوز کار می‌کرد، پس از انتشار روی Nginx از کار افتاده است.
  • علت: ارتباط WebSocket با یک درخواست عادی HTTP شروع می‌شود که سپس درخواست "ارتقا" (Upgrade) به یک کانکشن دائمی و دوطرفه را می‌دهد. یک پراکسی ساده این درخواست ارتقا را متوجه نشده و آن را رد می‌کند.
  • راه‌حل: باید به Nginx بگوییم که درخواست‌های Upgrade را درک کرده و آن‌ها را به Kestrel منتقل کند. این کار با دو هدر انجام می‌شود. خوشبختانه این هدرها در "قالب طلایی" ما از فصل ۳ وجود داشتند، اما اکنون دلیل وجودشان را درک می‌کنیم:
به بلاک location در کانفیگ Nginx خود دقت کنید:
location / {
    proxy_pass         http://localhost:5000;
    proxy_set_header   Host $host;
    
    # --- این دو خط برای WebSocket حیاتی هستند ---
    # به Kestrel می‌گوید که کلاینت درخواست ارتقای پروتکل را دارد
    proxy_set_header   Upgrade $http_upgrade;
    # نوع کانکشن را روی "upgrade" تنظیم می‌کند تا ارتباط باز بماند
    proxy_set_header   Connection "upgrade";
    
    # ... سایر هدرها
}
با این تنظیمات، Nginx به یک کانال شفاف برای ارتباطات WebSocket تبدیل شده و SignalR به درستی کار خواهد کرد.

بخش ۲: تکنیک‌های بهینه‌سازی عملکرد
تکنیک ۱: فشرده‌سازی پاسخ‌ها با Gzip
  • چرا؟ این تکنیک حجم فایل‌های متنی (HTML, CSS, JS, JSON) را قبل از ارسال به کاربر تا ۷۰-۸۰٪ کاهش می‌دهد. نتیجه آن بارگذاری سریع‌تر صفحات و صرفه‌جویی در مصرف پهنای باند است. بهتر است این کار توسط Nginx انجام شود که برای این منظور بهینه شده است.
  • چگونه؟ این تنظیمات معمولاً به صورت سراسری در فایل /etc/nginx/nginx.conf و داخل بلاک http قرار می‌گیرند.
http {
    # ... سایر تنظیمات

    # فعال‌سازی Gzip
    gzip on;

    # به پراکسی‌ها می‌گوید که نسخه فشرده را کش کنند
    gzip_vary on;

    # برای تمام درخواست‌هایی که از طریق پراکسی می‌آیند اعمال شود
    gzip_proxied any;

    # سطح فشرده‌سازی (بین ۱ تا ۹، ۶ یک انتخاب معقول است)
    gzip_comp_level 6;

    # نوع فایل‌هایی که باید فشرده شوند
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}
  • پس از افزودن این کد و ری‌استارت کردن Nginx، می‌توانید با ابزارهای توسعه‌دهنده مرورگر (Developer Tools) در تب Network ببینید که حجم فایل‌ها به شدت کاهش یافته است.

تکنیک ۲: استفاده از کش مرورگر (Browser Caching)
  • چرا؟ شما می‌توانید به مرورگر کاربر دستور دهید که فایل‌های استاتیک (که به ندرت تغییر می‌کنند) را برای مدتی در حافظه خود نگه دارد. در بازدیدهای بعدی، این فایل‌ها به جای دانلود مجدد از سرور، مستقیماً از کش کاربر بارگذاری می‌شوند که سرعت را فوق‌العاده افزایش می‌دهد.
  • چگونه؟ بلاک location مربوط به فایل‌های استاتیک که در فصل ۳ ساختیم را به شکل زیر تکمیل می‌کنیم:
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ {
    root /var/www/mywebapp/wwwroot;

    # به مرورگر می‌گوید این فایل را برای ۷ روز کش کند
    expires 7d;

    # به کش‌های عمومی (مانند CDN) نیز اجازه کش کردن می‌دهد
    add_header Cache-Control "public";
}

بخش ۳: امنیت و پایداری پیشرفته
تکنیک ۱: محدود کردن نرخ درخواست (Rate Limiting)
  • چرا؟ برای محافظت از سرور در برابر حملات ساده Denial-of-Service (DoS) یا ربات‌هایی که با ارسال درخواست‌های مکرر، منابع سرور را مصرف می‌کنند.
  • چگونه؟ این کار در دو مرحله انجام می‌شود:
  • تعریف محدوده در nginx.conf: در بلاک http یک محدوده تعریف می‌کنیم.
http {
    # ...
    # یک محدوده حافظه ۱۰ مگابایتی تعریف می‌کند که به هر IP اجازه ۱۰ درخواست در ثانیه را می‌دهد
    limit_req_zone $binary_remote_addr zone=global_limit:10m rate=10r/s;
}
  • اعمال محدوده در کانفیگ سایت: در بلاک location سایت خود، این محدوده را اعمال می‌کنیم.
location / {
    # اعمال محدوده تعریف شده
    limit_req zone=global_limit burst=20;

    # ... تنظیمات پراکسی
}
  • در این مثال، هر IP می‌تواند تا ۱۰ درخواست در ثانیه ارسال کند. پارامتر burst=20 اجازه می‌دهد تا ۲۰ درخواست به صورت آنی و پشت سر هم ارسال شوند تا کاربران عادی دچار مشکل نشوند. درخواست‌های بیشتر با خطای 503 Service Unavailable پاسخ داده می‌شوند.

تکنیک ۲: استفاده از سوکت‌های یونیکس (Unix Sockets)
  • چرا؟ به جای استفاده از پورت TCP (مانند localhost:5000) برای ارتباط بین Nginx و Kestrel، می‌توان از سوکت‌های یونیکس استفاده کرد. این کار کمی عملکرد را بهبود می‌بخشد (چون از پشته شبکه TCP/IP عبور نمی‌کند) و مشکل تداخل پورت‌ها در سرور را از بین می‌برد.
  • چگونه؟ این تغییر نیازمند ویرایش در دو نقطه است:
  • تغییر در برنامه ASP.NET Core (Program.cs):
builder.WebHost.ConfigureKestrel(options =>
{
    // این خط را کامنت یا حذف کنید
    // options.Listen(IPAddress.Loopback, 5000); 

    // و این خط را اضافه کنید
    options.ListenUnixSocket("/var/run/kestrel-mywebapp.sock");
});
  • تغییر در کانفیگ Nginx:
location / {
    # این خط را تغییر دهید
    # proxy_pass http://localhost:5000;

    # به این خط
    proxy_pass http://unix:/var/run/kestrel-mywebapp.sock;

    # ...
}
  • نکته مهم: کاربر Nginx (www-data) باید دسترسی خواندن و نوشتن به این فایل سوکت داشته باشد. این موضوع می‌تواند نیازمند تنظیمات دسترسی بیشتری باشد و به همین دلیل یک تکنیک پیشرفته محسوب می‌شود.

جمع‌بندی نهایی دوره
در طول این دوره، ما یک سفر کامل را از یک برنامه ساده ASP.NET Core که با dotnet run اجرا می‌شد، تا یک زیرساخت تولید حرفه‌ای، امن و با عملکرد بالا طی کردیم.
شما یاد گرفتید که چگونه:
  • برنامه خود را با systemd به یک سرویس پایدار تبدیل کنید.
  • Nginx را به عنوان یک Reverse Proxy هوشمند، امن و بهینه پیکربندی کنید.
  • با Let's Encrypt سایت خود را به صورت رایگان و خودکار با HTTPS امن سازید.
  • با استفاده از لاگ‌های Nginx و Journald به صورت سیستماتیک مشکلات را عیب‌یابی کنید.
  • با تکنیک‌های پیشرفته مانند فشرده‌سازی، کشینگ و Rate Limiting، عملکرد و پایداری برنامه خود را به حداکثر برسانید.

شما اکنون دانش و مهارت لازم برای استقرار و مدیریت هر نوع برنامه ASP.NET Core در یک محیط واقعی لینوکس را با اطمینان کامل در اختیار دارید. موفق باشید!