ASP.NET Hosting dan penskalakan Inti SignalR

Oleh Ashley Stanton-Nurse, Brady Gaster, dan Tom Dykstra

Artikel ini menjelaskan pertimbangan hosting dan penskalaan untuk aplikasi lalu lintas tinggi yang menggunakan ASP.NET Core SignalR.

Sesi tetap

SignalR memerlukan proses server yang sama menangani semua permintaan HTTP untuk koneksi tertentu. Ketika SignalR berjalan pada server farm (beberapa server), "sticky session" harus digunakan. "Sesi lekat" juga disebut afinitas sesi. Azure App Service menggunakan Microsoft Application Request Routing (ARR) untuk merutekan permintaan. Mengaktifkan pengaturan "Afinitas sesi" (Afinitas ARR) di aplikasi App Service Anda akan mengaktifkan sesi tetap.

Ada tiga skenario di mana sesi tetap tidak diperlukan untuk sebuah aplikasi:

  • Hosting di satu server dalam satu proses
  • Menggunakan layanan Azure SignalR (sesi lekat diaktifkan untuk layanan, bukan aplikasi)
  • Semua klien dikonfigurasi untuk menggunakan WebSockets saja dan konfigurasi klien memungkinkan SkipNegotiation

Dalam semua skenario lainnya (termasuk saat backplane Redis digunakan), lingkungan server harus dikonfigurasi agar menggunakan sticky session.

Untuk panduan tentang mengonfigurasi Azure App Service untuk SignalR, lihat Menerbitkan aplikasi ASP.NET Core SignalR ke Azure App Service. Untuk panduan tentang mengonfigurasi sesi lekat untuk Blazor aplikasi yang menggunakan SignalR Azure, lihat Blazor sisi server ASP.NET Core.

Sumber daya koneksi TCP

Jumlah koneksi TCP bersamaan yang dapat didukung server web terbatas. Klien HTTP standar menggunakan koneksi ephemeral . Koneksi ini dapat ditutup ketika klien diam dan dibuka kembali nanti. Di sisi lain, SignalR koneksi persisten. SignalR koneksi tetap terbuka bahkan ketika klien menganggur. Dalam aplikasi lalu lintas tinggi yang melayani banyak klien, koneksi persisten ini dapat menyebabkan server mencapai jumlah koneksi maksimum mereka.

Koneksi persisten juga menggunakan memori tambahan, untuk melacak setiap koneksi.

Penggunaan sumber daya terkait koneksi yang berat dengan SignalR dapat memengaruhi aplikasi web lain yang dihosting di server yang sama. Saat SignalR membuka dan menahan koneksi TCP terakhir yang tersedia, aplikasi web lain di server yang sama juga tidak memiliki koneksi lagi yang tersedia untuk mereka.

Jika server kehabisan koneksi, Anda akan melihat kesalahan soket acak dan kesalahan pengaturan ulang koneksi. Contohnya:

An attempt was made to access a socket in a way forbidden by its access permissions...

Agar penggunaan sumber daya tidak SignalR menyebabkan kesalahan di aplikasi web lain, jalankan SignalR di server yang berbeda dari aplikasi web Anda yang lain.

Untuk menjaga penggunaan sumber daya SignalR tidak menyebabkan kesalahan dalam aplikasi SignalR, lakukan peluasan skala untuk membatasi jumlah koneksi yang harus ditangani server.

Perluasan skala

Aplikasi yang menggunakan SignalR perlu melacak semua koneksinya, yang menciptakan masalah untuk farm server. Tambahkan server, dan mendapatkan koneksi baru yang tidak diketahui server lain. Misalnya, SignalR pada setiap server dalam diagram berikut tidak menyadari koneksi di server lain. Ketika SignalR di salah satu server ingin mengirim pesan ke semua klien, pesan hanya masuk ke klien yang terhubung ke server tersebut.

Ilustrasi yang menggambarkan penskalaan SignalR tanpa backplane.

Opsi untuk memecahkan masalah ini adalah azure SignalR Service dan Redis backplane.

Layanan Azure SignalR

Azure SignalR Service berfungsi sebagai proksi bagi lalu lintas real-time dan berfungsi ganda sebagai backplane saat aplikasi diskalakan ke beberapa server. Setiap kali klien memulai koneksi ke server, klien dialihkan untuk terhubung ke layanan. Diagram berikut mengilustrasikan proses ini:

Illustration yang menggambarkan pembuatan koneksi ke Azure SignalR Service.

Hasilnya adalah bahwa layanan mengelola semua koneksi klien, sementara setiap server hanya membutuhkan jumlah koneksi konstan kecil ke layanan, seperti yang ditunjukkan dalam diagram berikut:

Ilustrasi yang menggambarkan klien dan server yang tersambung ke layanan.

Pendekatan untuk peluasan skala ini memiliki beberapa keuntungan daripada alternatif backplane Redis:

  • Sesi lekat, juga dikenal sebagai afinitas client, tidak diperlukan karena klien segera diarahkan ke Layanan Azure SignalR saat terhubung.
  • Aplikasi SignalR dapat menskalakan berdasarkan jumlah pesan yang dikirim, sementara Azure SignalR Service menskalakan untuk menangani sejumlah koneksi. Misalnya, mungkin ada ribuan klien, tetapi jika hanya beberapa pesan per detik yang dikirim, SignalR aplikasi tidak perlu menskalakan ke beberapa server hanya untuk menangani koneksi itu sendiri.
  • Aplikasi SignalR tidak menggunakan lebih banyak sumber daya koneksi daripada aplikasi web tanpa SignalR.

Untuk alasan ini, rekomendasinya adalah menggunakan Layanan Azure SignalR untuk semua aplikasi ASP.NET Core SignalR yang dihosting di Azure, termasuk App Service, komputer virtual, dan kontainer.

Untuk informasi selengkapnya, lihat dokumentasi Azure SignalR Service.

Redis Backplane

Redis adalah penyimpanan kunci-nilai dalam memori yang mendukung sistem olahpesan dengan model terbitkan/berlangganan. SignalR Backplane Redis menggunakan fitur publikasi/langganan untuk meneruskan pesan ke server lain. Ketika klien membuat koneksi, informasi koneksi diteruskan ke backplane. Ketika server ingin mengirim pesan ke semua klien, server mengirimkannya ke backplane. Backplane mengetahui semua klien yang terhubung dan server mana yang mereka gunakan. Ini mengirim pesan ke semua klien melalui server masing-masing. Proses ini diilustrasikan dalam diagram berikut:

Ilustrasi yang menggambarkan backplane Redis dengan pesan yang dikirim dari satu server ke semua klien.

Backplane Redis adalah pendekatan peluasan skala yang direkomendasikan untuk aplikasi yang dihosting di infrastruktur Anda sendiri. Jika latensi koneksi yang signifikan ada antara pusat data Anda dan pusat data Azure, Azure SignalR Service mungkin bukan opsi praktis untuk aplikasi lokal dengan latensi rendah atau persyaratan throughput tinggi.

Kelebihan Azure SignalR Service yang dijelaskan sebelumnya merupakan kekurangan bagi backplane Redis:

  • Sesi yang lengket, juga dikenal sebagai afinitas klien, diperlukan, kecuali ketika kedua hal berikut ini benar:
    • Semua klien dikonfigurasi untuk hanya menggunakan WebSocket.
    • Pengaturan SkipNegotiation diaktifkan dalam konfigurasi klien. Setelah koneksi dimulai di server, koneksi harus tetap berada di server tersebut.
  • Aplikasi SignalR harus meluaskan skala berdasarkan jumlah klien, bahkan saat mengirim beberapa pesan.
  • Aplikasi SignalR menggunakan lebih banyak sumber daya koneksi daripada aplikasi web tanpa SignalR.

Batasan IIS pada sistem operasi klien Windows

Windows 10 dan Windows 8.x adalah sistem operasi klien. Layanan Informasi Internet (IIS) pada sistem operasi klien memiliki batas 10 koneksi bersamaan. Koneksi SignalR memiliki karakteristik berikut:

  • Mereka bersifat sementara dan sering dibentuk kembali.
  • Tidak segera dibuang ketika tidak lagi digunakan.

Karakteristik ini membuatnya cenderung mencapai batas 10 koneksi pada sistem operasi klien. Saat Anda menggunakan sistem operasi klien untuk pengembangan, pertimbangkan rekomendasi berikut:

  • Hindari IIS
  • Menggunakan Kestrel atau IIS Express sebagai target penyebaran

Linux dengan Nginx

Kode berikut berisi pengaturan minimum yang diperlukan untuk mengaktifkan WebSocket, ServerSentEvents, dan LongPolling untuk SignalR:

http {
  map $http_connection $connection_upgrade {
    "~*Upgrade" $http_connection;
    default keep-alive;
  }

  server {
    listen 80;
    server_name example.com *.example.com;

    # Configure the SignalR Endpoint
    location /hubroute {
      # App server url
      proxy_pass http://localhost:5000;

      # Configuration for WebSockets
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_cache off;
      # WebSockets were implemented after http/1.0
      proxy_http_version 1.1;

      # Configuration for ServerSentEvents
      proxy_buffering off;

      # Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds
      proxy_read_timeout 100s;

      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }
  }
}

Ketika beberapa server back-end digunakan, sesi tetap harus ditambahkan untuk mencegah koneksi SignalR berpindah server saat terhubung. Ada beberapa cara untuk menambahkan sticky session di Nginx. Contoh berikut menunjukkan dua pendekatan berdasarkan apa yang telah Anda sediakan.

Kode berikut melengkapi konfigurasi contoh sebelumnya. Dalam cuplikan, backend adalah nama grup server.

  • Dengan Nginx Open Source, gunakan ip_hash untuk merutekan koneksi ke server berdasarkan alamat IP klien:

    http {
       upstream backend {
         # App server 1
         server localhost:5000;
         # App server 2
         server localhost:5002;
    
         ip_hash;
       }
    }
    
  • Dengan Nginx Plus, gunakan sticky untuk menambahkan cookie ke permintaan dan mengarahkan permintaan pengguna ke satu server:

    http {
       upstream backend {
         # App server 1
         server localhost:5000;
         # App server 2
         server localhost:5002;
    
         sticky cookie srv_id expires=max domain=.example.com path=/ httponly;
       }
    }
    
  • Untuk kedua konfigurasi, ubah proxy_pass http://localhost:5000 di bagian server menjadi proxy_pass http://backend.

Anda dapat menemukan informasi selengkapnya di Host ASP.NET Core di Linux dengan Nginx.

Penyedia backplane lainnya SignalR

Penyedia non-Microsoft berikut juga menawarkan backplane SignalR: