ASP.NET Hosting dan penskalakan Inti SignalR

Oleh Andrew 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 Lengket

SignalR mengharuskan semua permintaan HTTP untuk koneksi tertentu ditangani oleh proses server yang sama. Ketika SignalR berjalan di farm server (beberapa server), "sesi lengket" harus digunakan. "Sesi lekat" juga disebut afinitas sesi oleh beberapa penyeimbang beban. Azure App Service menggunakan Perutean Permintaan Aplikasi (ARR) untuk merutekan permintaan. Mengaktifkan pengaturan "Afinitas ARR" di Azure App Service Anda akan mengaktifkan "sesi lekat". Satu-satunya keadaan di mana sesi lengket tidak diperlukan adalah:

  1. Saat menghosting di satu server, dalam satu proses.
  2. Saat menggunakan Layanan Azure SignalR .
  3. Ketika semua klien dikonfigurasi untuk hanya menggunakan WebSocket, danpengaturan SkipNegotiation diaktifkan dalam konfigurasi klien.

Dalam semua keadaan lain (termasuk ketika backplane Redis digunakan), lingkungan server harus dikonfigurasi untuk sesi lengket.

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 Layanan AzureSignalR, lihat Menghosting dan menyebarkan aplikasi sisi Blazor 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 beberapa 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 SignalR penggunaan sumber daya tidak menyebabkan kesalahan dalam aplikasi, peluasan skala untuk membatasi jumlah koneksi yang harus ditangani SignalR server.

Peluasan 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.

Scaling SignalR without a backplane

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

Layanan Azure SignalR

Azure SignalR Service berfungsi sebagai proksi untuk lalu lintas real-time dan berfungsi ganda sebagai backplane saat aplikasi diskalakan di beberapa server. Setiap kali klien memulai koneksi ke server, klien dialihkan untuk terhubung ke layanan. Proses ini diilustrasikan oleh diagram berikut:

Establishing a connection to the 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:

Clients connected to the service, servers connected to the service

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

  • Sesi lengket, juga dikenal sebagai afinitas klien, tidak diperlukan, karena klien segera dialihkan 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 meluaskan skala ke beberapa server hanya untuk menangani koneksi itu sendiri.
  • Aplikasi SignalR tidak akan menggunakan lebih banyak sumber daya koneksi secara signifikan daripada aplikasi web tanpa SignalR.

Untuk alasan ini, kami merekomendasikan Layanan Azure SignalR untuk semua aplikasi ASP.NET Core yang SignalR dihosting di Azure, termasuk App Service, VM, dan kontainer.

Untuk informasi selengkapnya, lihat dokumentasi Azure SignalR Service.

Backplane Redis

Redis adalah penyimpanan kunci-nilai dalam memori yang mendukung sistem olahpesan dengan model terbitkan/berlangganan. Backplane SignalR Redis menggunakan fitur pub/sub untuk meneruskan pesan ke server lain. Ketika klien membuat koneksi, informasi koneksi diteruskan ke backplane. Ketika server ingin mengirim pesan ke semua klien, server akan dikirim 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:

Redis backplane, message sent from one server to all clients

Backplane Redis adalah pendekatan peluasan skala yang direkomendasikan untuk aplikasi yang dihosting di infrastruktur Anda sendiri. Jika ada latensi koneksi yang signifikan 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.

Keuntungan Azure SignalR Service yang dicatat sebelumnya adalah kerugian untuk backplane Redis:

  • Sesi 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 meskipun beberapa pesan sedang dikirim.
  • Aplikasi SignalR menggunakan sumber daya koneksi yang jauh lebih banyak daripada aplikasi web tanpa SignalR.

Batasan IIS pada OS klien Windows

Windows 10 dan Windows 8.x adalah sistem operasi klien. IIS pada sistem operasi klien memiliki batas 10 koneksi bersamaan. SignalRKoneksinya adalah:

  • Sementara dan sering dibuat ulang.
  • Tidak segera dibuang ketika tidak lagi digunakan.

Kondisi sebelumnya membuatnya cenderung mencapai batas 10 koneksi pada OS klien. Saat OS klien digunakan untuk pengembangan, kami sarankan:

  • Hindari IIS.
  • Gunakan Kestrel atau IIS Express sebagai target penyebaran.

Linux dengan Nginx

Berikut ini 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 backend digunakan, sesi lengket harus ditambahkan untuk mencegah SignalR koneksi beralih server saat menyambungkan. Ada beberapa cara untuk menambahkan sesi lengket di Nginx. Dua pendekatan ditunjukkan di bawah ini tergantung pada apa yang telah Anda sediakan.

Berikut ini ditambahkan selain konfigurasi sebelumnya. Dalam contoh berikut, 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 permintaan ke dan menyematkan permintaan pengguna ke 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;
  }
}

Terakhir, ubah proxy_pass http://localhost:5000 di bagian menjadi serverproxy_pass http://backend.

Untuk informasi selengkapnya tentang WebSocket melalui Nginx, lihat NGINX sebagai Proksi WebSocket.

Untuk informasi selengkapnya tentang penyeimbangan beban dan sesi lengket, lihat penyeimbangan beban NGINX.

Untuk informasi selengkapnya tentang ASP.NET Core dengan Nginx lihat artikel berikut ini:

Penyedia backplane pihak SignalR ketiga

Langkah berikutnya

Untuk informasi selengkapnya, lihat sumber daya berikut: